001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.awt.Dimension;
008import java.awt.GridBagLayout;
009import java.awt.event.ActionEvent;
010import java.awt.event.ActionListener;
011import java.util.EventObject;
012import java.util.concurrent.CopyOnWriteArrayList;
013
014import javax.swing.AbstractAction;
015import javax.swing.ActionMap;
016import javax.swing.JCheckBox;
017import javax.swing.JPanel;
018import javax.swing.JTable;
019import javax.swing.event.CellEditorListener;
020import javax.swing.event.ChangeEvent;
021import javax.swing.table.TableCellEditor;
022import javax.swing.table.TableCellRenderer;
023
024import 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 */
037class 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        @Override
043        public void actionPerformed(ActionEvent e) {
044            fireEditingStopped();
045        }
046    };
047
048    public ActionFlagsTableCell() {
049        super();
050        listeners = new CopyOnWriteArrayList<CellEditorListener>();
051
052        checkBoxes[0] = new JCheckBox(tr("Upload"));
053        checkBoxes[1] = new JCheckBox(tr("Save"));
054        setLayout(new GridBagLayout());
055
056        ActionMap am = getActionMap();
057        for (final JCheckBox b : checkBoxes) {
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                @Override
063                public void actionPerformed(ActionEvent e) {
064                    b.setSelected(!b.isSelected());
065                    fireEditingStopped();
066                }
067            });
068        }
069
070        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>"));
071    }
072
073    protected void updateCheckboxes(Object v) {
074        if (checkBoxes[0] != null && checkBoxes[1] != null) {
075            boolean[] values;
076            if(v instanceof SaveLayerInfo) {
077                values = new boolean[2];
078                values[0] = ((SaveLayerInfo) v).isDoUploadToServer();
079                values[1] = ((SaveLayerInfo) v).isDoSaveToFile();
080            } else {
081                values = (boolean[]) v;
082            }
083            checkBoxes[0].setSelected(values[0]);
084            checkBoxes[1].setSelected(values[1]);
085        }
086    }
087
088    @Override
089    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
090        updateCheckboxes(value);
091        return this;
092    }
093
094    @Override
095    public void addCellEditorListener(CellEditorListener l) {
096        if (l != null) {
097            listeners.addIfAbsent(l);
098        }
099    }
100
101    protected void fireEditingCanceled() {
102        for (CellEditorListener l: listeners) {
103            l.editingCanceled(new ChangeEvent(this));
104        }
105    }
106
107    protected void fireEditingStopped() {
108        for (CellEditorListener l: listeners) {
109            l.editingStopped(new ChangeEvent(this));
110        }
111    }
112
113    @Override
114    public void cancelCellEditing() {
115        fireEditingCanceled();
116    }
117
118    @Override
119    public Object getCellEditorValue() {
120        boolean[] values = new boolean[2];
121        values[0] = checkBoxes[0].isSelected();
122        values[1] = checkBoxes[1].isSelected();
123        return values;
124    }
125
126    @Override
127    public boolean isCellEditable(EventObject anEvent) {
128        return true;
129    }
130
131    @Override
132    public void removeCellEditorListener(CellEditorListener l) {
133        listeners.remove(l);
134    }
135
136    @Override
137    public boolean shouldSelectCell(EventObject anEvent) {
138        return true;
139    }
140
141    @Override
142    public boolean stopCellEditing() {
143        fireEditingStopped();
144        return true;
145    }
146
147    @Override
148    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
149        updateCheckboxes(value);
150        return this;
151    }
152}