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