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;
012
013import javax.swing.AbstractAction;
014import javax.swing.ActionMap;
015import javax.swing.JCheckBox;
016import javax.swing.JPanel;
017import javax.swing.JTable;
018import javax.swing.event.CellEditorListener;
019import javax.swing.table.TableCellEditor;
020import javax.swing.table.TableCellRenderer;
021
022import org.openstreetmap.josm.gui.util.CellEditorSupport;
023import org.openstreetmap.josm.tools.GBC;
024
025/**
026 * This class creates a table cell that features two checkboxes, Upload and Save. It
027 * handles everything on its own, in other words it renders itself and also functions
028 * as editor so the checkboxes may be set by the user.
029 *
030 * Intended usage is like this:
031 * <code>
032 * <br>ActionFlagsTableCell aftc = new ActionFlagsTableCell();
033 * <br>col = new TableColumn(0);
034 * <br>col.setCellRenderer(aftc);
035 * <br>col.setCellEditor(aftc);
036 * </code>
037 */
038class ActionFlagsTableCell extends JPanel implements TableCellRenderer, TableCellEditor {
039    private final JCheckBox[] checkBoxes = new JCheckBox[2];
040    private final transient CellEditorSupport cellEditorSupport = new CellEditorSupport(this);
041
042    private final transient ActionListener al = new ActionListener() {
043        @Override
044        public void actionPerformed(ActionEvent e) {
045            cellEditorSupport.fireEditingStopped();
046        }
047    };
048
049    /**
050     * Constructs a new {@code ActionFlagsTableCell}.
051     */
052    ActionFlagsTableCell() {
053        checkBoxes[0] = new JCheckBox(tr("Upload"));
054        checkBoxes[1] = new JCheckBox(tr("Save"));
055        setLayout(new GridBagLayout());
056
057        ActionMap am = getActionMap();
058        for (final JCheckBox b : checkBoxes) {
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                    cellEditorSupport.fireEditingStopped();
066                }
067            });
068        }
069    }
070
071    protected void updateCheckboxes(Object v) {
072        if (v != null && checkBoxes[0] != null && checkBoxes[1] != null) {
073            boolean[] values;
074            if (v instanceof SaveLayerInfo) {
075                values = new boolean[2];
076                values[0] = ((SaveLayerInfo) v).isDoUploadToServer();
077                values[1] = ((SaveLayerInfo) v).isDoSaveToFile();
078            } else {
079                values = (boolean[]) v;
080            }
081            checkBoxes[0].setSelected(values[0]);
082            checkBoxes[1].setSelected(values[1]);
083        }
084    }
085
086    private void updatePanel(SaveLayerInfo info) {
087        StringBuilder sb = new StringBuilder();
088        sb.append("<html>");
089        sb.append(tr("Select which actions to perform for this layer, if you click the leftmost button."));
090        removeAll();
091        if (info != null) {
092            if (info.isUploadable()) {
093                sb.append("<br/>");
094                sb.append(tr("Check \"Upload\" to upload the changes to the OSM server."));
095                add(checkBoxes[0], GBC.eol().fill(GBC.HORIZONTAL));
096            }
097            if (info.isSavable()) {
098                sb.append("<br/>");
099                sb.append(tr("Check \"Save\" to save the layer to the file specified on the left."));
100                add(checkBoxes[1], GBC.eol().fill(GBC.HORIZONTAL));
101            }
102        }
103        sb.append("</html>");
104        setToolTipText(sb.toString());
105    }
106
107    @Override
108    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
109        updatePanel((SaveLayerInfo) value);
110        updateCheckboxes(value);
111        return this;
112    }
113
114    @Override
115    public void addCellEditorListener(CellEditorListener l) {
116        cellEditorSupport.addCellEditorListener(l);
117    }
118
119    @Override
120    public void cancelCellEditing() {
121        cellEditorSupport.fireEditingCanceled();
122    }
123
124    @Override
125    public Object getCellEditorValue() {
126        boolean[] values = new boolean[2];
127        values[0] = checkBoxes[0].isSelected();
128        values[1] = checkBoxes[1].isSelected();
129        return values;
130    }
131
132    @Override
133    public boolean isCellEditable(EventObject anEvent) {
134        return true;
135    }
136
137    @Override
138    public void removeCellEditorListener(CellEditorListener l) {
139        cellEditorSupport.removeCellEditorListener(l);
140    }
141
142    @Override
143    public boolean shouldSelectCell(EventObject anEvent) {
144        return true;
145    }
146
147    @Override
148    public boolean stopCellEditing() {
149        cellEditorSupport.fireEditingStopped();
150        return true;
151    }
152
153    @Override
154    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
155        updatePanel((SaveLayerInfo) value);
156        updateCheckboxes(value);
157        return this;
158    }
159}