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