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