001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.io;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.awt.Component;
007    import java.awt.Dimension;
008    import java.awt.GridBagLayout;
009    import java.awt.event.ActionEvent;
010    import java.awt.event.ActionListener;
011    import java.util.EventObject;
012    import java.util.concurrent.CopyOnWriteArrayList;
013    
014    import javax.swing.AbstractAction;
015    import javax.swing.ActionMap;
016    import javax.swing.JCheckBox;
017    import javax.swing.JPanel;
018    import javax.swing.JTable;
019    import javax.swing.event.CellEditorListener;
020    import javax.swing.event.ChangeEvent;
021    import javax.swing.table.TableCellEditor;
022    import javax.swing.table.TableCellRenderer;
023    
024    import org.openstreetmap.josm.tools.GBC;
025    
026    /**
027     * This class creates a table cell that features two checkboxes, Upload and Save. It
028     * handles everything on its own, in other words it renders itself and also functions
029     * as editor so the checkboxes may be set by the user.
030     * 
031     * Intended usage is like this:
032     * ActionFlagsTableCell aftc = new ActionFlagsTableCell();
033     * col = new TableColumn(0);
034     * col.setCellRenderer(aftc);
035     * col.setCellEditor(aftc);
036     */
037    class ActionFlagsTableCell extends JPanel implements TableCellRenderer, TableCellEditor {
038        protected final JCheckBox[] checkBoxes = new JCheckBox[2];
039        private CopyOnWriteArrayList<CellEditorListener> listeners;
040    
041        private ActionListener al = new ActionListener() {
042            public void actionPerformed(ActionEvent e) {
043                fireEditingStopped();
044            }
045        };
046    
047        public ActionFlagsTableCell() {
048            super();
049            listeners = new CopyOnWriteArrayList<CellEditorListener>();
050    
051            checkBoxes[0] = new JCheckBox(tr("Upload"));
052            checkBoxes[1] = new JCheckBox(tr("Save"));
053            setLayout(new GridBagLayout());
054    
055            ActionMap am = getActionMap();
056            for(int i=0; i<checkBoxes.length; i++) {
057                final JCheckBox b = checkBoxes[i];
058                add(b, GBC.eol().fill(GBC.HORIZONTAL));
059                b.setPreferredSize(new Dimension(b.getPreferredSize().width, 19));
060                b.addActionListener(al);
061                am.put(b.getText(), new AbstractAction() {
062                    public void actionPerformed(ActionEvent e) {
063                        b.setSelected(!b.isSelected());
064                        fireEditingStopped();
065                    }
066                });
067            }
068    
069            setToolTipText(tr("<html>Select which actions to perform for this layer, if you click the leftmost button.<br/>Check \"upload\" to upload the changes to the OSM server.<br/>Check \"Save\" to save the layer to the file specified on the left.</html>"));
070        }
071    
072        protected void updateCheckboxes(Object v) {
073            if (checkBoxes[0] != null && checkBoxes[1] != null) {
074                boolean[] values;
075                if(v instanceof SaveLayerInfo) {
076                    values = new boolean[2];
077                    values[0] = ((SaveLayerInfo) v).isDoUploadToServer();
078                    values[1] = ((SaveLayerInfo) v).isDoSaveToFile();
079                } else {
080                    values = (boolean[]) v;
081                }
082                checkBoxes[0].setSelected(values[0]);
083                checkBoxes[1].setSelected(values[1]);
084            }
085        }
086    
087        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
088            updateCheckboxes(value);
089            return this;
090        }
091    
092        public void addCellEditorListener(CellEditorListener l) {
093            if (l != null) {
094                listeners.addIfAbsent(l);
095            }
096        }
097    
098        protected void fireEditingCanceled() {
099            for (CellEditorListener l: listeners) {
100                l.editingCanceled(new ChangeEvent(this));
101            }
102        }
103    
104        protected void fireEditingStopped() {
105            for (CellEditorListener l: listeners) {
106                l.editingStopped(new ChangeEvent(this));
107            }
108        }
109    
110        public void cancelCellEditing() {
111            fireEditingCanceled();
112        }
113    
114        public Object getCellEditorValue() {
115            boolean[] values = new boolean[2];
116            values[0] = checkBoxes[0].isSelected();
117            values[1] = checkBoxes[1].isSelected();
118            return values;
119        }
120    
121        public boolean isCellEditable(EventObject anEvent) {
122            return true;
123        }
124    
125        public void removeCellEditorListener(CellEditorListener l) {
126            listeners.remove(l);
127        }
128    
129        public boolean shouldSelectCell(EventObject anEvent) {
130            return true;
131        }
132    
133        public boolean stopCellEditing() {
134            fireEditingStopped();
135            return true;
136        }
137    
138        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
139            updateCheckboxes(value);
140            return this;
141        }
142    }