001package icy.gui.inspector;
002
003import icy.gui.component.AbstractRoisPanel.BaseColumnInfo;
004import icy.gui.component.button.IcyButton;
005import icy.preferences.XMLPreferences;
006import icy.resource.ResourceUtil;
007import icy.resource.icon.IcyIcon;
008import icy.roi.ROIDescriptor;
009import icy.roi.ROIUtil;
010
011import java.awt.BorderLayout;
012import java.awt.GridBagConstraints;
013import java.awt.GridBagLayout;
014import java.awt.Insets;
015import java.awt.event.ActionEvent;
016import java.awt.event.ActionListener;
017import java.util.ArrayList;
018import java.util.Collections;
019import java.util.List;
020import java.util.Set;
021
022import javax.swing.JLabel;
023import javax.swing.JPanel;
024import javax.swing.JScrollPane;
025import javax.swing.JSplitPane;
026import javax.swing.JTable;
027import javax.swing.ListSelectionModel;
028import javax.swing.table.AbstractTableModel;
029import javax.swing.table.TableColumn;
030import javax.swing.table.TableColumnModel;
031
032public class RoiSettingPanel extends JPanel implements ActionListener
033{
034    // GUI
035    private JScrollPane scrollPaneView;
036    private JScrollPane scrollPaneExport;
037    private JTable tableView;
038    private JTable tableExport;
039    private JPanel panelExportTop;
040    private JLabel lblColumnSelectionFor;
041    private JLabel lblNewLabel;
042    private IcyButton upViewBtn;
043    private IcyButton downViewBtn;
044    private IcyButton upExportBtn;
045    private IcyButton downExportBtn;
046
047    // internals
048    List<BaseColumnInfo> idsView;
049    List<BaseColumnInfo> idsExport;
050
051    private AbstractTableModel viewModel;
052    private AbstractTableModel exportModel;
053
054    private final XMLPreferences prefView;
055    private final XMLPreferences prefExport;
056
057    /**
058     * Create the panel.
059     * 
060     * @param exportPreferences
061     */
062    public RoiSettingPanel(XMLPreferences viewPreferences, XMLPreferences exportPreferences)
063    {
064        super();
065
066        prefView = viewPreferences;
067        prefExport = exportPreferences;
068
069        final Set<ROIDescriptor> descriptors = ROIUtil.getROIDescriptors().keySet();
070
071        idsView = new ArrayList<BaseColumnInfo>();
072        idsExport = new ArrayList<BaseColumnInfo>();
073
074        // build view and export lists
075        for (ROIDescriptor descriptor : descriptors)
076        {
077            idsView.add(new BaseColumnInfo(descriptor, prefView, false));
078            idsExport.add(new BaseColumnInfo(descriptor, prefExport, true));
079        }
080
081        sortLists();
082
083        initialize();
084
085        viewModel = new AbstractTableModel()
086        {
087            @Override
088            public int getColumnCount()
089            {
090                return 2;
091            }
092
093            @Override
094            public Class<?> getColumnClass(int columnIndex)
095            {
096                switch (columnIndex)
097                {
098                    case 0:
099                        // name
100                        return String.class;
101
102                    case 1:
103                        // visibility
104                        return Boolean.class;
105                }
106
107                return String.class;
108            }
109
110            @Override
111            public String getColumnName(int column)
112            {
113                switch (column)
114                {
115                    case 0:
116                        return "Column name";
117
118                    case 1:
119                        return "Visible";
120                }
121
122                return "";
123            }
124
125            @Override
126            public int getRowCount()
127            {
128                return idsView.size();
129            }
130
131            @Override
132            public Object getValueAt(int rowIndex, int columnIndex)
133            {
134                switch (columnIndex)
135                {
136                    case 0:
137                        // name
138                        return idsView.get(rowIndex).descriptor.getName();
139
140                    case 1:
141                        // visibility
142                        return Boolean.valueOf(idsView.get(rowIndex).visible);
143                }
144
145                return null;
146            }
147
148            @Override
149            public boolean isCellEditable(int rowIndex, int columnIndex)
150            {
151                return (columnIndex == 1);
152            }
153
154            @Override
155            public void setValueAt(Object aValue, int rowIndex, int columnIndex)
156            {
157                // visibility
158                if (columnIndex == 1)
159                    idsView.get(rowIndex).visible = ((Boolean) aValue).booleanValue();
160            }
161        };
162
163        exportModel = new AbstractTableModel()
164        {
165            @Override
166            public int getColumnCount()
167            {
168                return 2;
169            }
170
171            @Override
172            public Class<?> getColumnClass(int columnIndex)
173            {
174                switch (columnIndex)
175                {
176                    case 0:
177                        // name
178                        return String.class;
179
180                    case 1:
181                        // visibility
182                        return Boolean.class;
183                }
184
185                return String.class;
186            }
187
188            @Override
189            public String getColumnName(int column)
190            {
191                switch (column)
192                {
193                    case 0:
194                        return "Column name";
195
196                    case 1:
197                        return "Visible";
198                }
199
200                return "";
201            }
202
203            @Override
204            public int getRowCount()
205            {
206                return idsExport.size();
207            }
208
209            @Override
210            public Object getValueAt(int rowIndex, int columnIndex)
211            {
212                switch (columnIndex)
213                {
214                    case 0:
215                        // name
216                        return idsExport.get(rowIndex).descriptor.getName();
217
218                    case 1:
219                        // visibility
220                        return Boolean.valueOf(idsExport.get(rowIndex).visible);
221                }
222
223                return null;
224            }
225
226            @Override
227            public boolean isCellEditable(int rowIndex, int columnIndex)
228            {
229                return (columnIndex == 1);
230            }
231
232            @Override
233            public void setValueAt(Object aValue, int rowIndex, int columnIndex)
234            {
235                // visibility
236                if (columnIndex == 1)
237                    idsExport.get(rowIndex).visible = ((Boolean) aValue).booleanValue();
238            }
239        };
240
241        TableColumnModel columnModel;
242        TableColumn column;
243
244        tableView.setModel(viewModel);
245        columnModel = tableView.getColumnModel();
246
247        column = columnModel.getColumn(0);
248        column.setPreferredWidth(150);
249        column.setMinWidth(80);
250        column = columnModel.getColumn(1);
251        column.setResizable(false);
252        column.setPreferredWidth(50);
253        column.setMaxWidth(50);
254        column.setMinWidth(30);
255
256        tableExport.setModel(exportModel);
257        columnModel = tableExport.getColumnModel();
258
259        column = columnModel.getColumn(0);
260        column.setPreferredWidth(150);
261        column.setMinWidth(80);
262        column = columnModel.getColumn(1);
263        column.setResizable(false);
264        column.setPreferredWidth(50);
265        column.setMaxWidth(50);
266        column.setMinWidth(30);
267
268        upViewBtn.addActionListener(this);
269        downViewBtn.addActionListener(this);
270        upExportBtn.addActionListener(this);
271        downExportBtn.addActionListener(this);
272    }
273
274    private void initialize()
275    {
276        setLayout(new BorderLayout(0, 0));
277
278        JSplitPane splitPane = new JSplitPane();
279        splitPane.setResizeWeight(0.5);
280        add(splitPane, BorderLayout.CENTER);
281
282        JPanel panelView = new JPanel();
283        splitPane.setLeftComponent(panelView);
284        panelView.setLayout(new BorderLayout(0, 0));
285
286        scrollPaneView = new JScrollPane();
287        panelView.add(scrollPaneView, BorderLayout.CENTER);
288
289        tableView = new JTable();
290        tableView.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
291        tableView.setRowSelectionAllowed(true);
292        scrollPaneView.setViewportView(tableView);
293
294        JPanel panelViewTop = new JPanel();
295        panelView.add(panelViewTop, BorderLayout.NORTH);
296        GridBagLayout gbl_panelViewTop = new GridBagLayout();
297        gbl_panelViewTop.columnWidths = new int[] {0, 0, 0, 0};
298        gbl_panelViewTop.rowHeights = new int[] {14, 0};
299        gbl_panelViewTop.columnWeights = new double[] {1.0, 0.0, 0.0, Double.MIN_VALUE};
300        gbl_panelViewTop.rowWeights = new double[] {0.0, Double.MIN_VALUE};
301        panelViewTop.setLayout(gbl_panelViewTop);
302
303        lblColumnSelectionFor = new JLabel("Columns to display");
304        GridBagConstraints gbc_lblColumnSelectionFor = new GridBagConstraints();
305        gbc_lblColumnSelectionFor.insets = new Insets(0, 0, 0, 5);
306        gbc_lblColumnSelectionFor.gridx = 0;
307        gbc_lblColumnSelectionFor.gridy = 0;
308        panelViewTop.add(lblColumnSelectionFor, gbc_lblColumnSelectionFor);
309
310        upViewBtn = new IcyButton(new IcyIcon(ResourceUtil.ICON_ARROW_UP));
311        upViewBtn.setToolTipText("Change order of selected column(s)");
312        upViewBtn.setFlat(true);
313        GridBagConstraints gbc_upViewBtn = new GridBagConstraints();
314        gbc_upViewBtn.insets = new Insets(0, 0, 0, 5);
315        gbc_upViewBtn.gridx = 1;
316        gbc_upViewBtn.gridy = 0;
317        panelViewTop.add(upViewBtn, gbc_upViewBtn);
318
319        downViewBtn = new IcyButton(new IcyIcon(ResourceUtil.ICON_ARROW_DOWN));
320        downViewBtn.setToolTipText("Change order of selected column(s)");
321        downViewBtn.setFlat(true);
322        GridBagConstraints gbc_downViewBtn = new GridBagConstraints();
323        gbc_downViewBtn.gridx = 2;
324        gbc_downViewBtn.gridy = 0;
325        panelViewTop.add(downViewBtn, gbc_downViewBtn);
326
327        JPanel panelExport = new JPanel();
328        splitPane.setRightComponent(panelExport);
329        panelExport.setLayout(new BorderLayout(0, 0));
330
331        scrollPaneExport = new JScrollPane();
332        panelExport.add(scrollPaneExport, BorderLayout.CENTER);
333
334        tableExport = new JTable();
335        tableExport.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
336        tableExport.setRowSelectionAllowed(true);
337        scrollPaneExport.setViewportView(tableExport);
338
339        panelExportTop = new JPanel();
340        panelExport.add(panelExportTop, BorderLayout.NORTH);
341        GridBagLayout gbl_panelExportTop = new GridBagLayout();
342        gbl_panelExportTop.columnWidths = new int[] {0, 0, 0, 0};
343        gbl_panelExportTop.rowHeights = new int[] {14, 0};
344        gbl_panelExportTop.columnWeights = new double[] {1.0, 0.0, 0.0, Double.MIN_VALUE};
345        gbl_panelExportTop.rowWeights = new double[] {0.0, Double.MIN_VALUE};
346        panelExportTop.setLayout(gbl_panelExportTop);
347
348        lblNewLabel = new JLabel("Columns to export (XLS or CSV)");
349        GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
350        gbc_lblNewLabel.insets = new Insets(0, 0, 0, 5);
351        gbc_lblNewLabel.gridx = 0;
352        gbc_lblNewLabel.gridy = 0;
353        panelExportTop.add(lblNewLabel, gbc_lblNewLabel);
354
355        upExportBtn = new IcyButton(new IcyIcon(ResourceUtil.ICON_ARROW_UP));
356        upExportBtn.setToolTipText("Change order of selected column(s)");
357        upExportBtn.setFlat(true);
358        GridBagConstraints gbc_upExportBtn = new GridBagConstraints();
359        gbc_upExportBtn.insets = new Insets(0, 0, 0, 5);
360        gbc_upExportBtn.gridx = 1;
361        gbc_upExportBtn.gridy = 0;
362        panelExportTop.add(upExportBtn, gbc_upExportBtn);
363
364        downExportBtn = new IcyButton(new IcyIcon(ResourceUtil.ICON_ARROW_DOWN));
365        downExportBtn.setToolTipText("Change order of selected column(s)");
366        downExportBtn.setFlat(true);
367        GridBagConstraints gbc_downExportBtn = new GridBagConstraints();
368        gbc_downExportBtn.gridx = 2;
369        gbc_downExportBtn.gridy = 0;
370        panelExportTop.add(downExportBtn, gbc_downExportBtn);
371    }
372
373    void fixOrders()
374    {
375        int order;
376
377        order = 0;
378        for (BaseColumnInfo columnInfo : idsView)
379            columnInfo.order = order++;
380        order = 0;
381        for (BaseColumnInfo columnInfo : idsExport)
382            columnInfo.order = order++;
383    }
384
385    /**
386     * Sort lists on their order
387     */
388    void sortLists()
389    {
390        // sort tables
391        Collections.sort(idsView);
392        Collections.sort(idsExport);
393        // and fix orders
394        fixOrders();
395    }
396
397    /**
398     * Save columns setting to preferences
399     */
400    public void save()
401    {
402        sortLists();
403
404        for (BaseColumnInfo columnInfo : idsView)
405            columnInfo.save(prefView);
406        for (BaseColumnInfo columnInfo : idsExport)
407            columnInfo.save(prefExport);
408    }
409
410    List<BaseColumnInfo> getSelected(JTable table, List<BaseColumnInfo> columnInfos)
411    {
412        final List<BaseColumnInfo> result = new ArrayList<BaseColumnInfo>();
413        final int[] selected = table.getSelectedRows();
414
415        for (int index : selected)
416            result.add(columnInfos.get(index));
417
418        return result;
419    }
420
421    void restoreSelected(JTable table, List<BaseColumnInfo> columnInfos, List<BaseColumnInfo> selected)
422    {
423        final ListSelectionModel selectionModel = table.getSelectionModel();
424
425        selectionModel.setValueIsAdjusting(true);
426        try
427        {
428            selectionModel.clearSelection();
429
430            for (BaseColumnInfo bci : selected)
431            {
432                final int index = columnInfos.indexOf(bci);
433                if (index >= 0)
434                    selectionModel.addSelectionInterval(index, index);
435            }
436        }
437        finally
438        {
439            selectionModel.setValueIsAdjusting(false);
440        }
441    }
442
443    @Override
444    public void actionPerformed(ActionEvent e)
445    {
446        final Object source = e.getSource();
447        final JTable table;
448        final List<BaseColumnInfo> columnInfos;
449        final int v;
450
451        if ((source == upViewBtn) || (source == downViewBtn))
452        {
453            table = tableView;
454            columnInfos = idsView;
455        }
456        else if ((source == upExportBtn) || (source == downExportBtn))
457        {
458            table = tableExport;
459            columnInfos = idsExport;
460        }
461        else
462        {
463            table = null;
464            columnInfos = null;
465        }
466
467        if ((source == upViewBtn) || (source == upExportBtn))
468            v = -1;
469        else if ((source == downViewBtn) || (source == downExportBtn))
470            v = 1;
471        else
472            v = 0;
473
474        if ((table != null) && (columnInfos != null))
475        {
476            final List<BaseColumnInfo> selected = getSelected(table, columnInfos);
477
478            // update order of selected area
479            for (BaseColumnInfo bci : selected)
480                bci.order = bci.order + v;
481
482            if (v == -1)
483            {
484                // change order of previous item
485                final int firstSelected = table.getSelectionModel().getMinSelectionIndex();
486                if ((firstSelected != -1) && (firstSelected > 0))
487                    columnInfos.get(firstSelected - 1).order += table.getSelectedRowCount();
488            }
489            else
490            {
491                // change order of next item
492                final int lastSelected = table.getSelectionModel().getMaxSelectionIndex();
493                if ((lastSelected != -1) && (lastSelected < (columnInfos.size() - 1)))
494                    columnInfos.get(lastSelected + 1).order -= table.getSelectedRowCount();
495            }
496
497            // sort lists
498            sortLists();
499
500            restoreSelected(table, columnInfos, selected);
501            // refresh table data
502            viewModel.fireTableRowsUpdated(0, idsView.size() - 1);
503            exportModel.fireTableRowsUpdated(0, idsExport.size() - 1);
504        }
505    }
506}