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