001package jmri.jmrit.beantable;
002
003import java.awt.BorderLayout;
004import java.awt.event.ActionEvent;
005import java.util.ArrayList;
006
007import javax.annotation.Nonnull;
008import javax.swing.*;
009import javax.swing.event.*;
010import javax.swing.table.*;
011
012import jmri.*;
013import jmri.swing.RowSorterUtil;
014import jmri.util.AlphanumComparator;
015
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019abstract public class AbstractTableTabAction<E extends NamedBean> extends AbstractTableAction<E> {
020
021    protected JPanel dataPanel;
022    protected JTabbedPane dataTabs;
023
024    protected boolean init = false;
025
026    public AbstractTableTabAction(String s) {
027        super(s);
028    }
029
030    @Override
031    protected void createModel() {
032        dataPanel = new JPanel();
033        dataTabs = new JTabbedPane();
034        dataPanel.setLayout(new BorderLayout());
035        Manager<E> mgr = getManager();
036        if (mgr instanceof jmri.managers.AbstractProxyManager) {
037            // build the list, with default at start and internal at end (if present)
038            jmri.managers.AbstractProxyManager<E> proxy = (jmri.managers.AbstractProxyManager<E>) mgr;
039
040            tabbedTableArray.add(new TabbedTableItem<>(Bundle.getMessage("All"), true, mgr, getNewTableAction("All"))); // NOI18N
041
042            proxy.getDisplayOrderManagerList().stream().map(manager -> {
043                String manuName = manager.getMemo().getUserName();
044                TabbedTableItem<E> itemModel = new TabbedTableItem<>(manuName, true, manager, getNewTableAction(manuName)); // connection name to display in Tab
045                return itemModel;
046            }).forEachOrdered(itemModel -> {
047                tabbedTableArray.add(itemModel);
048            });
049
050        } else {
051            Manager<E> man = getManager();
052            String manuName = ( man!=null ? man.getMemo().getUserName() : "Unknown Manager");
053            tabbedTableArray.add(new TabbedTableItem<E>(manuName, true, getManager(), getNewTableAction(manuName)));
054        }
055        for (int x = 0; x < tabbedTableArray.size(); x++) {
056            AbstractTableAction<E> table = tabbedTableArray.get(x).getAAClass();
057            table.addToPanel(this);
058            dataTabs.addTab(tabbedTableArray.get(x).getItemString(), null, tabbedTableArray.get(x).getPanel(), null);
059        }
060        dataTabs.addChangeListener((ChangeEvent evt) -> {
061            setMenuBar(f);
062        });
063        dataPanel.add(dataTabs, BorderLayout.CENTER);
064        init = true;
065    }
066
067    @Override
068    abstract protected Manager<E> getManager();
069
070    abstract protected AbstractTableAction<E> getNewTableAction(String choice);
071
072    @Override
073    public JPanel getPanel() {
074        if (!init) {
075            createModel();
076        }
077        return dataPanel;
078    }
079
080    protected ArrayList<TabbedTableItem<E>> tabbedTableArray = new ArrayList<>();
081
082    @Override
083    protected void setTitle() {
084        //atf.setTitle("multiple sensors");
085    }
086
087    @Override
088    abstract protected String helpTarget();
089
090    @Override
091    protected void addPressed(ActionEvent e) {
092        log.warn("This should not have happened");
093    }
094
095    @Override
096    public void addToFrame(BeanTableFrame<E> f) {
097        try {
098            TabbedTableItem<E> table = tabbedTableArray.get(dataTabs.getSelectedIndex());
099            if (table != null) {
100                table.getAAClass().addToFrame(f);
101            }
102        } catch (ArrayIndexOutOfBoundsException ex) {
103            log.error("{} in add to Frame {} {}", ex.toString(), dataTabs.getSelectedIndex(), dataTabs.getSelectedComponent());
104        }
105    }
106
107    @Override
108    public void setMenuBar(BeanTableFrame<E> f) {
109        try {
110            tabbedTableArray.get(dataTabs.getSelectedIndex()).getAAClass().setMenuBar(f);
111        } catch (ArrayIndexOutOfBoundsException ex) {
112            log.error("{} in add to Menu {} {}", ex.toString(), dataTabs.getSelectedIndex(), dataTabs.getSelectedComponent());
113        }
114    }
115
116    public void addToBottomBox(JComponent c, String str) {
117        tabbedTableArray.forEach((table) -> {
118            String item = table.getItemString();
119            if (item != null && item.equals(str)) {
120                table.addToBottomBox(c);
121            }
122        });
123    }
124
125    @Override
126    public void print(javax.swing.JTable.PrintMode mode, java.text.MessageFormat headerFormat, java.text.MessageFormat footerFormat) {
127        try {
128            tabbedTableArray.get(dataTabs.getSelectedIndex()).getDataTable().print(mode, headerFormat, footerFormat);
129        } catch (java.awt.print.PrinterException e1) {
130            log.warn("error printing", e1);
131        } catch (NullPointerException ex) {
132            log.error("Trying to print returned a NPE error");
133        }
134    }
135
136    @Override
137    public void dispose() {
138        for (int x = 0; x < tabbedTableArray.size(); x++) {
139            tabbedTableArray.get(x).dispose();
140        }
141        super.dispose();
142    }
143
144    static protected class TabbedTableItem<E extends NamedBean> extends AbstractTableAction.TableItem<E> {  // E comes from the parent
145
146        final String itemText;
147
148        private JScrollPane dataScroll;
149        final Box bottomBox;
150        private boolean addToFrameRan = false;
151        final Manager<E> manager;
152
153        private int bottomBoxIndex; // index to insert extra stuff
154        static final int BOTTOM_STRUT_WIDTH = 20;
155
156        private boolean standardModel = true;
157
158        final JPanel dataPanel = new JPanel();
159
160        @SuppressWarnings("unchecked")
161        public TabbedTableItem(String choice, boolean stdModel, Manager<E> manager, @Nonnull AbstractTableAction<E> tableAction) {
162
163            super(tableAction);
164
165            itemText = choice;
166            standardModel = stdModel;
167            this.manager = manager;
168
169            //If a panel model is used, it should really add to the bottom box
170            //but it can be done this way if required.
171            bottomBox = Box.createHorizontalBox();
172            bottomBox.add(Box.createHorizontalGlue());
173            bottomBoxIndex = 0;
174            dataPanel.setLayout(new BorderLayout());
175            if (stdModel) {
176                createDataModel();
177            } else {
178                addPanelModel();
179            }
180        }
181
182        @SuppressWarnings("unchecked")
183        final void createDataModel() {
184            tableAction.setManager(manager);
185            dataModel = tableAction.getTableDataModel();
186            TableRowSorter<BeanTableDataModel<E>> sorter = new TableRowSorter<>(dataModel);
187            dataTable = dataModel.makeJTable(dataModel.getMasterClassName() + ":" + getItemString(), dataModel, sorter);
188            dataScroll = new JScrollPane(dataTable);
189
190            RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.SYSNAMECOL, SortOrder.ASCENDING);
191
192            sorter.setComparator(BeanTableDataModel.USERNAMECOL, new AlphanumComparator());
193            RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.USERNAMECOL, SortOrder.ASCENDING);
194
195            dataModel.configureTable(dataTable);
196            tableAction.configureTable(dataTable);
197
198            java.awt.Dimension dataTableSize = dataTable.getPreferredSize();
199            // width is right, but if table is empty, it's not high
200            // enough to reserve much space.
201            dataTableSize.height = Math.max(dataTableSize.height, 400);
202            dataScroll.getViewport().setPreferredSize(dataTableSize);
203
204            // set preferred scrolling options
205            dataScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
206            dataScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
207
208            //dataPanel.setLayout(new BoxLayout(dataPanel, BoxLayout.Y_AXIS));
209            dataPanel.add(dataScroll, BorderLayout.CENTER);
210
211            dataPanel.add(bottomBox, BorderLayout.SOUTH);
212
213            includeAddButton(tableAction.includeAddButton());
214
215            includePropertyCheckBox();
216
217        }
218
219        final void addPanelModel() {
220            dataPanel.add(tableAction.getPanel(), BorderLayout.CENTER);
221            dataPanel.add(bottomBox, BorderLayout.SOUTH);
222        }
223
224        public boolean getStandardTableModel() {
225            return standardModel;
226        }
227
228        public String getItemString() {
229            return itemText;
230        }
231
232        public JPanel getPanel() {
233            return dataPanel;
234        }
235
236        public boolean getAdditionsToFrameDone() {
237            return addToFrameRan;
238        }
239
240        public void setAddToFrameRan() {
241            addToFrameRan = true;
242        }
243
244        
245
246        @Override
247        protected void addToBottomBox(JComponent comp) {
248            try {
249                bottomBox.add(Box.createHorizontalStrut(BOTTOM_STRUT_WIDTH), bottomBoxIndex);
250                ++bottomBoxIndex;
251                bottomBox.add(comp, bottomBoxIndex);
252                ++bottomBoxIndex;
253            } catch (java.lang.IllegalArgumentException ex) {
254                log.error("Could not add to bottom box.", ex);
255            }
256        }
257
258        @Override
259        protected void dispose() {
260            super.dispose();
261            dataScroll = null;
262        }
263    }
264
265    private final static Logger log = LoggerFactory.getLogger(AbstractTableTabAction.class);
266
267}