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    /**
043     * Constructs a new {@code ActionFlagsTableCell}.
044     */
045    ActionFlagsTableCell() {
046        checkBoxes[0] = new JCheckBox(tr("Upload"));
047        checkBoxes[1] = new JCheckBox(tr("Save"));
048        setLayout(new GridBagLayout());
049
050        ActionListener al = e -> cellEditorSupport.fireEditingStopped();
051        ActionMap am = getActionMap();
052        for (final JCheckBox b : checkBoxes) {
053            b.setPreferredSize(new Dimension(b.getPreferredSize().width, 19));
054            b.addActionListener(al);
055            am.put(b.getText(), new AbstractAction() {
056                @Override
057                public void actionPerformed(ActionEvent e) {
058                    b.setSelected(!b.isSelected());
059                    cellEditorSupport.fireEditingStopped();
060                }
061            });
062        }
063    }
064
065    protected void updateCheckboxes(Object v) {
066        if (v != null && checkBoxes[0] != null && checkBoxes[1] != null) {
067            boolean[] values;
068            if (v instanceof SaveLayerInfo) {
069                values = new boolean[2];
070                values[0] = ((SaveLayerInfo) v).isDoUploadToServer();
071                values[1] = ((SaveLayerInfo) v).isDoSaveToFile();
072            } else {
073                values = (boolean[]) v;
074            }
075            checkBoxes[0].setSelected(values[0]);
076            checkBoxes[1].setSelected(values[1]);
077        }
078    }
079
080    private void updatePanel(SaveLayerInfo info) {
081        StringBuilder sb = new StringBuilder(128)
082            .append("<html>")
083            .append(tr("Select which actions to perform for this layer, if you click the leftmost button."));
084        removeAll();
085        if (info != null) {
086            if (info.isUploadable()) {
087                sb.append("<br/>")
088                  .append(tr("Check \"Upload\" to upload the changes to the OSM server."));
089                add(checkBoxes[0], GBC.eol().fill(GBC.HORIZONTAL));
090            }
091            if (info.isSavable()) {
092                sb.append("<br/>")
093                  .append(tr("Check \"Save\" to save the layer to the file specified on the left."));
094                add(checkBoxes[1], GBC.eol().fill(GBC.HORIZONTAL));
095            }
096        }
097        sb.append("</html>");
098        setToolTipText(sb.toString());
099    }
100
101    @Override
102    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
103        return getTableCellEditorComponent(table, value, isSelected, row, column);
104    }
105
106    @Override
107    public void addCellEditorListener(CellEditorListener l) {
108        cellEditorSupport.addCellEditorListener(l);
109    }
110
111    @Override
112    public void cancelCellEditing() {
113        cellEditorSupport.fireEditingCanceled();
114    }
115
116    @Override
117    public Object getCellEditorValue() {
118        boolean[] values = new boolean[2];
119        values[0] = checkBoxes[0].isSelected();
120        values[1] = checkBoxes[1].isSelected();
121        return values;
122    }
123
124    @Override
125    public boolean isCellEditable(EventObject anEvent) {
126        return true;
127    }
128
129    @Override
130    public void removeCellEditorListener(CellEditorListener l) {
131        cellEditorSupport.removeCellEditorListener(l);
132    }
133
134    @Override
135    public boolean shouldSelectCell(EventObject anEvent) {
136        return true;
137    }
138
139    @Override
140    public boolean stopCellEditing() {
141        cellEditorSupport.fireEditingStopped();
142        return true;
143    }
144
145    @Override
146    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
147        updatePanel((SaveLayerInfo) value);
148        updateCheckboxes(value);
149        return this;
150    }
151}