001    package data.stdforms;
002    
003    import sale.*;
004    import data.*;
005    import data.filters.AbstractStockFilter;
006    import data.filters.CatalogFilter;
007    import data.stdforms.twotableformsheet.*;
008    import data.swing.*;
009    import users.UserManager;
010    import users.swing.UserTableModel;
011    import util.swing.*;
012    
013    import java.util.*;
014    
015    import javax.swing.*;
016    import javax.swing.table.TableModel;
017    
018    /**
019     * A FormSheet that will display the contents of two data containers, a source and a destination, and will
020     * allow the user to move items between the two.
021     *
022     * <p>Source and destination are displayed in a tabular form. The data containers that are supported as source
023     * or destination are: {@link Catalog}, {@link Stock}, {@link DataBasket}. There will be two buttons that
024     * allow to move items from the source into the destination table and vice-versa. If at least one of source
025     * and destination is a {@link CountingStock} there will also be an input line where the user can specify how
026     * many items are to be moved. The actual moving will be implemented as sub-process of the process that
027     * displays the FormSheet. The concrete sub-process implementations are provided by {@link MoveStrategy}
028     * strategy objects.</p>
029     *
030     * <p>A quite comprehensive set of <code>create()</code> functions is provided to allow to easily create
031     * TwoTableFormSheets by simply supplying some parameters.</p>
032     *
033     * @author Steffen Zschaler
034     * @version 2.0 20/08/1999
035     * @since v2.0
036     */
037    public class TwoTableFormSheet extends FormSheet {
038    
039        /**
040             * ID for serialization.
041             */
042            private static final long serialVersionUID = 1073218641254871804L;
043    
044            /**
045         * The DataBasket used.
046         */
047        private DataBasket m_db;
048    
049        /**
050         * The source for the left table.
051         */
052        private Object m_leftSource;
053    
054        /**
055         * The source for the right table.
056         */
057        private Object m_rightSource;
058    
059        /**
060         * The left table
061         */
062        private JTable m_leftTable;
063    
064        /**
065         * The left table
066         */
067        private JTable m_rightTable;
068    
069        /**
070         * The strategy used when moving items between source and destination.
071         *
072         * @serial
073         */
074        private MoveStrategy m_ms;
075    
076        /**
077         * The gate at which the FormSheet is displayed.
078         *
079         * @serial
080         */
081        private UIGate m_uigGate;
082    
083        /**
084         * The {@link TableModel} of the left table displayed.
085         */
086        private transient util.swing.AbstractTableModel m_atmLeftModel;
087    
088        /**
089         * The {@link TableModel} of the right table displayed.
090         */
091        private transient util.swing.AbstractTableModel m_atmRightModel;
092    
093        /**
094         * Reference to the currently selected index.
095         *
096         * @serial
097         */
098        private final int[] m_anLeftSelection = new int[] {
099                 -1};
100    
101        /**
102         * Reference to the currently selected index.
103         *
104         * @serial
105         */
106        private final int[] m_anRightSelection = new int[] {
107                 -1};
108    
109        /**
110         * Create a new TwoTableFormSheet. Instead of calling this constructor directly, use one of the many
111         * <code>create()</code> functions provided.
112         *
113         * @param sCaption the caption of the FormSheet.
114         * @param fscc the content creator to be used.
115         * @param uigGate the gate at which to display the FormSheet.
116         * @param ms the strategy to be used when moving items between source and destination.
117         */
118        protected TwoTableFormSheet(String sCaption, FormSheetContentCreator fscc, UIGate uigGate,
119                MoveStrategy ms) {
120            super(sCaption, (JComponent)null, true);
121    
122            m_ms = ms;
123            setGate(uigGate);
124    
125            addContentCreator(fscc);
126        }
127    
128        /**
129         * Get the record currently selected in the left table.
130         *
131         * <p>The actual class of the record depends on the concrete type of TableModel used. See the TableModel's
132         * <code>getRecord()</code> method for details.</p>
133         */
134        public Object getLeftSelectedRecord() {
135            return m_atmLeftModel.getRecord(m_anLeftSelection[0]);
136        }
137    
138        /**
139         * Get the record currently selected in the right table.
140         *
141         * <p>The actual class of the record depends on the concrete type of TableModel used. See the TableModel's
142         * <code>getRecord()</code> method for details.</p>
143         */
144        public Object getRightSelectedRecord() {
145            return m_atmRightModel.getRecord(m_anRightSelection[0]);
146        }
147    
148        /**
149         * Get the currently attached DataBasket.
150         *
151         * @override Never
152         */
153        public DataBasket getDataBasket() {
154            return m_db;
155        }
156    
157        /**
158         * Get the source of the left table.
159         *
160         * @override Never
161         */
162        public Object getLeftTableSource() {
163            return m_leftSource;
164        }
165    
166        /**
167         * Get the source of the right table.
168         *
169         * @override Never
170         */
171        public Object getRightTableSource() {
172            return m_rightSource;
173        }
174        
175        /**
176         * Set the source of the left table.
177         * New source is a {@link data.Catalog}
178         *
179         * @param m_catalogSource the new datasource as Catalog
180         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
181         * 
182         * @override Never
183         */
184        public void setLeftTable(   Catalog m_catalogSource,
185                                                            TableEntryDescriptor ted) {
186            JAbstractTable jat_c = (JAbstractTable) getLeftTable();
187            AbstractTableModel atm = jat_c.getAbstractTableModel();
188            if(atm instanceof CatalogTableModel) {
189                    atm.setData(m_catalogSource);
190            }
191            else {
192                    jat_c.setModel(
193                                    new CatalogTableModel(  m_catalogSource,
194                                                                                            getDataBasket(),
195                                                                                            ((CatalogTableModel)atm).getComparator(),
196                                                                                            ted));
197            }
198        }
199        
200        /**
201         * Set the source of the left table.
202         * New source is a {@link data.CountingStock}
203         *
204         * @param m_csSource the new datasource as CoutingStock
205         * @param fShowZeros if true, lines informing about a zero amount of objects will be shown. Only necessary if prior TableModel is different from actual TableModel.
206         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
207         * 
208         * @override Never
209         */
210        public void setLeftTable(   CountingStock m_csSource,
211                                                                    boolean fShowZeros,
212                                                                    TableEntryDescriptor ted) 
213            {
214            JAbstractTable jat_c = (JAbstractTable) getLeftTable();
215            AbstractTableModel atm = jat_c.getAbstractTableModel();
216            if(atm instanceof CountingStockTableModel) {
217                    atm.setData(m_csSource);
218            }
219            else {
220                    jat_c.setModel(
221                                    new CountingStockTableModel(    m_csSource,
222                                                                                                            getDataBasket(),
223                                                                                                            ((CatalogTableModel) atm).getComparator(),
224                                                                                                            fShowZeros,
225                                                                                                            ted));
226            }
227        }
228        
229        /**
230         * Set the source of the left table.
231         * New source is a {@link data.StoringStock}
232         *
233         * @param m_stSource the new datasource as StoringStock
234         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
235         * 
236         * @override Never
237         */
238        public void setLeftTable(   StoringStock m_stSource,
239                                                            TableEntryDescriptor ted)
240            {
241            JAbstractTable jat_c = (JAbstractTable) getLeftTable();
242            AbstractTableModel atm = jat_c.getAbstractTableModel();
243            if(atm instanceof StoringStockTableModel) {
244                    atm.setData(m_stSource);        
245            }
246            else {
247                    jat_c.setModel(
248                                    new StoringStockTableModel(     m_stSource,
249                                                                                            getDataBasket(),
250                                                                                                    null,
251                                                                                                    ted));
252            }
253            
254        }
255        
256        /**
257         * Set the source of the left table.
258         * New source is a {@link users.UserManager}
259         *
260         * @param m_umManager the new datasource as UserManager
261         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
262         *
263         * @override Never
264         */
265        public void setLeftTable(   UserManager m_umManager,
266                                                            TableEntryDescriptor ted) {
267            JAbstractTable jat_c = (JAbstractTable) getLeftTable();
268            AbstractTableModel atm = jat_c.getAbstractTableModel();
269            if(atm instanceof UserTableModel) {
270                    atm.setData(m_umManager);       
271            }
272            else {
273                    jat_c.setModel(
274                                    new UserTableModel(     m_umManager,
275                                                                            null,
276                                                                                    ted));
277            }
278        }
279        
280        /**
281         * Set the source of the left table.
282         * New source is a {@link data.DataBasket}
283         * 
284         * @param m_dbSource the new datasource as Databasket
285         * @param dbc a condition specifying the DataBasketEntries to be part of the model. Only necessary if prior TableModel is different from actual TableModel.
286         * @param dbeg dbeg a strategy that will group individual DataBasketEntries together for display. If
287         * <code>null</code>, no grouping will occur. Only necessary if prior TableModel is different from actual TableModel. 
288         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
289         * 
290         * @override Never
291         */
292        public void setLeftTable(   DataBasket m_dbSource,
293                                                            DataBasketCondition dbc,
294                                                                    DataBasketEntryGrouper dbeg,
295                                                                    TableEntryDescriptor ted) {
296            JAbstractTable jat_c = (JAbstractTable) getLeftTable();
297            AbstractTableModel atm = jat_c.getAbstractTableModel();
298            if(atm instanceof DataBasketTableModel) {
299                    atm.setData(m_dbSource);        
300            }
301            else {
302                    jat_c.setModel(
303                                    new DataBasketTableModel(       m_dbSource,
304                                                                                            dbc,
305                                                                                                    dbeg,
306                                                                                                    null,
307                                                                                                    ted));
308            }
309        }
310        
311        /**
312         * Set the source of the right table.
313         * New source is a {@link data.Catalog}
314         *
315         * @param m_catalogSource the new datasource as Catalog
316         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
317         * 
318         * @override Never
319         */
320        public void setRightTable(  Catalog m_catalogSource,
321                                                            TableEntryDescriptor ted) {
322            JAbstractTable jat_c = (JAbstractTable) getRightTable();
323            AbstractTableModel atm = jat_c.getAbstractTableModel();
324            if(atm instanceof CatalogTableModel) {
325                    atm.setData(m_catalogSource);
326            }
327            else {
328                    jat_c.setModel(
329                                    new CatalogTableModel(  m_catalogSource,
330                                                                                            getDataBasket(),
331                                                                                            ((CatalogTableModel)atm).getComparator(),
332                                                                                            ted));
333            }
334        }
335        
336        /**
337         * Set the source of the right table.
338         * New source is a {@link data.CountingStock}
339         *
340         * @param m_csSource the new datasource as CoutingStock
341         * @param fShowZeros if true, lines informing about a zero amount of objects will be shown. Only necessary if prior TableModel is different from actual TableModel.
342         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
343         * 
344         * @override Never
345         */
346        public void setRightTable(  CountingStock m_csSource,
347                                                                    boolean fShowZeros,
348                                                                    TableEntryDescriptor ted) 
349            {
350            JAbstractTable jat_c = (JAbstractTable) getRightTable();
351            AbstractTableModel atm = jat_c.getAbstractTableModel();
352            if(atm instanceof CountingStockTableModel) {
353                    atm.setData(m_csSource);
354            }
355            else {
356                    jat_c.setModel(
357                                    new CountingStockTableModel(    m_csSource,
358                                                                                                            getDataBasket(),
359                                                                                                            ((CatalogTableModel) atm).getComparator(),
360                                                                                                            fShowZeros,
361                                                                                                            ted));
362            }
363        }
364        
365        /**
366         * Set the source of the right table.
367         * New source is a {@link data.StoringStock}
368         *
369         * @param m_stSource the new datasource as StoringStock
370         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
371         * 
372         * @override Never
373         */
374        public void setRightTable(  StoringStock m_stSource,
375                                                            TableEntryDescriptor ted)
376            {
377            JAbstractTable jat_c = (JAbstractTable) getRightTable();
378            AbstractTableModel atm = jat_c.getAbstractTableModel();
379            if(atm instanceof StoringStockTableModel) {
380                    atm.setData(m_stSource);        
381            }
382            else {
383                    jat_c.setModel(
384                                    new StoringStockTableModel(     m_stSource,
385                                                                                            getDataBasket(),
386                                                                                                    null,
387                                                                                                    ted));
388            }
389            
390        }
391        
392        /**
393         * Set the source of the right table.
394         * New source is a {@link data.DataBasket}
395         * 
396         * @param m_dbSource the new datasource as Databasket
397         * @param dbc a condition specifying the DataBasketEntries to be part of the model. Only necessary if prior TableModel is different from actual TableModel.
398         * @param dbeg dbeg a strategy that will group individual DataBasketEntries together for display. If
399         * <code>null</code>, no grouping will occur. Only necessary if prior TableModel is different from actual TableModel. 
400         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
401         * 
402         * @override Never
403         */
404        public void setRightTable(  DataBasket m_dbSource,
405                                                            DataBasketCondition dbc,
406                                                                    DataBasketEntryGrouper dbeg,
407                                                                    TableEntryDescriptor ted) {
408            JAbstractTable jat_c = (JAbstractTable) getRightTable();
409            AbstractTableModel atm = jat_c.getAbstractTableModel();
410            if(atm instanceof DataBasketTableModel) {
411                    atm.setData(m_dbSource);        
412            }
413            else {
414                    jat_c.setModel(
415                                    new DataBasketTableModel(       m_dbSource,
416                                                                                            dbc,
417                                                                                                    dbeg,
418                                                                                                    null,
419                                                                                                    ted));
420            }
421        }
422        
423        /**
424         * Set the source of the right table.
425         * New source is a {@link users.UserManager}
426         *
427         * @param m_umManager the new datasource as UserManager
428         * @param ted the new TableEntryDescriptor for the DataBasket. Only necessary if prior TableModel is different from actual TableModel.
429         *
430         * @override Never
431         */
432        public void setRightTable(  UserManager m_umManager,
433                                                            TableEntryDescriptor ted) {
434            JAbstractTable jat_c = (JAbstractTable) getRightTable();
435            AbstractTableModel atm = jat_c.getAbstractTableModel();
436            if(atm instanceof UserTableModel) {
437                    atm.setData(m_umManager);       
438            }
439            else {
440                    jat_c.setModel(
441                                    new UserTableModel(     m_umManager,
442                                                                            null,
443                                                                                    ted));
444            }
445        }
446        
447        /**
448         * Get the left table.
449         *
450         * @override Never
451         */
452        public JTable getLeftTable() {
453            return m_leftTable;
454        }
455    
456        /**
457         * Get the right table.
458         *
459         * @override Never
460         */
461        public JTable getRightTable() {
462            return m_rightTable;
463        }
464    
465        /**
466         * Get the strategy used when moving items between source and destination.
467         *
468         * @override Never
469         */
470        public MoveStrategy getStrategy() {
471            return m_ms;
472        }
473    
474        /**
475         * Set the strategy to be used when moving items between source and destination. Note, that the new
476         * strategy's {@link MoveStrategy#canMoveToDest} and {@link MoveStrategy#canMoveToSource} methods will
477         * have no effect. Also, it is your responsibility to make sure, that the actual class of the strategy
478         * matches the source/destination combination.
479         *
480         * @param ms the new strategy
481         *
482         * @override Never
483         */
484        public void setStrategy(MoveStrategy ms) {
485            m_ms = ms;
486        }
487    
488        /**
489         * Get the gate at which the FormSheet is being displayed.
490         *
491         * @override Never
492         */
493        public UIGate getGate() {
494            return m_uigGate;
495        }
496    
497        /**
498         * Set the gate at which to display the FormSheet. The FormSheet will be moved to the new gate, i.e.
499         * {@link UIGate#setFormSheet} will be called with the FormSheet as a parameter.
500         *
501         * @override Never
502         */
503        public void setGate(UIGate uigGate) {
504            if (m_uigGate != null) {
505                m_uigGate.setFormSheet(null);
506            }
507    
508            m_uigGate = uigGate;
509    
510            if (m_uigGate != null) {
511                m_uigGate.setFormSheet(this);
512            }
513        }
514    
515    
516        //set methods have to change the move strategy, still to do...
517        /**
518         * Changes the {@link TableModel} of the left table
519         * @param the new TableModel
520         */
521      /*  public void setLeftTableModel(util.swing.AbstractTableModel tm) {
522            m_atmLeftModel.fireTableDataChanged(); //unselect a possibly selected record
523            if (tm instanceof TableSorter) {
524                m_atmLeftModel = tm;
525            } else {
526                m_atmLeftModel = new TableSorter(tm);
527            }
528            m_leftTable.setModel(m_atmLeftModel);
529            ((JAbstractTable)m_leftTable).initialize();
530        }*/
531    
532        /**
533         * Changes the {@link TableModel} of the right table
534         * @param the new TableModel
535         */
536        /*public void setRightTableModel(util.swing.AbstractTableModel tm) {
537            m_atmRightModel.fireTableDataChanged(); //unselect a possibly selected record
538            if (tm instanceof TableSorter) {
539                m_atmRightModel = tm;
540            } else {
541                m_atmRightModel = new TableSorter(tm);
542            }
543            m_rightTable.setModel(m_atmRightModel);
544            ((JAbstractTable)m_rightTable).initialize();
545        }*/
546    
547        // 1. CountingStock -> CountingStock
548    
549        /**
550         * Create and return a new TwoTableFormSheet where source and destination are CountingStocks.
551         *
552         * <p>There will be an input line where the user can specify how many items to move with the next action.
553         * </p>
554         *
555         * @param sCaption the caption of the FormSheet.
556         * @param csSource the source Stock.
557         * @param csDest the destination Stock.
558         * @param db the DataBasket relative to which to perform all operations.
559         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
560         * {@link #setGate set} before actually using the FormSheet.
561         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
562         * keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the keys.
563         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
564         * the keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the
565         * keys.
566         * @param fShowZerosSource if false, source lines containing '0' in the &quot;Count&quot; column will be
567         * hidden.
568         * @param fShowZerosDest if false, destination lines containing '0' in the &quot;Count&quot; column will be
569         * hidden.
570         * @param tedSource a TableEntryDescriptor that can split individual
571         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
572         * used for the source table. If <code>null</code> and <code>csSource</code> is a {@link MoneyBag} it
573         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csSource.getCatalog()</code> to format values.
574         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
575         * @param tedDest a TableEntryDescriptor that can split individual
576         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
577         * used for the destination table. If <code>null</code> and <code>csDest</code> is a {@link MoneyBag} it
578         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csDest.getCatalog()</code> to format values.
579         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
580         * @param cscssMoveStrategy the strategy to be used when moving items between source and destination. If
581         * <code>null</code>, defaults to a {@link CSCSStrategy} object.
582         */
583        public static TwoTableFormSheet create(String sCaption, final CountingStock csSource,
584                final CountingStock csDest, final DataBasket db, UIGate uigGate, final Comparator<CatalogItem> cmpSource,
585                final Comparator<CatalogItem> cmpDest, final boolean fShowZerosSource, final boolean fShowZerosDest,
586                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
587                CSCSStrategy cscssMoveStrategy) {
588    
589            if (csSource.getCatalog(db) != csDest.getCatalog(db)) {
590                throw new CatalogConflictException();
591            }
592    
593            FormSheetContentCreator fscc = new FormSheetContentCreator() {
594                            private static final long serialVersionUID = -8133335597008065230L;
595    
596                            protected void createFormSheetContent(FormSheet fs) {
597    
598                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
599    
600                    final int[] anCounter = {
601                            1};
602    
603                    JCountingStockTable jcstSource = new JCountingStockTable(csSource, db, cmpSource,
604                            fShowZerosSource,
605                            ((tedSource != null) ? (tedSource) : ((csSource instanceof MoneyBag) ?
606                            (new DefaultMoneyBagItemTED((data.Currency)csSource.getCatalog(db))) :
607                            (new DefaultCountingStockItemTED()))));
608                    jcstSource.setSelectionObserver(ttfs.m_anLeftSelection);
609                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jcstSource.
610                            getModel();
611    
612                    ttfs.m_atmLeftModel = atmSource;
613                    ttfs.m_leftTable = jcstSource;
614                    ttfs.m_leftSource = csSource;
615                    ttfs.m_db = db;
616    
617                    JCountingStockTable jcstDest = new JCountingStockTable(csDest, db, cmpDest, fShowZerosDest,
618                            ((tedDest != null) ? (tedDest) : ((csDest instanceof MoneyBag) ?
619                            (new DefaultMoneyBagItemTED((data.Currency)csDest.getCatalog(db))) :
620                            (new DefaultCountingStockItemTED()))));
621                    jcstDest.setSelectionObserver(ttfs.m_anRightSelection);
622                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jcstDest.
623                            getModel();
624    
625                    ttfs.m_atmRightModel = atmDest;
626                    ttfs.m_rightTable = jcstDest;
627                    ttfs.m_rightSource = csDest;
628    
629                    JTextField jtf = new JIntInput(anCounter, 1, 1, Integer.MAX_VALUE);
630    
631                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
632                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
633    
634                    JPanel jpForm = new JPanel();
635                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
636    
637                    jpForm.add(new JScrollPane(jcstSource));
638    
639                    jpForm.add(createCentralBox(jbRight, jbLeft, jtf, ttfs.getStrategy()));
640    
641                    jpForm.add(new JScrollPane(jcstDest));
642    
643                    if (ttfs.getStrategy().canMoveToDest()) {
644                        jbRight.addActionListener(new ActionActionListener(fs) {
645                                                    private static final long serialVersionUID = 1112118904469417631L;
646    
647                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
648                                CountingStockTableModel.Record r = (CountingStockTableModel.Record)atmSource.
649                                        getRecord(ttfs.m_anLeftSelection[0]);
650    
651                                if (r != null) {
652                                    UIGate uig = ttfs.getGate();
653                                    if (uig != null) {
654                                        uig.setNextTransition(((CSCSStrategy)ttfs.getStrategy()).
655                                                getMoveToDestProcess(p, sp, csSource, csDest, db, r.getDescriptor(),
656                                                anCounter[0], ttfs));
657                                    }
658                                }
659                            }
660                        });
661                    }
662    
663                    if (ttfs.getStrategy().canMoveToSource()) {
664                        jbLeft.addActionListener(new ActionActionListener(fs) {
665                                                    private static final long serialVersionUID = -8570898083061871811L;
666    
667                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
668                                CountingStockTableModel.Record r = (CountingStockTableModel.Record)atmDest.
669                                        getRecord(ttfs.m_anRightSelection[0]);
670    
671                                if (r != null) {
672                                    UIGate uig = ttfs.getGate();
673                                    if (uig != null) {
674                                        uig.setNextTransition(((CSCSStrategy)ttfs.getStrategy()).
675                                                getMoveToSourceProcess(p, sp, csSource, csDest, db,
676                                                r.getDescriptor(), anCounter[0], ttfs));
677                                    }
678                                }
679                            }
680                        });
681                    }
682    
683                    fs.setComponent(jpForm);
684                }
685            };
686    
687            cscssMoveStrategy = ((cscssMoveStrategy != null) ? (cscssMoveStrategy) : (new CSCSStrategy()));
688    
689            return new TwoTableFormSheet(sCaption, fscc, uigGate, cscssMoveStrategy);
690        }
691    
692        /**
693         * Create and return a new TwoTableFormSheet where source and destination are CountingStocks.
694         *
695         * <p>Calls the appropriate fully parameterized function, passing default values (i.e. <code>null</code> or
696         * false) for the missing parameters.</p>
697         *
698         * @param sCaption the caption of the FormSheet.
699         * @param csSource the source Stock.
700         * @param csDest the destination Stock.
701         * @param db the DataBasket relative to which to perform all operations.
702         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
703         * {@link #setGate set} before actually using the FormSheet.
704         */
705        public static TwoTableFormSheet create(String sCaption, CountingStock csSource, CountingStock csDest,
706                DataBasket db, UIGate uigGate) {
707            return create(sCaption, csSource, csDest, db, uigGate, null, null, false, false, null, null, null);
708        }
709    
710        // 2. StoringStock -> StoringStock
711    
712        /**
713         * Create and return a new TwoTableFormSheet where source and destination are StoringStocks.
714         *
715         * @param sCaption the caption of the FormSheet.
716         * @param ssSource the source Stock.
717         * @param ssDest the destination Stock.
718         * @param db the DataBasket relative to which to perform all operations.
719         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
720         * {@link #setGate set} before actually using the FormSheet.
721         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
722         * individual items. If <code>null</code> the ordering will be the natural ordering of the items.
723         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
724         * the individual items. If <code>null</code> the ordering will be the natural ordering of the items.
725         * @param tedSource a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
726         * table's cells. It will be used for the source table. If <code>null</code> it defaults to a
727         * {@link DefaultStockItemTED}.
728         * @param tedDest a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
729         * table's cells. It will be used for the destination table. If <code>null</code> it defaults to a
730         * {@link DefaultStockItemTED}.
731         * @param sssssMoveStrategy the strategy to be used when moving items between source and destination. If
732         * <code>null</code>, defaults to a {@link SSSSStrategy} object.
733         */
734        public static TwoTableFormSheet create(String sCaption, final StoringStock ssSource,
735                final StoringStock ssDest, final DataBasket db, UIGate uigGate, final Comparator<StockItem> cmpSource,
736                final Comparator<StockItem> cmpDest, final TableEntryDescriptor tedSource,
737                final TableEntryDescriptor tedDest, SSSSStrategy sssssMoveStrategy) {
738            FormSheetContentCreator fscc = new FormSheetContentCreator() {
739                            private static final long serialVersionUID = -3246844792440325885L;
740    
741                            protected void createFormSheetContent(FormSheet fs) {
742                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
743    
744                    JStoringStockTable jsstSource = new JStoringStockTable(ssSource, db, cmpSource,
745                            ((tedSource != null) ? (tedSource) : (new DefaultStockItemTED())));
746                    jsstSource.setSelectionObserver(ttfs.m_anLeftSelection);
747                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jsstSource.
748                            getModel();
749    
750                    ttfs.m_atmLeftModel = atmSource;
751                    ttfs.m_leftTable = jsstSource;
752                    ttfs.m_leftSource = ssSource;
753                    ttfs.m_db = db;
754    
755                    JStoringStockTable jsstDest = new JStoringStockTable(ssDest, db, cmpDest,
756                            ((tedDest != null) ? (tedDest) : (new DefaultStockItemTED())));
757                    jsstDest.setSelectionObserver(ttfs.m_anRightSelection);
758                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jsstDest.
759                            getModel();
760    
761                    ttfs.m_atmRightModel = atmDest;
762                    ttfs.m_rightTable = jsstDest;
763                    ttfs.m_rightSource = ssDest;
764    
765                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
766                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
767    
768                    JPanel jpForm = new JPanel();
769                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
770    
771                    jpForm.add(new JScrollPane(jsstSource));
772    
773                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
774    
775                    jpForm.add(new JScrollPane(jsstDest));
776    
777                    if (ttfs.getStrategy().canMoveToDest()) {
778                        jbRight.addActionListener(new ActionActionListener(fs) {
779                                                    private static final long serialVersionUID = -4181225063618764681L;
780    
781                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
782                                StockItem si = (StockItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
783    
784                                if (si != null) {
785                                    UIGate uig = ttfs.getGate();
786                                    if (uig != null) {
787                                        uig.setNextTransition(((SSSSStrategy)ttfs.getStrategy()).
788                                                getMoveToDestProcess(p, sp, ssSource, ssDest, db, si, ttfs));
789                                    }
790                                }
791                            }
792                        });
793                    }
794    
795                    if (ttfs.getStrategy().canMoveToSource()) {
796                        jbLeft.addActionListener(new ActionActionListener(fs) {
797                                                    private static final long serialVersionUID = -4160594553952172204L;
798    
799                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
800                                StockItem si = (StockItem)atmDest.getRecord(ttfs.m_anRightSelection[0]);
801    
802                                if (si != null) {
803                                    UIGate uig = ttfs.getGate();
804                                    if (uig != null) {
805                                        uig.setNextTransition(((SSSSStrategy)ttfs.getStrategy()).
806                                                getMoveToSourceProcess(p, sp, ssSource, ssDest, db, si, ttfs));
807                                    }
808                                }
809                            }
810                        });
811                    }
812    
813                    fs.setComponent(jpForm);
814                }
815            };
816    
817            sssssMoveStrategy = ((sssssMoveStrategy != null) ? (sssssMoveStrategy) : (new SSSSStrategy()));
818    
819            return new TwoTableFormSheet(sCaption, fscc, uigGate, sssssMoveStrategy);
820        }
821    
822        /**
823         * Create and return a new TwoTableFormSheet where source and destination are StoringStocks.
824         *
825         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
826         * parameters.</p>
827         *
828         * @param sCaption the caption of the FormSheet.
829         * @param ssSource the source Stock.
830         * @param ssDest the destination Stock.
831         * @param db the DataBasket relative to which to perform all operations.
832         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
833         * {@link #setGate set} before actually using the FormSheet.
834         */
835        public static TwoTableFormSheet create(String sCaption, StoringStock ssSource, StoringStock ssDest,
836                DataBasket db, UIGate uigGate) {
837    
838            return create(sCaption, ssSource, ssDest, db, uigGate, null, null, null, null, null);
839        }
840    
841        // 3. CountingStock -> DataBasket
842    
843        /**
844         * Create and return a new TwoTableFormSheet where the source is a CountingStock and the destination is a
845         * DataBasket.
846         *
847         * <p>There will be an input line where the user can specify how many items to move with the next action.
848         * </p>
849         *
850         * @param sCaption the caption of the FormSheet.
851         * @param csSource the source Stock.
852         * @param dbDest the destination DataBasket.
853         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
854         * {@link #setGate set} before actually using the FormSheet.
855         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
856         * keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the keys.
857         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
858         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
859         * secondary keys.
860         * @param dbegDest a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
861         * right JDataBasketTable.
862         * @param fShowZeros if false, source lines containing '0' in the &quot;Count&quot; column will be hidden.
863         * @param tedSource a TableEntryDescriptor that can split individual
864         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
865         * used for the source table. If <code>null</code> and <code>csSource</code> is a {@link MoneyBag} it
866         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csSource.getCatalog()</code> to format values.
867         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
868         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
869         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
870         * {@link DefaultCountingStockDBETableEntryDescriptor}.
871         * @param csdbsMoveStrategy the strategy to be used when moving items between source and destination. If
872         * <code>null</code>, defaults to a {@link CSDBStrategy} object.
873         */
874        public static TwoTableFormSheet create(String sCaption, final CountingStock csSource,
875                final DataBasket dbDest, UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
876                final DataBasketEntryGrouper dbegDest, final boolean fShowZeros,
877                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
878                CSDBStrategy csdbsMoveStrategy) {
879    
880            FormSheetContentCreator fscc = new FormSheetContentCreator() {
881                            private static final long serialVersionUID = -5795620030475564035L;
882    
883                            protected void createFormSheetContent(FormSheet fs) {
884                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
885    
886                    final int[] anCounter = {
887                            1};
888    
889                    JCountingStockTable jcstSource = new JCountingStockTable(csSource, dbDest, cmpSource,
890                            fShowZeros,
891                            ((tedSource != null) ? (tedSource) : ((csSource instanceof MoneyBag) ?
892                            (new DefaultMoneyBagItemTED((data.Currency)csSource.getCatalog(dbDest))) :
893                            (new DefaultCountingStockItemTED()))));
894                    jcstSource.setSelectionObserver(ttfs.m_anLeftSelection);
895                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jcstSource.
896                            getModel();
897    
898                    ttfs.m_atmLeftModel = atmSource;
899                    ttfs.m_leftTable = jcstSource;
900                    ttfs.m_leftSource = csSource;
901                    ttfs.m_db = dbDest;
902    
903                    JDataBasketTable jdbtDest = new JDataBasketTable(dbDest,
904                            ((csSource instanceof AbstractStockFilter) ?
905                            DataBasketConditionImpl.allStockItemsWithSource(((AbstractStockFilter)csSource).
906                            getMainStock()) : DataBasketConditionImpl.allStockItemsWithSource(csSource)),
907                            ((dbegDest != null) ? (dbegDest) : (new CountingStockDBEGrouper())), cmpDest,
908                            ((tedDest != null) ? (tedDest) : (new DefaultCountingStockDBETableEntryDescriptor())));
909                    jdbtDest.setSelectionObserver(ttfs.m_anRightSelection);
910                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jdbtDest.
911                            getModel();
912    
913                    ttfs.m_atmRightModel = atmDest;
914                    ttfs.m_rightTable = jdbtDest;
915                    ttfs.m_rightSource = dbDest;
916    
917                    JTextField jtf = new JIntInput(anCounter, 1, 1, Integer.MAX_VALUE);
918    
919                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
920                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
921    
922                    JPanel jpForm = new JPanel();
923                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
924    
925                    jpForm.add(new JScrollPane(jcstSource));
926    
927                    jpForm.add(createCentralBox(jbRight, jbLeft, jtf, ttfs.getStrategy()));
928    
929                    jpForm.add(new JScrollPane(jdbtDest));
930    
931                    if (ttfs.getStrategy().canMoveToDest()) {
932                        jbRight.addActionListener(new ActionActionListener(fs) {
933                                                    private static final long serialVersionUID = 4471703500502108028L;
934    
935                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
936                                CountingStockTableModel.Record r = (CountingStockTableModel.Record)atmSource.
937                                        getRecord(ttfs.m_anLeftSelection[0]);
938    
939                                if (r != null) {
940                                    UIGate uig = ttfs.getGate();
941                                    if (uig != null) {
942                                        uig.setNextTransition(((CSDBStrategy)ttfs.getStrategy()).
943                                                getMoveToDestProcess(p, sp, csSource, dbDest, r.getDescriptor(),
944                                                anCounter[0], ttfs));
945                                    }
946                                }
947                            }
948                        });
949                    }
950    
951                    if (ttfs.getStrategy().canMoveToSource()) {
952                        jbLeft.addActionListener(new ActionActionListener(fs) {
953                                                    private static final long serialVersionUID = -5007638342896652663L;
954    
955                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
956                                DataBasketEntry dbe = (DataBasketEntry)atmDest.getRecord(ttfs.m_anRightSelection[
957                                        0]);
958    
959                                if (dbe != null) {
960                                    UIGate uig = ttfs.getGate();
961                                    if (uig != null) {
962                                        uig.setNextTransition(((CSDBStrategy)ttfs.getStrategy()).
963                                                getMoveToSourceProcess(p, sp, csSource, dbDest, dbe, anCounter[0],
964                                                ttfs));
965                                    }
966                                }
967                            }
968                        });
969                    }
970    
971                    fs.setComponent(jpForm);
972                }
973            };
974    
975            csdbsMoveStrategy = ((csdbsMoveStrategy != null) ? (csdbsMoveStrategy) : (new CSDBStrategy()));
976    
977            return new TwoTableFormSheet(sCaption, fscc, uigGate, csdbsMoveStrategy);
978        }
979    
980        /**
981         * Create and return a new TwoTableFormSheet where the source is a CountingStock and the destination is a
982         * DataBasket.
983         *
984         * <p>There will be an input line where the user can specify how many items to move with the next action.
985         * </p>
986         *
987         * @param sCaption the caption of the FormSheet.
988         * @param csSource the source Stock.
989         * @param dbDest the destination DataBasket.
990         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
991         * {@link #setGate set} before actually using the FormSheet.
992         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
993         * keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the keys.
994         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
995         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
996         * secondary keys.
997         * @param fShowZeros if false, source lines containing '0' in the &quot;Count&quot; column will be hidden.
998         * @param tedSource a TableEntryDescriptor that can split individual
999         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
1000         * used for the source table. If <code>null</code> and <code>csSource</code> is a {@link MoneyBag} it
1001         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csSource.getCatalog()</code> to format values.
1002         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
1003         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
1004         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
1005         * {@link DefaultCountingStockDBETableEntryDescriptor}.
1006         * @param csdbsMoveStrategy the strategy to be used when moving items between source and destination. If
1007         * <code>null</code>, defaults to a {@link CSDBStrategy} object.
1008         */
1009        public static TwoTableFormSheet create(String sCaption, final CountingStock csSource,
1010                final DataBasket dbDest, UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
1011                final boolean fShowZeros, final TableEntryDescriptor tedSource,
1012                final TableEntryDescriptor tedDest, CSDBStrategy csdbsMoveStrategy) {
1013            return create(sCaption, csSource, dbDest, uigGate, cmpSource, cmpDest, null, fShowZeros, tedSource,
1014                    tedDest, csdbsMoveStrategy);
1015        }
1016    
1017        /**
1018         * Create and return a new TwoTableFormSheet where the source is a CountingStocks and the destination is a
1019         * DataBasket.
1020         *
1021         * <p>Calls the appropriate fully parameterized function, passing default values (i.e. <code>null</code> or
1022         * false) for the missing parameters.</p>
1023         *
1024         * @param sCaption the caption of the FormSheet.
1025         * @param csSource the source Stock.
1026         * @param dbDest the destination DataBasket.
1027         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1028         * {@link #setGate set} before actually using the FormSheet.
1029         */
1030        public static TwoTableFormSheet create(String sCaption, CountingStock csSource, DataBasket dbDest,
1031                UIGate uigGate) {
1032            return create(sCaption, csSource, dbDest, uigGate, null, null, null, false, null, null, null);
1033        }
1034    
1035        // 4. DataBasket -> CountingStock
1036    
1037        /**
1038         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1039         * CountingStock.
1040         *
1041         * <p>There will be an input line where the user can specify how many items to move with the next action.
1042         * </p>
1043         *
1044         * @param sCaption the caption of the FormSheet.
1045         * @param dbSource the source DataBasket.
1046         * @param csDest the destination Stock.
1047         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1048         * {@link #setGate set} before actually using the FormSheet.
1049         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
1050         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1051         * secondary keys.
1052         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1053         * the keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the
1054         * keys.
1055         * @param dbegSource a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
1056         * left JDataBasketTable.
1057         * @param fShowZeros if false, destination lines containing '0' in the &quot;Count&quot; column will be
1058         * hidden.
1059         * @param tedSource a TableEntryDescriptor that can split individual
1060         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table.
1061         * If <code>null</code>  it defaults to a {@link DefaultCountingStockDBETableEntryDescriptor}.
1062         * @param tedDest a TableEntryDescriptor that can split individual
1063         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
1064         * used for the destination table. If <code>null</code> and <code>csDest</code> is a {@link MoneyBag} it
1065         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csDest.getCatalog()</code> to format values.
1066         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
1067         * @param dbcssMoveStrategy the strategy to be used when moving items between source and destination. If
1068         * <code>null</code>, defaults to a {@link DBCSStrategy} object.
1069         */
1070        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource,
1071                final CountingStock csDest, UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<CatalogItem> cmpDest,
1072                final DataBasketEntryGrouper dbegSource, final boolean fShowZeros,
1073                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
1074                DBCSStrategy dbcssMoveStrategy) {
1075    
1076            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1077                            private static final long serialVersionUID = -2079940405267654611L;
1078    
1079                            protected void createFormSheetContent(FormSheet fs) {
1080                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1081    
1082                    final int[] anCounter = {
1083                            1};
1084    
1085                    JDataBasketTable jdbtSource = new JDataBasketTable(dbSource,
1086                            new DataBasketConditionImpl(DataBasketKeys.STOCK_ITEM_MAIN_KEY, null, null, null, null) {
1087                                            private static final long serialVersionUID = 1142154905328043110L;
1088    
1089                                            public boolean match(DataBasketEntry dbe) {
1090                            return (dbe.getDestination() == null);
1091                        }
1092                    }
1093    
1094                    , ((dbegSource != null) ? (dbegSource) : (new CountingStockDBEGrouper())), cmpSource,
1095                            ((tedSource != null) ? (tedSource) : (new DefaultCountingStockDBETableEntryDescriptor())));
1096                    jdbtSource.setSelectionObserver(ttfs.m_anLeftSelection);
1097                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jdbtSource.
1098                            getModel();
1099    
1100                    ttfs.m_atmLeftModel = atmSource;
1101                    ttfs.m_leftTable = jdbtSource;
1102                    ttfs.m_leftSource = dbSource;
1103                    ttfs.m_db = dbSource;
1104    
1105                    JCountingStockTable jcstDest = new JCountingStockTable(csDest, dbSource, cmpDest, fShowZeros,
1106                            ((tedDest != null) ? (tedDest) : ((csDest instanceof MoneyBag) ?
1107                            (new DefaultMoneyBagItemTED((data.Currency)csDest.getCatalog(dbSource))) :
1108                            (new DefaultCountingStockItemTED()))));
1109                    jcstDest.setSelectionObserver(ttfs.m_anRightSelection);
1110                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jcstDest.
1111                            getModel();
1112    
1113                    ttfs.m_atmRightModel = atmDest;
1114                    ttfs.m_rightTable = jcstDest;
1115                    ttfs.m_rightSource = csDest;
1116    
1117                    JTextField jtf = new JIntInput(anCounter, 1, 1, Integer.MAX_VALUE);
1118    
1119                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1120                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1121    
1122                    JPanel jpForm = new JPanel();
1123                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1124    
1125                    jpForm.add(new JScrollPane(jdbtSource));
1126    
1127                    jpForm.add(createCentralBox(jbRight, jbLeft, jtf, ttfs.getStrategy()));
1128    
1129                    jpForm.add(new JScrollPane(jcstDest));
1130    
1131                    if (ttfs.getStrategy().canMoveToDest()) {
1132                        jbRight.addActionListener(new ActionActionListener(fs) {
1133                                                    private static final long serialVersionUID = -8588835240056512061L;
1134    
1135                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1136                                DataBasketEntry dbe = (DataBasketEntry)atmSource.getRecord(ttfs.m_anLeftSelection[
1137                                        0]);
1138    
1139                                if (dbe != null) {
1140                                    UIGate uig = ttfs.getGate();
1141                                    if (uig != null) {
1142                                        uig.setNextTransition(((DBCSStrategy)ttfs.getStrategy()).
1143                                                getMoveToDestProcess(p, sp, dbSource, csDest, dbe, anCounter[0],
1144                                                ttfs));
1145                                    }
1146                                }
1147                            }
1148                        });
1149                    }
1150    
1151                    if (ttfs.getStrategy().canMoveToSource()) {
1152                        jbLeft.addActionListener(new ActionActionListener(fs) {
1153                                                    private static final long serialVersionUID = 5431271030825698400L;
1154    
1155                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1156                                CountingStockTableModel.Record r = (CountingStockTableModel.Record)atmDest.
1157                                        getRecord(ttfs.m_anRightSelection[0]);
1158    
1159                                if (r != null) {
1160                                    UIGate uig = ttfs.getGate();
1161                                    if (uig != null) {
1162                                        uig.setNextTransition(((DBCSStrategy)ttfs.getStrategy()).
1163                                                getMoveToSourceProcess(p, sp, dbSource, csDest, r.getDescriptor(),
1164                                                anCounter[0], ttfs));
1165                                    }
1166                                }
1167                            }
1168                        });
1169                    }
1170    
1171                    fs.setComponent(jpForm);
1172                }
1173            };
1174    
1175            dbcssMoveStrategy = ((dbcssMoveStrategy != null) ? (dbcssMoveStrategy) : (new DBCSStrategy()));
1176    
1177            return new TwoTableFormSheet(sCaption, fscc, uigGate, dbcssMoveStrategy);
1178        }
1179    
1180        /**
1181         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1182         * CountingStock.
1183         *
1184         * <p>There will be an input line where the user can specify how many items to move with the next action.
1185         * </p>
1186         *
1187         * @param sCaption the caption of the FormSheet.
1188         * @param dbSource the source DataBasket.
1189         * @param csDest the destination Stock.
1190         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1191         * {@link #setGate set} before actually using the FormSheet.
1192         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
1193         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1194         * secondary keys.
1195         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1196         * the keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the
1197         * keys.
1198         * @param fShowZeros if false, destination lines containing '0' in the &quot;Count&quot; column will be
1199         * hidden.
1200         * @param tedSource a TableEntryDescriptor that can split individual
1201         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table.
1202         * If <code>null</code>  it defaults to a {@link DefaultCountingStockDBETableEntryDescriptor}.
1203         * @param tedDest a TableEntryDescriptor that can split individual
1204         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
1205         * used for the destination table. If <code>null</code> and <code>csDest</code> is a {@link MoneyBag} it
1206         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csDest.getCatalog()</code> to format values.
1207         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
1208         * @param dbcssMoveStrategy the strategy to be used when moving items between source and destination. If
1209         * <code>null</code>, defaults to a {@link DBCSStrategy} object.
1210         */
1211        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource,
1212                final CountingStock csDest, UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<CatalogItem> cmpDest,
1213                final boolean fShowZeros, final TableEntryDescriptor tedSource,
1214                final TableEntryDescriptor tedDest, DBCSStrategy dbcssMoveStrategy) {
1215            return create(sCaption, dbSource, csDest, uigGate, cmpSource, cmpDest, null, fShowZeros, tedSource,
1216                    tedDest, dbcssMoveStrategy);
1217        }
1218    
1219        /**
1220         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1221         * CountingStock.
1222         *
1223         * <p>Calls the appropriate fully parameterized function, passing default values (i.e. <code>null</code> or
1224         * false) for the missing parameters.</p>
1225         *
1226         * @param sCaption the caption of the FormSheet.
1227         * @param dbSource the source DataBasket.
1228         * @param csDest the destination Stock.
1229         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1230         * {@link #setGate set} before actually using the FormSheet.
1231         */
1232        public static TwoTableFormSheet create(String sCaption, DataBasket dbSource, CountingStock csDest,
1233                UIGate uigGate) {
1234            return create(sCaption, dbSource, csDest, uigGate, null, null, null, false, null, null, null);
1235        }
1236    
1237        // 5. StoringStock -> DataBasket
1238    
1239        /**
1240         * Create and return a new TwoTableFormSheet where the source is a StoringStock and the destination is a
1241         * DataBasket.
1242         *
1243         * @param sCaption the caption of the FormSheet.
1244         * @param ssSource the source Stock.
1245         * @param dbDest the destination DataBasket.
1246         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1247         * {@link #setGate set} before actually using the FormSheet.
1248         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
1249         * individual items. If <code>null</code> the ordering will be the natural ordering of the items.
1250         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1251         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1252         * secondary keys.
1253         * @param dbegDest a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
1254         * right JDataBasketTable.
1255         * @param tedSource a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
1256         * table's cells. It will be used for the source table. If <code>null</code> it defaults to a
1257         * {@link DefaultStockItemTED}.
1258         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
1259         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
1260         * {@link DefaultStoringStockDBETableEntryDescriptor}.
1261         * @param ssdbsMoveStrategy the strategy to be used when moving items between source and destination. If
1262         * <code>null</code>, defaults to a {@link SSDBStrategy} object.
1263         */
1264        public static TwoTableFormSheet create(String sCaption, final StoringStock ssSource,
1265                final DataBasket dbDest, UIGate uigGate, final Comparator<StockItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
1266                final DataBasketEntryGrouper dbegDest, final TableEntryDescriptor tedSource,
1267                final TableEntryDescriptor tedDest, SSDBStrategy ssdbsMoveStrategy) {
1268            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1269                            private static final long serialVersionUID = -4435653161479409701L;
1270    
1271                            protected void createFormSheetContent(FormSheet fs) {
1272                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1273    
1274                    JStoringStockTable jsstSource = new JStoringStockTable(ssSource, dbDest, cmpSource,
1275                            ((tedSource != null) ? (tedSource) : (new DefaultStockItemTED())));
1276                    jsstSource.setSelectionObserver(ttfs.m_anLeftSelection);
1277                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jsstSource.
1278                            getModel();
1279    
1280                    ttfs.m_atmLeftModel = atmSource;
1281                    ttfs.m_leftTable = jsstSource;
1282                    ttfs.m_leftSource = ssSource;
1283                    ttfs.m_db = dbDest;
1284    
1285                    JDataBasketTable jdbtDest = new JDataBasketTable(dbDest,
1286                            ((ssSource instanceof AbstractStockFilter) ?
1287                            DataBasketConditionImpl.allStockItemsWithSource(((AbstractStockFilter)ssSource).
1288                            getMainStock()) : DataBasketConditionImpl.allStockItemsWithSource(ssSource)),
1289                            ((dbegDest != null) ? (dbegDest) : (NOPDataBasketEntryGrouper.NO_GROUPS)), cmpDest,
1290                            ((tedDest != null) ? (tedDest) : (new DefaultStoringStockDBETableEntryDescriptor())));
1291                    jdbtDest.setSelectionObserver(ttfs.m_anRightSelection);
1292                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jdbtDest.
1293                            getModel();
1294    
1295                    ttfs.m_atmRightModel = atmDest;
1296                    ttfs.m_rightTable = jdbtDest;
1297                    ttfs.m_rightSource = dbDest;
1298    
1299                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1300                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1301    
1302                    JPanel jpForm = new JPanel();
1303                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1304    
1305                    jpForm.add(new JScrollPane(jsstSource));
1306    
1307                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
1308    
1309                    jpForm.add(new JScrollPane(jdbtDest));
1310    
1311                    if (ttfs.getStrategy().canMoveToDest()) {
1312                        jbRight.addActionListener(new ActionActionListener(fs) {
1313                                                    private static final long serialVersionUID = -6327031877893874831L;
1314    
1315                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1316                                final StockItem si = (StockItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
1317    
1318                                if (si != null) {
1319                                    UIGate uig = ttfs.getGate();
1320                                    if (uig != null) {
1321                                        uig.setNextTransition(((SSDBStrategy)ttfs.getStrategy()).
1322                                                getMoveToDestProcess(p, sp, ssSource, dbDest, si, ttfs));
1323                                    }
1324                                }
1325                            }
1326                        });
1327                    }
1328    
1329                    if (ttfs.getStrategy().canMoveToSource()) {
1330                        jbLeft.addActionListener(new ActionActionListener(fs) {
1331                                                    private static final long serialVersionUID = -361676770169467572L;
1332    
1333                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1334                                final DataBasketEntry dbe = (DataBasketEntry)atmDest.getRecord(ttfs.
1335                                        m_anRightSelection[0]);
1336    
1337                                if (dbe != null) {
1338                                    UIGate uig = ttfs.getGate();
1339                                    if (uig != null) {
1340                                        uig.setNextTransition(((SSDBStrategy)ttfs.getStrategy()).
1341                                                getMoveToSourceProcess(p, sp, ssSource, dbDest, dbe, ttfs));
1342                                    }
1343                                }
1344                            }
1345                        });
1346                    }
1347    
1348                    fs.setComponent(jpForm);
1349                }
1350            };
1351    
1352            ssdbsMoveStrategy = ((ssdbsMoveStrategy != null) ? (ssdbsMoveStrategy) : (new SSDBStrategy()));
1353    
1354            return new TwoTableFormSheet(sCaption, fscc, uigGate, ssdbsMoveStrategy);
1355        }
1356    
1357        /**
1358         * Create and return a new TwoTableFormSheet where the source is a StoringStock and the destination is a
1359         * DataBasket.
1360         *
1361         * @param sCaption the caption of the FormSheet.
1362         * @param ssSource the source Stock.
1363         * @param dbDest the destination DataBasket.
1364         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1365         * {@link #setGate set} before actually using the FormSheet.
1366         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be the
1367         * individual items. If <code>null</code> the ordering will be the natural ordering of the items.
1368         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1369         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1370         * secondary keys.
1371         * @param tedSource a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
1372         * table's cells. It will be used for the source table. If <code>null</code> it defaults to a
1373         * {@link DefaultStockItemTED}.
1374         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
1375         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
1376         * {@link DefaultStoringStockDBETableEntryDescriptor}.
1377         * @param ssdbsMoveStrategy the strategy to be used when moving items between source and destination. If
1378         * <code>null</code>, defaults to a {@link SSDBStrategy} object.
1379         */
1380        public static TwoTableFormSheet create(String sCaption, final StoringStock ssSource,
1381                final DataBasket dbDest, UIGate uigGate, final Comparator<StockItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
1382                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
1383                SSDBStrategy ssdbsMoveStrategy) {
1384            return create(sCaption, ssSource, dbDest, uigGate, cmpSource, cmpDest, null, tedSource, tedDest,
1385                    ssdbsMoveStrategy);
1386        }
1387    
1388        /**
1389         * Create and return a new TwoTableFormSheet where the source is a StoringStock and the destination is a
1390         * DataBasket.
1391         *
1392         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
1393         * parameters.</p>
1394         *
1395         * @param sCaption the caption of the FormSheet.
1396         * @param ssSource the source Stock.
1397         * @param dbDest the destination DataBasket.
1398         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1399         * {@link #setGate set} before actually using the FormSheet.
1400         */
1401        public static TwoTableFormSheet create(String sCaption, StoringStock ssSource, DataBasket dbDest,
1402                UIGate uigGate) {
1403            return create(sCaption, ssSource, dbDest, uigGate, null, null, null, null, null, null);
1404        }
1405    
1406        // 6. DataBasket -> StoringStock
1407    
1408        /**
1409         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1410         * StoringStock.
1411         *
1412         * @param sCaption the caption of the FormSheet.
1413         * @param dbSource the source DataBasket.
1414         * @param ssDest the destination Stock.
1415         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1416         * {@link #setGate set} before actually using the FormSheet.
1417         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
1418         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1419         * secondary keys.
1420         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1421         * the individual items. If <code>null</code> the ordering will be the natural ordering of the items.
1422         * @param dbegSource a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
1423         * left JDataBasketTable.
1424         * @param tedSource a TableEntryDescriptor that can split individual
1425         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table. If
1426         * <code>null</code>  it defaults to a {@link DefaultStoringStockDBETableEntryDescriptor}.
1427         * @param tedDest a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
1428         * table's cells. It will be used for the destination table. If <code>null</code> it defaults to a
1429         * {@link DefaultStockItemTED}.
1430         * @param dbsssMoveStrategy the strategy to be used when moving items between source and destination. If
1431         * <code>null</code>, defaults to a {@link DBSSStrategy} object.
1432         */
1433        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource,
1434                final StoringStock ssDest, UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<StockItem> cmpDest,
1435                final DataBasketEntryGrouper dbegSource, final TableEntryDescriptor tedSource,
1436                final TableEntryDescriptor tedDest, DBSSStrategy dbsssMoveStrategy) {
1437            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1438                            private static final long serialVersionUID = 5765146452893400940L;
1439    
1440                            protected void createFormSheetContent(FormSheet fs) {
1441                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1442    
1443                    JDataBasketTable jdbtSource = new JDataBasketTable(dbSource,
1444                            new DataBasketConditionImpl(DataBasketKeys.STOCK_ITEM_MAIN_KEY, null, null, null, null) {
1445                                            private static final long serialVersionUID = -5401073810821293576L;
1446    
1447                                            public boolean match(DataBasketEntry dbe) {
1448                            return (dbe.getDestination() == null);
1449                        }
1450                    }
1451    
1452                    , ((dbegSource != null) ? (dbegSource) : (NOPDataBasketEntryGrouper.NO_GROUPS)), cmpSource,
1453                            ((tedSource != null) ? (tedSource) : (new DefaultStoringStockDBETableEntryDescriptor())));
1454                    jdbtSource.setSelectionObserver(ttfs.m_anLeftSelection);
1455                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jdbtSource.
1456                            getModel();
1457    
1458                    ttfs.m_atmLeftModel = atmSource;
1459                    ttfs.m_leftTable = jdbtSource;
1460                    ttfs.m_leftSource = dbSource;
1461                    ttfs.m_db = dbSource;
1462    
1463                    JStoringStockTable jsstDest = new JStoringStockTable(ssDest, dbSource, cmpDest,
1464                            ((tedDest != null) ? (tedDest) : (new DefaultStockItemTED())));
1465                    jsstDest.setSelectionObserver(ttfs.m_anRightSelection);
1466                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jsstDest.
1467                            getModel();
1468    
1469                    ttfs.m_atmRightModel = atmDest;
1470                    ttfs.m_rightTable = jsstDest;
1471                    ttfs.m_rightSource = ssDest;
1472    
1473                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1474                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1475    
1476                    JPanel jpForm = new JPanel();
1477                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1478    
1479                    jpForm.add(new JScrollPane(jdbtSource));
1480    
1481                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
1482    
1483                    jpForm.add(new JScrollPane(jsstDest));
1484    
1485                    if (ttfs.getStrategy().canMoveToDest()) {
1486                        jbRight.addActionListener(new ActionActionListener(fs) {
1487                                                    private static final long serialVersionUID = 1913174881601181320L;
1488    
1489                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1490                                final DataBasketEntry dbe = (DataBasketEntry)atmSource.getRecord(ttfs.
1491                                        m_anLeftSelection[0]);
1492    
1493                                if (dbe != null) {
1494                                    UIGate uig = ttfs.getGate();
1495                                    if (uig != null) {
1496                                        uig.setNextTransition(((DBSSStrategy)ttfs.getStrategy()).
1497                                                getMoveToDestProcess(p, sp, dbSource, ssDest, dbe, ttfs));
1498                                    }
1499                                }
1500                            }
1501                        });
1502                    }
1503    
1504                    if (ttfs.getStrategy().canMoveToSource()) {
1505                        jbLeft.addActionListener(new ActionActionListener(fs) {
1506                                                    private static final long serialVersionUID = -207034683832569198L;
1507    
1508                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1509                                final StockItem si = (StockItem)atmDest.getRecord(ttfs.m_anRightSelection[0]);
1510    
1511                                if (si != null) {
1512                                    UIGate uig = ttfs.getGate();
1513                                    if (uig != null) {
1514                                        uig.setNextTransition(((DBSSStrategy)ttfs.getStrategy()).
1515                                                getMoveToSourceProcess(p, sp, dbSource, ssDest, si, ttfs));
1516                                    }
1517                                }
1518                            }
1519                        });
1520                    }
1521    
1522                    fs.setComponent(jpForm);
1523                }
1524            };
1525    
1526            dbsssMoveStrategy = ((dbsssMoveStrategy != null) ? (dbsssMoveStrategy) : (new DBSSStrategy()));
1527    
1528            return new TwoTableFormSheet(sCaption, fscc, uigGate, dbsssMoveStrategy);
1529        }
1530    
1531        /**
1532         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1533         * StoringStock.
1534         *
1535         * @param sCaption the caption of the FormSheet.
1536         * @param dbSource the source DataBasket.
1537         * @param ssDest the destination Stock.
1538         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1539         * {@link #setGate set} before actually using the FormSheet.
1540         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
1541         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1542         * secondary keys.
1543         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1544         * the individual items. If <code>null</code> the ordering will be the natural ordering of the items.
1545         * @param tedSource a TableEntryDescriptor that can split individual
1546         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table. If
1547         * <code>null</code>  it defaults to a {@link DefaultStoringStockDBETableEntryDescriptor}.
1548         * @param tedDest a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
1549         * table's cells. It will be used for the destination table. If <code>null</code> it defaults to a
1550         * {@link DefaultStockItemTED}.
1551         * @param dbsssMoveStrategy the strategy to be used when moving items between source and destination. If
1552         * <code>null</code>, defaults to a {@link DBSSStrategy} object.
1553         */
1554        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource,
1555                final StoringStock ssDest, UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<StockItem> cmpDest,
1556                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
1557                DBSSStrategy dbsssMoveStrategy) {
1558            return create(sCaption, dbSource, ssDest, uigGate, cmpSource, cmpDest, null, tedSource, tedDest,
1559                    dbsssMoveStrategy);
1560        }
1561    
1562        /**
1563         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1564         * StoringStock.
1565         *
1566         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
1567         * parameters.</p>
1568         *
1569         * @param sCaption the caption of the FormSheet.
1570         * @param dbSource the source DataBasket.
1571         * @param ssDest the destination Stock.
1572         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1573         * {@link #setGate set} before actually using the FormSheet.
1574         */
1575        public static TwoTableFormSheet create(String sCaption, DataBasket dbSource, StoringStock ssDest,
1576                UIGate uigGate) {
1577            return create(sCaption, dbSource, ssDest, uigGate, null, null, null, null, null, null);
1578        }
1579    
1580        // 7. Catalog -> Catalog
1581    
1582        /**
1583         * Create and return a new TwoTableFormSheet where source and destination are Catalogs.
1584         *
1585         * @param sCaption the caption of the FormSheet.
1586         * @param cSource the source Catalog.
1587         * @param cDest the destination Catalog.
1588         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1589         * {@link #setGate set} before actually using the FormSheet.
1590         * @param cmpSource a comparator defining the source sorting order. The items to be compared are
1591         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
1592         * natural ordering.
1593         * @param cmpDest a comparator defining the destination sorting order. The items to be compared are
1594         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
1595         * natural ordering.
1596         * @param tedSource a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
1597         * for the source table. If <code>null</code> and <code>cSource</code> is a {@link Currency} it defaults to
1598         * a {@link DefaultCurrencyItemTED} using <code>cSource</code> to format values. Otherwise, it defaults to a
1599         * {@link DefaultCatalogItemTED}.
1600         * @param tedDest a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
1601         * for the destination table. If <code>null</code> and <code>cDest</code> is a {@link Currency} it defaults
1602         * to a {@link DefaultCurrencyItemTED} using <code>cDest</code> to format values. Otherwise, it defaults to
1603         * a {@link DefaultCatalogItemTED}.
1604         * @param ccsMoveStrategy the strategy to be used when moving items between source and destination. If
1605         * <code>null</code> it defaults to a {@link CCStrategy} object.
1606         */
1607        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final Catalog cDest,
1608                final DataBasket db, UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<CatalogItem> cmpDest,
1609                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
1610                CCStrategy ccsMoveStrategy) {
1611            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1612                            private static final long serialVersionUID = 5921766528918967555L;
1613    
1614                            protected void createFormSheetContent(FormSheet fs) {
1615                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1616    
1617                    JCatalogTable jctSource = new JCatalogTable(cSource, db, cmpSource,
1618                            ((tedSource != null) ? (tedSource) : ((cSource instanceof data.Currency) ?
1619                            (new DefaultCurrencyItemTED((data.Currency)cSource)) : (new DefaultCatalogItemTED()))));
1620                    jctSource.setSelectionObserver(ttfs.m_anLeftSelection);
1621                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jctSource.
1622                            getModel();
1623    
1624                    ttfs.m_atmLeftModel = atmSource;
1625                    ttfs.m_leftTable = jctSource;
1626                    ttfs.m_leftSource = cSource;
1627                    ttfs.m_db = db;
1628    
1629                    JCatalogTable jctDest = new JCatalogTable(cDest, db, cmpDest,
1630                            ((tedDest != null) ? (tedDest) : ((cDest instanceof data.Currency) ?
1631                            (new DefaultCurrencyItemTED((data.Currency)cDest)) : (new DefaultCatalogItemTED()))));
1632                    jctDest.setSelectionObserver(ttfs.m_anRightSelection);
1633                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jctDest.getModel();
1634    
1635                    ttfs.m_atmRightModel = atmDest;
1636                    ttfs.m_rightTable = jctDest;
1637                    ttfs.m_rightSource = cDest;
1638    
1639                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1640                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1641    
1642                    JPanel jpForm = new JPanel();
1643                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1644    
1645                    jpForm.add(new JScrollPane(jctSource));
1646    
1647                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
1648    
1649                    jpForm.add(new JScrollPane(jctDest));
1650    
1651                    if (ttfs.getStrategy().canMoveToDest()) {
1652                        jbRight.addActionListener(new ActionActionListener(fs) {
1653                                                    private static final long serialVersionUID = 3141626245269084808L;
1654    
1655                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1656                                final CatalogItem ci = (CatalogItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
1657    
1658                                if (ci != null) {
1659                                    UIGate uig = ttfs.getGate();
1660                                    if (uig != null) {
1661                                        uig.setNextTransition(((CCStrategy)ttfs.getStrategy()).
1662                                                getMoveToDestProcess(p, sp, cSource, cDest, db, ci, ttfs));
1663                                    }
1664                                }
1665                            }
1666                        });
1667                    }
1668    
1669                    if (ttfs.getStrategy().canMoveToSource()) {
1670                        jbLeft.addActionListener(new ActionActionListener(fs) {
1671                                                    private static final long serialVersionUID = -3299578886725522974L;
1672    
1673                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1674                                final CatalogItem ci = (CatalogItem)atmDest.getRecord(ttfs.m_anRightSelection[0]);
1675    
1676                                if (ci != null) {
1677                                    UIGate uig = ttfs.getGate();
1678                                    if (uig != null) {
1679                                        uig.setNextTransition(((CCStrategy)ttfs.getStrategy()).
1680                                                getMoveToSourceProcess(p, sp, cSource, cDest, db, ci, ttfs));
1681                                    }
1682                                }
1683                            }
1684                        });
1685                    }
1686    
1687                    fs.setComponent(jpForm);
1688                }
1689            };
1690    
1691            ccsMoveStrategy = ((ccsMoveStrategy != null) ? (ccsMoveStrategy) : (new CCStrategy()));
1692    
1693            return new TwoTableFormSheet(sCaption, fscc, uigGate, ccsMoveStrategy);
1694        }
1695    
1696        /**
1697         * Create and return a new TwoTableFormSheet where source and destination are Catalogs.
1698         *
1699         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
1700         * parameters.</p>
1701         *
1702         * @param sCaption the caption of the FormSheet.
1703         * @param cSource the source Catalog.
1704         * @param cDest the destination Catalog.
1705         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1706         * {@link #setGate set} before actually using the FormSheet.
1707         */
1708        public static TwoTableFormSheet create(String sCaption, Catalog cSource, Catalog cDest, DataBasket db,
1709                UIGate uigGate) {
1710            return create(sCaption, cSource, cDest, db, uigGate, null, null, null, null, null);
1711        }
1712    
1713        // 8. Catalog -> DataBasket
1714    
1715        /**
1716         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
1717         * DataBasket.
1718         *
1719         * @param sCaption the caption of the FormSheet.
1720         * @param cSource the source Catalog.
1721         * @param dbDest the destination Databasket.
1722         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1723         * {@link #setGate set} before actually using the FormSheet.
1724         * @param cmpSource a comparator defining the source sorting order. The items to be compared are
1725         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
1726         * natural ordering.
1727         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1728         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1729         * secondary keys.
1730         * @param dbegDest a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
1731         * right JDataBasketTable.
1732         * @param tedSource a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
1733         * for the source table. If <code>null</code> and <code>cSource</code> is a {@link Currency} it defaults to
1734         * a {@link DefaultCurrencyItemTED} using <code>cSource</code> to format values. Otherwise, it defaults to a
1735         * {@link DefaultCatalogItemTED}.
1736         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
1737         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
1738         * {@link DefaultCatalogItemDBETableEntryDescriptor}.
1739         * @param cdbsMoveStrategy the strategy to be used when moving items between source and destination. If
1740         * <code>null</code> it defaults to a {@link CDBStrategy} object.
1741         */
1742        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final DataBasket dbDest,
1743                UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
1744                final DataBasketEntryGrouper dbegDest, final TableEntryDescriptor tedSource,
1745                final TableEntryDescriptor tedDest, CDBStrategy cdbsMoveStrategy) {
1746    
1747            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1748                            private static final long serialVersionUID = 406970467078360943L;
1749    
1750                            protected void createFormSheetContent(FormSheet fs) {
1751                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1752    
1753                    JCatalogTable jctSource = new JCatalogTable(cSource, dbDest, cmpSource,
1754                            ((tedSource != null) ? (tedSource) : ((cSource instanceof data.Currency) ?
1755                            (new DefaultCurrencyItemTED((data.Currency)cSource)) : (new DefaultCatalogItemTED()))));
1756                    jctSource.setSelectionObserver(ttfs.m_anLeftSelection);
1757                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jctSource.
1758                            getModel();
1759    
1760                    ttfs.m_atmLeftModel = atmSource;
1761                    ttfs.m_leftTable = jctSource;
1762                    ttfs.m_leftSource = cSource;
1763                    ttfs.m_db = dbDest;
1764    
1765                    JDataBasketTable jdbtDest = new JDataBasketTable(dbDest,
1766                            ((cSource instanceof CatalogFilter) ?
1767                            DataBasketConditionImpl.allCatalogItemsWithSource(((CatalogFilter)cSource).
1768                            getMainCatalog()) : DataBasketConditionImpl.allCatalogItemsWithSource(cSource)),
1769                            ((dbegDest != null) ? (dbegDest) : (null)), cmpDest,
1770                            ((tedDest != null) ? (tedDest) : (new DefaultCatalogItemDBETableEntryDescriptor())));
1771                    jdbtDest.setSelectionObserver(ttfs.m_anRightSelection);
1772                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jdbtDest.
1773                            getModel();
1774    
1775                    ttfs.m_atmRightModel = atmDest;
1776                    ttfs.m_rightTable = jdbtDest;
1777                    ttfs.m_rightSource = dbDest;
1778    
1779                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1780                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1781    
1782                    JPanel jpForm = new JPanel();
1783                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1784    
1785                    jpForm.add(new JScrollPane(jctSource));
1786    
1787                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
1788    
1789                    jpForm.add(new JScrollPane(jdbtDest));
1790    
1791                    if (ttfs.getStrategy().canMoveToDest()) {
1792                        jbRight.addActionListener(new ActionActionListener(fs) {
1793                                                    private static final long serialVersionUID = 7258489945075658182L;
1794    
1795                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1796                                CatalogItem ci = (CatalogItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
1797    
1798                                if (ci != null) {
1799                                    UIGate uig = ttfs.getGate();
1800                                    if (uig != null) {
1801                                        uig.setNextTransition(((CDBStrategy)ttfs.getStrategy()).
1802                                                getMoveToDestProcess(p, sp, cSource, dbDest, ci, ttfs));
1803                                    }
1804                                }
1805                            }
1806                        });
1807                    }
1808    
1809                    if (ttfs.getStrategy().canMoveToSource()) {
1810                        jbLeft.addActionListener(new ActionActionListener(fs) {
1811                                                    private static final long serialVersionUID = -8778627391361553525L;
1812    
1813                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1814                                DataBasketEntry dbe = (DataBasketEntry)atmDest.getRecord(ttfs.m_anRightSelection[
1815                                        0]);
1816    
1817                                if (dbe != null) {
1818                                    CatalogItem ci = (CatalogItem)dbe.getValue();
1819    
1820                                    if (ci != null) {
1821                                        UIGate uig = ttfs.getGate();
1822                                        if (uig != null) {
1823                                            uig.setNextTransition(((CDBStrategy)ttfs.getStrategy()).
1824                                                    getMoveToSourceProcess(p, sp, cSource, dbDest, ci, ttfs));
1825                                        }
1826                                    }
1827                                }
1828                            }
1829                        });
1830                    }
1831    
1832                    fs.setComponent(jpForm);
1833                }
1834            };
1835    
1836            cdbsMoveStrategy = ((cdbsMoveStrategy != null) ? (cdbsMoveStrategy) : (new CDBStrategy()));
1837    
1838            return new TwoTableFormSheet(sCaption, fscc, uigGate, cdbsMoveStrategy);
1839        }
1840    
1841        /**
1842         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
1843         * DataBasket.
1844         *
1845         * @param sCaption the caption of the FormSheet.
1846         * @param cSource the source Catalog.
1847         * @param dbDest the destination Databasket.
1848         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1849         * {@link #setGate set} before actually using the FormSheet.
1850         * @param cmpSource a comparator defining the source sorting order. The items to be compared are
1851         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
1852         * natural ordering.
1853         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
1854         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1855         * secondary keys.
1856         * @param tedSource a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
1857         * for the source table. If <code>null</code> and <code>cSource</code> is a {@link Currency} it defaults to
1858         * a {@link DefaultCurrencyItemTED} using <code>cSource</code> to format values. Otherwise, it defaults to a
1859         * {@link DefaultCatalogItemTED}.
1860         * @param tedDest a TableEntryDescriptor that can split individual {@link DataBasketEntry DataBasketEntries}
1861         * into a table's cells. It will be used for the destination table. If <code>null</code>  it defaults to a
1862         * {@link DefaultCatalogItemDBETableEntryDescriptor}.
1863         * @param cdbsMoveStrategy the strategy to be used when moving items between source and destination. If
1864         * <code>null</code> it defaults to a {@link CDBStrategy} object.
1865         */
1866        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final DataBasket dbDest,
1867                UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<DataBasketEntry> cmpDest,
1868                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
1869                CDBStrategy cdbsMoveStrategy) {
1870            return create(sCaption, cSource, dbDest, uigGate, cmpSource, cmpDest, null, tedSource, tedDest,
1871                    cdbsMoveStrategy);
1872        }
1873    
1874        /**
1875         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
1876         * DataBasket.
1877         *
1878         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
1879         * parameters.</p>
1880         *
1881         * @param sCaption the caption of the FormSheet.
1882         * @param cSource the source Catalog.
1883         * @param dbDest the destination Databasket.
1884         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1885         * {@link #setGate set} before actually using the FormSheet.
1886         */
1887        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final DataBasket dbDest,
1888                UIGate uigGate) {
1889            return create(sCaption, cSource, dbDest, uigGate, null, null, null, null, null, null);
1890        }
1891    
1892        // 9. DataBasket -> Catalog
1893    
1894        /**
1895         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
1896         * Catalog.
1897         *
1898         * @param sCaption the caption of the FormSheet.
1899         * @param dbSource the source Databasket.
1900         * @param cDest the destination Catalog.
1901         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
1902         * {@link #setGate set} before actually using the FormSheet.
1903         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
1904         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
1905         * secondary keys.
1906         * @param cmpSource a comparator defining the destination sorting order. The items to be compared are
1907         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
1908         * natural ordering.
1909         * @param dbegSource a {@link DataBasketEntryGrouper} defining the representation of the DataBasketEntries at the
1910         * left JDataBasketTable.
1911         * @param tedSource a TableEntryDescriptor that can split individual
1912         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table.
1913         * If <code>null</code>  it defaults to a {@link DefaultCatalogItemDBETableEntryDescriptor}.
1914         * @param tedDest a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
1915         * for the destination table. If <code>null</code> and <code>cDest</code> is a {@link Currency} it defaults
1916         * to a {@link DefaultCurrencyItemTED} using <code>cDest</code> to format values. Otherwise, it defaults to
1917         * a {@link DefaultCatalogItemTED}.
1918         * @param dbcsMoveStrategy the strategy to be used when moving items between source and destination. If
1919         * <code>null</code> it defaults to a {@link DBCStrategy} object.
1920         */
1921        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource, final Catalog cDest,
1922                UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<CatalogItem> cmpDest,
1923                final DataBasketEntryGrouper dbegSource, final TableEntryDescriptor tedSource,
1924                final TableEntryDescriptor tedDest, DBCStrategy dbcsMoveStrategy) {
1925    
1926            FormSheetContentCreator fscc = new FormSheetContentCreator() {
1927                            private static final long serialVersionUID = 459826710705161118L;
1928    
1929                            protected void createFormSheetContent(FormSheet fs) {
1930                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
1931    
1932                    JDataBasketTable jdbtSource = new JDataBasketTable(dbSource,
1933                            new DataBasketConditionImpl(DataBasketKeys.CATALOG_ITEM_MAIN_KEY, null, null, null, null) {
1934                                            private static final long serialVersionUID = 4162132666448138305L;
1935    
1936                                            public boolean match(DataBasketEntry dbe) {
1937                            return (dbe.getDestination() == null);
1938                        }
1939                    }
1940    
1941                    , ((dbegSource != null) ? (dbegSource) : (null)), cmpSource,
1942                            ((tedSource != null) ? (tedSource) : (new DefaultCountingStockDBETableEntryDescriptor())));
1943                    jdbtSource.setSelectionObserver(ttfs.m_anLeftSelection);
1944                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jdbtSource.
1945                            getModel();
1946    
1947                    ttfs.m_atmLeftModel = atmSource;
1948                    ttfs.m_leftTable = jdbtSource;
1949                    ttfs.m_leftSource = dbSource;
1950                    ttfs.m_db = dbSource;
1951    
1952                    JCatalogTable jctDest = new JCatalogTable(cDest, dbSource, cmpDest,
1953                            ((tedDest != null) ? (tedDest) : ((cDest instanceof data.Currency) ?
1954                            (new DefaultCurrencyItemTED((data.Currency)cDest)) : (new DefaultCatalogItemTED()))));
1955                    jctDest.setSelectionObserver(ttfs.m_anRightSelection);
1956                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jctDest.getModel();
1957    
1958                    ttfs.m_atmRightModel = atmDest;
1959                    ttfs.m_rightTable = jctDest;
1960                    ttfs.m_leftSource = cDest;
1961    
1962                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
1963                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
1964    
1965                    JPanel jpForm = new JPanel();
1966                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
1967    
1968                    jpForm.add(new JScrollPane(jdbtSource));
1969    
1970                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
1971    
1972                    jpForm.add(new JScrollPane(jctDest));
1973    
1974                    if (ttfs.getStrategy().canMoveToDest()) {
1975                        jbRight.addActionListener(new ActionActionListener(fs) {
1976                                                    private static final long serialVersionUID = 8884940052850676776L;
1977    
1978                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1979                                CatalogItem ci = (CatalogItem)((DataBasketEntry)atmSource.getRecord(ttfs.
1980                                        m_anLeftSelection[0])).getValue();
1981    
1982                                if (ci != null) {
1983                                    UIGate uig = ttfs.getGate();
1984                                    if (uig != null) {
1985                                        uig.setNextTransition(((DBCStrategy)ttfs.getStrategy()).
1986                                                getMoveToDestProcess(p, sp, dbSource, cDest, ci, ttfs));
1987                                    }
1988                                }
1989                            }
1990                        });
1991                    }
1992    
1993                    if (ttfs.getStrategy().canMoveToSource()) {
1994                        jbLeft.addActionListener(new ActionActionListener(fs) {
1995                                                    private static final long serialVersionUID = 3980373479669559911L;
1996    
1997                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
1998                                CatalogItem ci = (CatalogItem)atmDest.getRecord(ttfs.m_anRightSelection[0]);
1999    
2000                                if (ci != null) {
2001                                    UIGate uig = ttfs.getGate();
2002                                    if (uig != null) {
2003                                        uig.setNextTransition(((DBCStrategy)ttfs.getStrategy()).
2004                                                getMoveToSourceProcess(p, sp, dbSource, cDest, ci, ttfs));
2005                                    }
2006                                }
2007                            }
2008                        });
2009                    }
2010    
2011                    fs.setComponent(jpForm);
2012                }
2013            };
2014    
2015            dbcsMoveStrategy = ((dbcsMoveStrategy != null) ? (dbcsMoveStrategy) : (new DBCStrategy()));
2016    
2017            return new TwoTableFormSheet(sCaption, fscc, uigGate, dbcsMoveStrategy);
2018        }
2019    
2020        /**
2021         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
2022         * Catalog.
2023         *
2024         * @param sCaption the caption of the FormSheet.
2025         * @param dbSource the source Databasket.
2026         * @param cDest the destination Catalog.
2027         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2028         * {@link #setGate set} before actually using the FormSheet.
2029         * @param cmpSource a comparator defining the source sorting order. The objects to be compared will be
2030         * DataBasketEntries. If <code>null</code> the entries will be ordered first by their main and then by their
2031         * secondary keys.
2032         * @param cmpSource a comparator defining the destination sorting order. The items to be compared are
2033         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
2034         * natural ordering.
2035         * @param tedSource a TableEntryDescriptor that can split individual
2036         * {@link DataBasketEntry DataBasketEntries} into a table's cells. It will be used for the source table.
2037         * If <code>null</code>  it defaults to a {@link DefaultCatalogItemDBETableEntryDescriptor}.
2038         * @param tedDest a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
2039         * for the destination table. If <code>null</code> and <code>cDest</code> is a {@link Currency} it defaults
2040         * to a {@link DefaultCurrencyItemTED} using <code>cDest</code> to format values. Otherwise, it defaults to
2041         * a {@link DefaultCatalogItemTED}.
2042         * @param dbcsMoveStrategy the strategy to be used when moving items between source and destination. If
2043         * <code>null</code> it defaults to a {@link DBCStrategy} object.
2044         */
2045        public static TwoTableFormSheet create(String sCaption, final DataBasket dbSource, final Catalog cDest,
2046                UIGate uigGate, final Comparator<DataBasketEntry> cmpSource, final Comparator<CatalogItem> cmpDest,
2047                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
2048                DBCStrategy dbcsMoveStrategy) {
2049            return create(sCaption, dbSource, cDest, uigGate, cmpSource, cmpDest, null, tedSource, tedDest,
2050                    dbcsMoveStrategy);
2051        }
2052    
2053        /**
2054         * Create and return a new TwoTableFormSheet where the source is a DataBasket and the destination is a
2055         * Catalog.
2056         *
2057         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
2058         * parameters.</p>
2059         *
2060         * @param sCaption the caption of the FormSheet.
2061         * @param dbSource the source Databasket.
2062         * @param cDest the destination Catalog.
2063         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2064         * {@link #setGate set} before actually using the FormSheet.
2065         */
2066        public static TwoTableFormSheet create(String sCaption, DataBasket dbSource, Catalog cDest,
2067                UIGate uigGate) {
2068            return create(sCaption, dbSource, cDest, uigGate, null, null, null, null, null, null);
2069        }
2070    
2071        // 10. Catalog -> StoringStock
2072    
2073        /**
2074         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
2075         * StoringStock.
2076         *
2077         * @param sCaption the caption of the FormSheet.
2078         * @param cSource the source Catalog.
2079         * @param ssDest the destination Stock.
2080         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2081         * {@link #setGate set} before actually using the FormSheet.
2082         * @param cmpSource a comparator defining the source sorting order. The items to be compared are
2083         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
2084         * natural ordering.
2085         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
2086         * the individual items. If <code>null</code> the ordering will be the natural ordering of the items.
2087         * @param tedSource a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
2088         * for the source table. If <code>null</code> and <code>cSource</code> is a {@link Currency} it defaults to
2089         * a {@link DefaultCurrencyItemTED} using <code>cSource</code> to format values. Otherwise, it defaults to a
2090         * {@link DefaultCatalogItemTED}.
2091         * @param tedDest a TableEntryDescriptor that can split individual {@link StockItem StockItems} into a
2092         * table's cells. It will be used for the destination table. If <code>null</code> it defaults to a
2093         * {@link DefaultStockItemTED}.
2094         * @param csssMoveStrategy the strategy to be used when moving items between source and destination.
2095         * <strong>Attention</strong>: Must not be <code>null</code>!
2096         */
2097        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final StoringStock ssDest,
2098                final DataBasket db, UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<StockItem> cmpDest,
2099                final TableEntryDescriptor tedSource, final TableEntryDescriptor tedDest,
2100                CSSStrategy csssMoveStrategy) { // EXCEPTION : STRATEGY MUST NOT BE NULL!!!
2101            FormSheetContentCreator fscc = new FormSheetContentCreator() {
2102                            private static final long serialVersionUID = 2334337490991839881L;
2103    
2104                            protected void createFormSheetContent(FormSheet fs) {
2105                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
2106    
2107                    JCatalogTable jctSource = new JCatalogTable(cSource, db, cmpSource,
2108                            ((tedSource != null) ? (tedSource) : ((cSource instanceof data.Currency) ?
2109                            (new DefaultCurrencyItemTED((data.Currency)cSource)) : (new DefaultCatalogItemTED()))));
2110                    jctSource.setSelectionObserver(ttfs.m_anLeftSelection);
2111                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jctSource.
2112                            getModel();
2113    
2114                    ttfs.m_atmLeftModel = atmSource;
2115                    ttfs.m_leftTable = jctSource;
2116                    ttfs.m_leftSource = cSource;
2117                    ttfs.m_db = db;
2118    
2119                    JStoringStockTable jsstDest = new JStoringStockTable(ssDest, db, cmpDest,
2120                            ((tedDest != null) ? (tedDest) : (new DefaultStockItemTED())));
2121                    jsstDest.setSelectionObserver(ttfs.m_anRightSelection);
2122                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jsstDest.
2123                            getModel();
2124    
2125                    ttfs.m_atmRightModel = atmDest;
2126                    ttfs.m_rightTable = jsstDest;
2127                    ttfs.m_rightSource = ssDest;
2128    
2129                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
2130                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
2131    
2132                    JPanel jpForm = new JPanel();
2133                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
2134    
2135                    jpForm.add(new JScrollPane(jctSource));
2136    
2137                    jpForm.add(createCentralBox(jbRight, jbLeft, null, ttfs.getStrategy()));
2138    
2139                    jpForm.add(new JScrollPane(jsstDest));
2140    
2141                    if (ttfs.getStrategy().canMoveToDest()) {
2142                        jbRight.addActionListener(new ActionActionListener(fs) {
2143                                                    private static final long serialVersionUID = -4160889060552520441L;
2144    
2145                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
2146                                CatalogItem ci = (CatalogItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
2147    
2148                                if (ci != null) {
2149                                    UIGate uig = ttfs.getGate();
2150                                    if (uig != null) {
2151                                        uig.setNextTransition(((CSSStrategy)ttfs.getStrategy()).
2152                                                getMoveToDestProcess(p, sp, cSource, ssDest, db, ci, ttfs));
2153                                    }
2154                                }
2155                            }
2156                        });
2157                    }
2158    
2159                    if (ttfs.getStrategy().canMoveToSource()) {
2160                        jbLeft.addActionListener(new ActionActionListener(fs) {
2161                                                    private static final long serialVersionUID = 8908544965167249317L;
2162    
2163                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
2164                                StockItem si = (StockItem)atmDest.getRecord(ttfs.m_anRightSelection[0]);
2165    
2166                                if (si != null) {
2167                                    UIGate uig = ttfs.getGate();
2168                                    if (uig != null) {
2169                                        uig.setNextTransition(((CSSStrategy)ttfs.getStrategy()).
2170                                                getMoveToSourceProcess(p, sp, cSource, ssDest, db, si, ttfs));
2171                                    }
2172                                }
2173                            }
2174                        });
2175                    }
2176    
2177                    fs.setComponent(jpForm);
2178                }
2179            };
2180    
2181            return new TwoTableFormSheet(sCaption, fscc, uigGate, csssMoveStrategy);
2182        }
2183    
2184        /**
2185         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
2186         * StoringStock.
2187         *
2188         * <p>Calls the appropriate fully parameterized function, passing <code>null</code> for the missing
2189         * parameters.</p>
2190         *
2191         * @param sCaption the caption of the FormSheet.
2192         * @param cSource the source Catalog.
2193         * @param ssDest the destination Stock.
2194         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2195         * {@link #setGate set} before actually using the FormSheet.
2196         * @param csssMoveStrategy the strategy to be used when moving items between source and destination.
2197         * <strong>Attention</strong>: Must not be <code>null</code>!
2198         */
2199        public static TwoTableFormSheet create(String sCaption, Catalog cSource, StoringStock ssDest,
2200                DataBasket db, UIGate uigGate, CSSStrategy csssMoveStrategy) { // EXCEPTION : STRATEGY MUST NOT BE NULL!!!
2201            return create(sCaption, cSource, ssDest, db, uigGate, null, null, null, null, csssMoveStrategy);
2202        }
2203    
2204        // 11. Catalog -> CountingStock
2205    
2206        /**
2207         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
2208         * CountingStock.
2209         *
2210         * @param sCaption the caption of the FormSheet.
2211         * @param cSource the source Catalog.
2212         * @param ssDest the destination Stock.
2213         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2214         * {@link #setGate set} before actually using the FormSheet.
2215         * @param cmpSource a comparator defining the source sorting order. The items to be compared are
2216         * {@link CatalogItem CatalogItems}. If <code>null</code> the items will be sorted according to their
2217         * natural ordering.
2218         * @param cmpDest a comparator defining the destination sorting order. The objects to be compared will be
2219         * the keys of the individual items. If <code>null</code> the ordering will be the natural ordering of the
2220         * keys.
2221         * @param fShowZeros if false, destination lines containing '0' in the &quot;Count&quot; column will be
2222         * hidden.
2223         * @param tedSource a TableEntryDescriptor that can split CatalogItems into a table's cells. It will be used
2224         * for the source table. If <code>null</code> and <code>cSource</code> is a {@link Currency} it defaults to
2225         * a {@link DefaultCurrencyItemTED} using <code>cSource</code> to format values. Otherwise, it defaults to a
2226         * {@link DefaultCatalogItemTED}.
2227         * @param tedDest a TableEntryDescriptor that can split individual
2228         * {@link data.swing.CountingStockTableModel.Record CountingStockTableModel records} into a table's cells. It will be
2229         * used for the destination table. If <code>null</code> and <code>csDest</code> is a {@link MoneyBag} it
2230         * defaults to a {@link DefaultMoneyBagItemTED} using <code>csDest.getCatalog()</code> to format values.
2231         * Otherwise, it defaults to a {@link DefaultCountingStockItemTED}.
2232         * @param ccssMoveStrategy the strategy to be used when moving items between source and destination. If
2233         * <code>null</code>, defaults to a {@link CCSStrategy} object.
2234         */
2235        public static TwoTableFormSheet create(String sCaption, final Catalog cSource, final CountingStock csDest,
2236                final DataBasket db, UIGate uigGate, final Comparator<CatalogItem> cmpSource, final Comparator<CatalogItem> cmpDest,
2237                final boolean fShowZeros, final TableEntryDescriptor tedSource,
2238                final TableEntryDescriptor tedDest, CCSStrategy ccssMoveStrategy) {
2239            FormSheetContentCreator fscc = new FormSheetContentCreator() {
2240                            private static final long serialVersionUID = 213845399196367982L;
2241    
2242                            protected void createFormSheetContent(FormSheet fs) {
2243                    final TwoTableFormSheet ttfs = (TwoTableFormSheet)fs;
2244    
2245                    final int[] anCounter = {
2246                            1};
2247    
2248                    JCatalogTable jctSource = new JCatalogTable(cSource, db, cmpSource,
2249                            ((tedSource != null) ? (tedSource) : ((cSource instanceof data.Currency) ?
2250                            (new DefaultCurrencyItemTED((data.Currency)cSource)) : (new DefaultCatalogItemTED()))));
2251                    jctSource.setSelectionObserver(ttfs.m_anLeftSelection);
2252                    final util.swing.AbstractTableModel atmSource = (util.swing.AbstractTableModel)jctSource.
2253                            getModel();
2254    
2255                    ttfs.m_atmLeftModel = atmSource;
2256                    ttfs.m_leftTable = jctSource;
2257                    ttfs.m_leftSource = cSource;
2258                    ttfs.m_db = db;
2259    
2260                    JCountingStockTable jcstDest = new JCountingStockTable(csDest, db, cmpDest, fShowZeros,
2261                            ((tedDest != null) ? (tedDest) : ((csDest instanceof MoneyBag) ?
2262                            (new DefaultMoneyBagItemTED((data.Currency)csDest.getCatalog(db))) :
2263                            (new DefaultCountingStockItemTED()))));
2264                    jcstDest.setSelectionObserver(ttfs.m_anRightSelection);
2265                    final util.swing.AbstractTableModel atmDest = (util.swing.AbstractTableModel)jcstDest.
2266                            getModel();
2267    
2268                    ttfs.m_atmRightModel = atmDest;
2269                    ttfs.m_rightTable = jcstDest;
2270                    ttfs.m_rightSource = csDest;
2271    
2272                    JTextField jtf = new JIntInput(anCounter, 1, 1, Integer.MAX_VALUE);
2273    
2274                    JButton jbRight = new JButton(getResourceText(BUTTON_RIGHT));
2275                    JButton jbLeft = new JButton(getResourceText(BUTTON_LEFT));
2276    
2277                    JPanel jpForm = new JPanel();
2278                    jpForm.setLayout(new BoxLayout(jpForm, BoxLayout.X_AXIS));
2279    
2280                    jpForm.add(new JScrollPane(jctSource));
2281    
2282                    jpForm.add(createCentralBox(jbRight, jbLeft, jtf, ttfs.getStrategy()));
2283    
2284                    jpForm.add(new JScrollPane(jcstDest));
2285    
2286                    if (ttfs.getStrategy().canMoveToDest()) {
2287                        jbRight.addActionListener(new ActionActionListener(fs) {
2288                            private static final long serialVersionUID = 8512187040845269111L;
2289    
2290                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
2291                                CatalogItem ci = (CatalogItem)atmSource.getRecord(ttfs.m_anLeftSelection[0]);
2292    
2293                                if (ci != null) {
2294                                    UIGate uig = ttfs.getGate();
2295                                    if (uig != null) {
2296                                        uig.setNextTransition(((CCSStrategy)ttfs.getStrategy()).
2297                                                getMoveToDestProcess(p, sp, cSource, csDest, db, ci, anCounter[0],
2298                                                ttfs));
2299                                    }
2300                                }
2301                            }
2302                        });
2303                    }
2304    
2305                    if (ttfs.getStrategy().canMoveToSource()) {
2306                        jbLeft.addActionListener(new ActionActionListener(fs) {
2307                                                    private static final long serialVersionUID = 4756376603858005686L;
2308    
2309                                                    public void doAction(SaleProcess p, final SalesPoint sp) {
2310                                CountingStockTableModel.Record r = (CountingStockTableModel.Record)atmDest.
2311                                        getRecord(ttfs.m_anRightSelection[0]);
2312    
2313                                if (r != null) {
2314                                    UIGate uig = ttfs.getGate();
2315                                    if (uig != null) {
2316                                        uig.setNextTransition(((CCSStrategy)ttfs.getStrategy()).
2317                                                getMoveToSourceProcess(p, sp, cSource, csDest, db,
2318                                                r.getDescriptor(), anCounter[0], ttfs));
2319                                    }
2320                                }
2321                            }
2322                        });
2323                    }
2324    
2325                    fs.setComponent(jpForm);
2326                }
2327            };
2328    
2329            ccssMoveStrategy = ((ccssMoveStrategy != null) ? (ccssMoveStrategy) : (new CCSStrategy()));
2330    
2331            return new TwoTableFormSheet(sCaption, fscc, uigGate, ccssMoveStrategy);
2332        }
2333    
2334        /**
2335         * Create and return a new TwoTableFormSheet where the source is a Catalog and the destination is a
2336         * CountingStock.
2337         *
2338         * <p>Calls the appropriate fully parameterized function, passing default values (i.e. <code>null</code> or
2339         * false) for the missing parameters.</p>
2340         *
2341         * @param sCaption the caption of the FormSheet.
2342         * @param cSource the source Catalog.
2343         * @param ssDest the destination Stock.
2344         * @param uigGate the Gate at which the FormSheet will be displayed. If this is <code>null</code> it must be
2345         * {@link #setGate set} before actually using the FormSheet.
2346         */
2347        public static TwoTableFormSheet create(String sCaption, Catalog cSource, CountingStock csDest,
2348                DataBasket db, UIGate uigGate) {
2349            return create(sCaption, cSource, csDest, db, uigGate, null, null, false, null, null, null);
2350        }
2351    
2352        // helper routines...
2353    
2354        /**
2355         * Internal helper function creating the central box with the two buttons and the input line.
2356         */
2357        private static final Box createCentralBox(JButton jbRight, JButton jbLeft, JTextField jtf,
2358                MoveStrategy ms) {
2359    
2360            Box b = Box.createVerticalBox();
2361            b.add(Box.createGlue());
2362    
2363            if (jtf != null) {
2364                jtf.setMaximumSize(new java.awt.Dimension(jbRight.getMaximumSize().width * 2 - 1,
2365                        jtf.getMinimumSize().height));
2366                b.add(jtf);
2367            }
2368    
2369            if (ms.canMoveToDest()) {
2370                b.add(jbRight);
2371            }
2372    
2373            if (ms.canMoveToSource()) {
2374                b.add(jbLeft);
2375            }
2376            b.add(Box.createGlue());
2377    
2378            Box bButtonBar = Box.createHorizontalBox();
2379            bButtonBar.add(Box.createGlue());
2380            bButtonBar.add(b);
2381            bButtonBar.add(Box.createGlue());
2382    
2383            return bButtonBar;
2384        }
2385    
2386        // resource stuff...
2387    
2388        /**
2389         * Resource identifier of the '<<' button's label. Is &quot;2TableFormSheet.button.left&quot;
2390         */
2391        public static final String BUTTON_LEFT = "2TableFormSheet.button.left";
2392    
2393        /**
2394         * Resource identifier of the '>>' button's label. Is &quot;2TableFormSheet.button.right&quot;
2395         */
2396        public static final String BUTTON_RIGHT = "2TableFormSheet.button.right";
2397    
2398        /**
2399         * The resource bundle that knows the buttons' labels.
2400         */
2401        private static ResourceBundle s_rbTexts = new ListResourceBundle() {
2402            protected Object[][] getContents() {
2403                return s_aaoContents;
2404            }
2405    
2406            private final Object[][] s_aaoContents = {
2407                    {
2408                    BUTTON_RIGHT, ">>"}
2409                    , {
2410                    BUTTON_LEFT, "<<"}
2411            };
2412        };
2413    
2414        /**
2415         * Monitor synchronizing access to the resource.
2416         */
2417        private static final Object s_oResourceLock = new Object();
2418    
2419        /**
2420         * Set the resource bundle that knows the labels for the buttons.
2421         *
2422         * <p>The resource must contain Strings for all items needed by TwoTableFormSheet, specifically
2423         * {@link #BUTTON_LEFT} and {@link #BUTTON_RIGHT}.</p>
2424         */
2425        public static final void setTextResource(ResourceBundle rb) {
2426            synchronized (s_oResourceLock) {
2427                s_rbTexts = rb;
2428            }
2429        }
2430    
2431        /**
2432         * Get a String from the global TwoTableFormSheet resource bundle.
2433         *
2434         * @param sKey the key for which to find the text.
2435         */
2436        public static final String getResourceText(String sKey) {
2437            synchronized (s_oResourceLock) {
2438                return s_rbTexts.getString(sKey);
2439            }
2440        }
2441    }