Ticket #3409: wip3409.patch
| File wip3409.patch, 44.4 KB (added by , 14 years ago) |
|---|
-
src/org/openstreetmap/josm/gui/io/SaveFlagCellEditor.java
1 // License: GPL. For details, see LICENSE file.2 package org.openstreetmap.josm.gui.io;3 4 import java.awt.Component;5 import java.awt.event.MouseAdapter;6 import java.awt.event.MouseEvent;7 import java.util.EventObject;8 import java.util.concurrent.CopyOnWriteArrayList;9 10 import javax.swing.JCheckBox;11 import javax.swing.JTable;12 import javax.swing.event.CellEditorListener;13 import javax.swing.event.ChangeEvent;14 import javax.swing.table.TableCellEditor;15 16 /**17 * This is {@see TableCellEditor} for a boolean flag. It is used in two table columns of18 * {@see SaveLayersTable} and renders the values of {@see SaveLayerInfo#isDoSaveToFile()}19 * and {@see SaveLayerInfo#isDoUploadToServer()}20 *21 */22 class SaveFlagCellEditor extends JCheckBox implements TableCellEditor {23 private CopyOnWriteArrayList<CellEditorListener> listeners;24 private boolean value;25 26 public SaveFlagCellEditor() {27 listeners = new CopyOnWriteArrayList<CellEditorListener>();28 addMouseListener(29 new MouseAdapter() {30 @Override31 public void mouseExited(MouseEvent e) {32 stopCellEditing();33 }34 }35 );36 }37 38 public void addCellEditorListener(CellEditorListener l) {39 if (l != null) {40 listeners.addIfAbsent(l);41 }42 }43 44 protected void fireEditingCanceled() {45 for (CellEditorListener l: listeners) {46 l.editingCanceled(new ChangeEvent(this));47 }48 }49 50 protected void fireEditingStopped() {51 for (CellEditorListener l: listeners) {52 l.editingStopped(new ChangeEvent(this));53 }54 }55 56 public void cancelCellEditing() {57 fireEditingCanceled();58 }59 60 public Object getCellEditorValue() {61 return value;62 }63 64 public boolean isCellEditable(EventObject anEvent) {65 return true;66 }67 68 public void removeCellEditorListener(CellEditorListener l) {69 listeners.remove(l);70 }71 72 public boolean shouldSelectCell(EventObject anEvent) {73 return true;74 }75 76 public void setInitialValue(boolean value) {77 this.value = value;78 setSelected(value);79 }80 81 public boolean stopCellEditing() {82 this.value = isSelected();83 fireEditingStopped();84 return true;85 }86 87 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {88 SaveLayerInfo info = (SaveLayerInfo)value;89 switch(column) {90 case 4: setInitialValue(info.isDoUploadToServer()); break;91 case 5: setInitialValue(info.isDoSaveToFile()); break;92 }93 return this;94 }95 } -
src/org/openstreetmap/josm/gui/io/SaveLayersTable.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.io; 3 3 4 import java.awt.Dimension; 4 5 import java.beans.PropertyChangeEvent; 5 6 import java.beans.PropertyChangeListener; 6 7 … … 12 13 public SaveLayersTable(SaveLayersModel model) { 13 14 super(model, new SaveLayersTableColumnModel()); 14 15 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); 16 super.setRowHeight(39); 17 super.getTableHeader().setPreferredSize(new Dimension(super.getTableHeader().getWidth(), 24)); 18 super.getTableHeader().setReorderingAllowed(false); 15 19 } 16 20 17 21 public void propertyChange(PropertyChangeEvent evt) { -
src/org/openstreetmap/josm/gui/io/SaveLayersModel.java
24 24 private Mode mode; 25 25 private PropertyChangeSupport support; 26 26 27 // keep in sync with how the columns are ordered in SaveLayersTableColumnModel#build 28 private static final int columnFilename = 0; 29 private static final int columnActions = 2; 30 27 31 public SaveLayersModel() { 28 32 mode = Mode.EDITING_DATA; 29 33 support = new PropertyChangeSupport(this); … … 82 86 83 87 @Override 84 88 public boolean isCellEditable(int row, int column) { 85 return column == 3 || column == 4 || column == 5;89 return column == columnFilename || column == columnActions; 86 90 } 87 91 88 92 @Override 89 93 public void setValueAt(Object value, int row, int column) { 90 94 switch(column) { 91 case 3 /* file name */: 92 this.layerInfo.get(row).setFile((File)value); 93 this.layerInfo.get(row).setDoSaveToFile(true); 94 break; 95 case 4 /* upload */: this.layerInfo.get(row).setDoUploadToServer((Boolean)value);break; 96 case 5 /* save */: this.layerInfo.get(row).setDoSaveToFile((Boolean)value);break; 95 case columnFilename: 96 this.layerInfo.get(row).setFile((File)value); 97 this.layerInfo.get(row).setDoSaveToFile(true); 98 break; 99 case columnActions: 100 boolean[] values = (boolean[]) value; 101 this.layerInfo.get(row).setDoUploadToServer(values[0]); 102 this.layerInfo.get(row).setDoSaveToFile(values[1]); 103 break; 97 104 } 98 105 fireTableDataChanged(); 99 106 } … … 103 110 } 104 111 105 112 public List<SaveLayerInfo> getLayersWithoutFilesAndSaveRequest() { 106 List<SaveLayerInfo> ret = new ArrayList<SaveLayerInfo>();113 List<SaveLayerInfo> ret = new ArrayList<SaveLayerInfo>(); 107 114 for (SaveLayerInfo info: layerInfo) { 108 115 if (info.isDoSaveToFile() && info.getFile() == null) { 109 116 ret.add(info); … … 214 221 } 215 222 return ret; 216 223 } 217 218 224 } -
src/org/openstreetmap/josm/gui/io/ActionFlagsTableCell.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.io; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.awt.Component; 7 import java.awt.Dimension; 8 import java.awt.GridBagLayout; 9 import java.awt.event.ActionEvent; 10 import java.awt.event.ActionListener; 11 import java.util.EventObject; 12 import java.util.concurrent.CopyOnWriteArrayList; 13 14 import javax.swing.AbstractAction; 15 import javax.swing.ActionMap; 16 import javax.swing.JCheckBox; 17 import javax.swing.JPanel; 18 import javax.swing.JTable; 19 import javax.swing.event.CellEditorListener; 20 import javax.swing.event.ChangeEvent; 21 import javax.swing.table.TableCellEditor; 22 import javax.swing.table.TableCellRenderer; 23 24 import org.openstreetmap.josm.tools.GBC; 25 26 /** 27 * This class creates a table cell that features two checkboxes, Upload and Save. It 28 * handles everything on its own, in other words it renders itself and also functions 29 * as editor so the checkboxes may be set by the user. 30 * 31 * Intended usage is like this: 32 * ActionFlagsTableCell aftc = new ActionFlagsTableCell(); 33 * col = new TableColumn(0); 34 * col.setCellRenderer(aftc); 35 * col.setCellEditor(aftc); 36 */ 37 class ActionFlagsTableCell extends JPanel implements TableCellRenderer, TableCellEditor { 38 protected JCheckBox[] checkBoxes = new JCheckBox[2]; 39 private CopyOnWriteArrayList<CellEditorListener> listeners; 40 41 private ActionListener al = new ActionListener() { 42 public void actionPerformed(ActionEvent e) { 43 fireEditingStopped(); 44 } 45 }; 46 47 public ActionFlagsTableCell() { 48 super(); 49 listeners = new CopyOnWriteArrayList<CellEditorListener>(); 50 51 setLayout(new GridBagLayout()); 52 checkBoxes[0] = new JCheckBox(tr("Upload")); 53 checkBoxes[1] = new JCheckBox(tr("Save")); 54 55 ActionMap am = getActionMap(); 56 for(int i=0; i<checkBoxes.length; i++) { 57 final JCheckBox b = checkBoxes[i]; 58 add(b, GBC.eol().fill(GBC.HORIZONTAL)); 59 b.setPreferredSize(new Dimension(b.getPreferredSize().width, 19)); 60 b.addActionListener(al); 61 am.put(b.getText(), new AbstractAction() { 62 public void actionPerformed(ActionEvent e) { 63 b.setSelected(!b.isSelected()); 64 fireEditingStopped(); 65 } 66 }); 67 } 68 69 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>")); 70 } 71 72 protected void updateCheckboxes(Object v) { 73 boolean[] values; 74 if(v instanceof SaveLayerInfo) { 75 values = new boolean[2]; 76 values[0] = ((SaveLayerInfo) v).isDoUploadToServer(); 77 values[1] = ((SaveLayerInfo) v).isDoSaveToFile(); 78 } else { 79 values = (boolean[]) v; 80 } 81 checkBoxes[0].setSelected(values[0]); 82 checkBoxes[1].setSelected(values[1]); 83 } 84 85 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 86 updateCheckboxes(value); 87 return this; 88 } 89 90 public void addCellEditorListener(CellEditorListener l) { 91 if (l != null) { 92 listeners.addIfAbsent(l); 93 } 94 } 95 96 protected void fireEditingCanceled() { 97 for (CellEditorListener l: listeners) { 98 l.editingCanceled(new ChangeEvent(this)); 99 } 100 } 101 102 protected void fireEditingStopped() { 103 for (CellEditorListener l: listeners) { 104 l.editingStopped(new ChangeEvent(this)); 105 } 106 } 107 108 public void cancelCellEditing() { 109 fireEditingCanceled(); 110 } 111 112 public Object getCellEditorValue() { 113 boolean[] values = new boolean[2]; 114 values[0] = checkBoxes[0].isSelected(); 115 values[1] = checkBoxes[1].isSelected(); 116 return values; 117 } 118 119 public boolean isCellEditable(EventObject anEvent) { 120 return true; 121 } 122 123 public void removeCellEditorListener(CellEditorListener l) { 124 listeners.remove(l); 125 } 126 127 public boolean shouldSelectCell(EventObject anEvent) { 128 return true; 129 } 130 131 public boolean stopCellEditing() { 132 fireEditingStopped(); 133 return true; 134 } 135 136 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 137 updateCheckboxes(value); 138 return this; 139 } 140 } 141 No newline at end of file -
src/org/openstreetmap/josm/gui/io/SaveLayersTableColumnModel.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.Component; 7 import java.awt.Dimension; 8 import java.awt.GridBagLayout; 9 10 import javax.swing.JLabel; 11 import javax.swing.JPanel; 12 import javax.swing.JTable; 6 13 import javax.swing.table.DefaultTableColumnModel; 7 import javax.swing.table.TableCellEditor;8 14 import javax.swing.table.TableCellRenderer; 9 15 import javax.swing.table.TableColumn; 10 16 17 import org.openstreetmap.josm.tools.GBC; 18 11 19 class SaveLayersTableColumnModel extends DefaultTableColumnModel { 20 /** small renderer class that handles the "should be uploaded/saved" texts. */ 21 private static class RecommendedActionsTableCell extends JPanel implements TableCellRenderer { 22 private final static JPanel pnlEmpty = new JPanel(); 23 private final static JLabel needsUpload = new JLabel(tr("should be uploaded")); 24 private final static JLabel needsSave = new JLabel(tr("should be saved")); 25 private final static GBC defaultCellStyle = GBC.eol().fill(GBC.HORIZONTAL).insets(2, 0, 2, 0); 26 27 public RecommendedActionsTableCell() { 28 setLayout(new GridBagLayout()); 29 pnlEmpty.setPreferredSize(new Dimension(1, 19)); 30 needsUpload.setPreferredSize(new Dimension(needsUpload.getPreferredSize().width, 19)); 31 needsSave.setPreferredSize(new Dimension(needsSave.getPreferredSize().width, 19)); 32 } 33 34 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 35 boolean hasFocus, int row, int column) { 36 SaveLayerInfo info = (SaveLayerInfo)value; 37 StringBuilder sb = new StringBuilder(); 38 sb.append("<html>"); 39 if (info.getLayer().requiresUploadToServer()) { 40 add(needsUpload, defaultCellStyle); 41 sb.append(tr("Layer ''{0}'' has modifications which should be uploaded to the server.", info.getName())); 42 43 } else { 44 add(pnlEmpty, defaultCellStyle); 45 sb.append(tr("Layer ''{0}'' has no modifications to be uploaded.", info.getName())); 46 } 47 sb.append("<br/>"); 48 49 if (info.getLayer().requiresSaveToFile()) { 50 add(needsSave, defaultCellStyle); 51 sb.append(tr("Layer ''{0}'' has modifications which should be saved to its associated file ''{1}''.", info.getName(), info.getFile().toString())); 52 } else { 53 add(pnlEmpty, defaultCellStyle); 54 sb.append(tr("Layer ''{0}'' has no modifications to be saved.", info.getName())); 55 } 56 sb.append("</html>"); 57 setToolTipText(sb.toString()); 58 return this; 59 } 60 } 61 12 62 protected void build() { 13 63 TableColumn col = null; 14 TableCellRenderer renderer = new SaveLayerInfoCellRenderer();15 TableCellEditor fileNameEditor = new FilenameCellEditor();16 TableCellEditor saveFlagEditor = new SaveFlagCellEditor();17 64 18 // column 0 - Layer 19 col = new TableColumn(0); 20 col.setHeaderValue(tr("Layer")); 65 // column 0 - layer name, save path editor 66 LayerNameAndFilePathTableCell lnafptc = new LayerNameAndFilePathTableCell(); 67 col = new TableColumn(0); // keep in sync with SaveLayersModel#columnFilename 68 col.setHeaderValue(tr("Layer Name and File Path")); 21 69 col.setResizable(true); 22 col.setCellRenderer(renderer); 23 col.setPreferredWidth(100); 70 col.setCellRenderer(lnafptc); 71 col.setCellEditor(lnafptc); 72 col.setPreferredWidth(324); 24 73 addColumn(col); 25 74 26 // column 1 - Uploadrequired75 // column 1 - actions required 27 76 col = new TableColumn(1); 28 col.setHeaderValue(tr(" Should upload?"));77 col.setHeaderValue(tr("Recommended Actions")); 29 78 col.setResizable(true); 30 col.setCellRenderer( renderer);31 col.setPreferredWidth( 50);79 col.setCellRenderer(new RecommendedActionsTableCell()); 80 col.setPreferredWidth(150); 32 81 addColumn(col); 33 82 34 // column 2 - Save to file required 35 col = new TableColumn(2); 36 col.setHeaderValue(tr("Should save?")); 83 // column 2- actions to take 84 ActionFlagsTableCell aftc = new ActionFlagsTableCell(); 85 col = new TableColumn(2); // keep in sync with SaveLayersModel#columnActions 86 col.setHeaderValue(tr("Actions To Take")); 37 87 col.setResizable(true); 38 col.setCellRenderer( renderer);39 col.set PreferredWidth(50);40 addColumn(col);88 col.setCellRenderer(aftc); 89 col.setCellEditor(aftc); 90 col.setPreferredWidth(100); 41 91 42 // column 3 - filename43 col = new TableColumn(3);44 col.setHeaderValue(tr("Filename"));45 col.setResizable(true);46 col.setCellRenderer(renderer);47 col.setCellEditor(fileNameEditor);48 col.setPreferredWidth(200);49 92 addColumn(col); 50 51 // column 4 - Upload52 col = new TableColumn(4);53 col.setHeaderValue(tr("Upload"));54 col.setResizable(true);55 col.setCellRenderer(renderer);56 col.setCellEditor(saveFlagEditor);57 col.setPreferredWidth(30);58 addColumn(col);59 60 // column 5 - Save61 col = new TableColumn(5);62 col.setHeaderValue(tr("Save"));63 col.setResizable(true);64 col.setCellRenderer(renderer);65 col.setCellEditor(saveFlagEditor);66 col.setPreferredWidth(30);67 68 addColumn(col);69 93 } 70 94 71 95 public SaveLayersTableColumnModel() { -
src/org/openstreetmap/josm/gui/io/LayerNameAndFilePathTableCell.java
5 5 6 6 import java.awt.Color; 7 7 import java.awt.Component; 8 import java.awt.Dimension; 8 9 import java.awt.Font; 10 import java.awt.GridBagLayout; 11 import java.awt.event.ActionEvent; 12 import java.awt.event.FocusAdapter; 13 import java.awt.event.FocusEvent; 9 14 import java.io.File; 15 import java.util.EventObject; 16 import java.util.concurrent.CopyOnWriteArrayList; 10 17 11 import javax.swing.JCheckBox; 18 import javax.swing.AbstractAction; 19 import javax.swing.BorderFactory; 20 import javax.swing.JButton; 12 21 import javax.swing.JLabel; 22 import javax.swing.JPanel; 13 23 import javax.swing.JTable; 14 import javax.swing.UIManager; 24 import javax.swing.JTextField; 25 import javax.swing.event.CellEditorListener; 26 import javax.swing.event.ChangeEvent; 27 import javax.swing.table.TableCellEditor; 15 28 import javax.swing.table.TableCellRenderer; 16 29 17 import org.openstreetmap.josm.io.OsmApi; 30 import org.openstreetmap.josm.actions.SaveActionBase; 31 import org.openstreetmap.josm.tools.GBC; 18 32 19 /**20 * This is a {@see TableCellRenderer} for rendering the various fields of a21 * {@see SaveLayerInfo} in the table {@see SaveLayersTable}.22 *23 *24 */25 class SaveLayerInfoCellRenderer implements TableCellRenderer {26 private JLabel lblRenderer;27 private JCheckBox cbRenderer;28 33 29 public SaveLayerInfoCellRenderer(){30 lblRenderer = new JLabel();31 cbRenderer = new JCheckBox();32 }34 class LayerNameAndFilePathTableCell extends JPanel implements TableCellRenderer, TableCellEditor { 35 private final static Color colorError = new Color(255,197,197); 36 private final static String separator = System.getProperty("file.separator"); 37 private final static String ellipsis = "…" + separator; 33 38 34 protected Component prepareLayerNameRenderer(SaveLayerInfo info) { 35 lblRenderer.setIcon(info.getLayer().getIcon()); 36 lblRenderer.setText(info.getName()); 37 lblRenderer.setToolTipText(info.getLayer().getToolTipText()); 38 return lblRenderer; 39 private final static JLabel lblLayerName = new JLabel(); 40 private final static JLabel lblFilename = new JLabel(""); 41 private final static JTextField tfFilename = new JTextField(); 42 private final JButton btnFileChooser = new JButton(new LaunchFileChooserAction()); 43 44 private final static GBC defaultCellStyle = GBC.eol().fill(GBC.HORIZONTAL).insets(2, 0, 2, 0); 45 46 private CopyOnWriteArrayList<CellEditorListener> listeners; 47 private File value; 48 49 50 /** constructor that sets the default on each element **/ 51 public LayerNameAndFilePathTableCell() { 52 setLayout(new GridBagLayout()); 53 54 lblLayerName.setPreferredSize(new Dimension(lblLayerName.getPreferredSize().width, 19)); 55 lblLayerName.setFont(lblLayerName.getFont().deriveFont(Font.BOLD)); 56 57 lblFilename.setPreferredSize(new Dimension(lblFilename.getPreferredSize().width, 19)); 58 lblFilename.setOpaque(true); 59 60 tfFilename.setToolTipText(tr("Either edit the path manually in the text field or click the \"...\" button to open a file chooser.")); 61 tfFilename.setPreferredSize(new Dimension(tfFilename.getPreferredSize().width, 19)); 62 tfFilename.addFocusListener( 63 new FocusAdapter() { 64 @Override public void focusGained(FocusEvent e) { 65 tfFilename.selectAll(); 66 } 67 } 68 ); 69 // hide border 70 tfFilename.setBorder(BorderFactory.createLineBorder(getBackground())); 71 72 btnFileChooser.setPreferredSize(new Dimension(20, 19)); 73 btnFileChooser.setOpaque(true); 74 75 listeners = new CopyOnWriteArrayList<CellEditorListener>(); 39 76 } 40 77 41 protected Component prepareUploadRequiredRenderer(SaveLayerInfo info) { 42 lblRenderer.setIcon(null); 43 lblRenderer.setHorizontalAlignment(JLabel.CENTER); 44 String text = info.getLayer().requiresUploadToServer() ? tr("Yes") : tr("No"); 45 lblRenderer.setText(text); 46 if (info.getLayer().requiresUploadToServer()) { 47 lblRenderer.setToolTipText(tr("Layer ''{0}'' has modifications which should be uploaded to the server.", info.getName())); 48 } else { 49 lblRenderer.setToolTipText(tr("Layer ''{0}'' has no modifications to be uploaded.", info.getName())); 50 } 51 return lblRenderer; 78 /** renderer used while not editing the file path **/ 79 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 80 boolean hasFocus, int row, int column) { 81 removeAll(); 82 SaveLayerInfo info = (SaveLayerInfo)value; 83 StringBuilder sb = new StringBuilder(); 84 sb.append("<html>"); 85 sb.append(addLblLayerName(info)); 86 sb.append("<br>"); 87 add(btnFileChooser, GBC.std()); 88 sb.append(addLblFilename(info)); 89 90 sb.append("</html>"); 91 setToolTipText(sb.toString()); 92 return this; 52 93 } 53 94 54 protected Component prepareSaveToFileRequired(SaveLayerInfo info) { 55 lblRenderer.setIcon(null); 56 lblRenderer.setHorizontalAlignment(JLabel.CENTER); 57 String text = info.getLayer().requiresSaveToFile() ? tr("Yes") : tr("No"); 58 lblRenderer.setText(text); 59 if (info.getLayer().requiresSaveToFile()) { 60 lblRenderer.setToolTipText(tr("Layer ''{0}'' has modifications which should be saved to its associated file ''{1}''.", info.getName(), info.getFile().toString())); 61 } else { 62 lblRenderer.setToolTipText(tr("Layer ''{0}'' has no modifications to be saved.", info.getName())); 63 } 64 return lblRenderer; 95 /** renderer used while the file path is being edited **/ 96 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, 97 int row, int column) { 98 removeAll(); 99 SaveLayerInfo info = (SaveLayerInfo)value; 100 value = info.getFile(); 101 tfFilename.setText(value == null ? "" : value.toString()); 102 103 StringBuilder sb = new StringBuilder(); 104 sb.append("<html>"); 105 sb.append(addLblLayerName(info)); 106 sb.append("<br/>"); 107 108 add(btnFileChooser, GBC.std()); 109 add(tfFilename, GBC.eol().fill(GBC.HORIZONTAL).insets(1, 0, 0, 0)); 110 tfFilename.selectAll(); 111 112 sb.append(tfFilename.getToolTipText()); 113 sb.append("</html>"); 114 setToolTipText(sb.toString()); 115 return this; 65 116 } 66 117 67 pr otectedboolean canWrite(File f) {118 private static boolean canWrite(File f) { 68 119 if (f == null) return false; 69 120 if (f.isDirectory()) return false; 70 121 if (f.exists() && f.canWrite()) return true; … … 73 124 return false; 74 125 } 75 126 76 protected Component prepareFileNameRenderer(SaveLayerInfo info) { 77 lblRenderer.setIcon(null); 127 /** adds layer name label to (this) using the given info. Returns tooltip that 128 * should be added to the panel **/ 129 private String addLblLayerName(SaveLayerInfo info) { 130 lblLayerName.setIcon(info.getLayer().getIcon()); 131 lblLayerName.setText(info.getName()); 132 add(lblLayerName, defaultCellStyle); 133 return tr("The bold text is the name of the layer."); 134 } 135 136 /** adds filename label to (this) using the given info. Returns tooltip that 137 * should be added to the panel */ 138 private String addLblFilename(SaveLayerInfo info) { 139 String tooltip = ""; 140 boolean error = false; 78 141 if (info.getFile() == null) { 79 if (!info.isDoSaveToFile()) { 80 lblRenderer.setText(tr("No file associated with this layer")); 81 } else { 82 lblRenderer.setBackground(new Color(255,197,197)); 83 lblRenderer.setText(tr("Please select a file")); 84 } 85 lblRenderer.setFont(lblRenderer.getFont().deriveFont(Font.ITALIC)); 86 lblRenderer.setToolTipText(tr("Layer ''{0}'' is not backed by a file", info.getName())); 142 error = info.isDoSaveToFile(); 143 lblFilename.setText(tr("Click here to choose save path")); 144 lblFilename.setFont(lblFilename.getFont().deriveFont(Font.ITALIC)); 145 tooltip = tr("Layer ''{0}'' is not backed by a file", info.getName()); 87 146 } else { 88 String text = info.getFile().getName(); 89 String parent = info.getFile().getParent(); 90 if (parent != null) { 91 if (parent.length() <= 10) { 92 text = info.getFile().getPath(); 93 } else { 94 text = parent.substring(0, 10) + "..." + File.separator + text; 95 } 96 } 97 lblRenderer.setText(text); 98 lblRenderer.setToolTipText(info.getFile().getAbsolutePath()); 147 String t = info.getFile().getPath(); 148 lblFilename.setText(makePathFit(t)); 149 tooltip = info.getFile().getAbsolutePath(); 99 150 if (info.isDoSaveToFile() && !canWrite(info.getFile())) { 100 lblRenderer.setBackground(new Color(255,197,197));101 lblRenderer.setToolTipText(tr("File ''{0}'' is not writable. Please enter another file name.", info.getFile().getPath()));151 error = true; 152 tooltip = tr("File ''{0}'' is not writable. Please enter another file name.", info.getFile().getPath()); 102 153 } 103 154 } 104 return lblRenderer; 155 156 lblFilename.setBackground(error ? colorError : getBackground()); 157 btnFileChooser.setBackground(error ? colorError : getBackground()); 158 159 add(lblFilename, defaultCellStyle); 160 return tr("Click cell to change the file path.") + "<br/>" + tooltip; 105 161 } 106 162 107 protected Component prepareUploadRenderer(SaveLayerInfo info){ 108 cbRenderer.setSelected(info.isDoUploadToServer()); 109 lblRenderer.setToolTipText(tr("Select to upload layer ''{0}'' to the server ''{1}''", info.getName(), OsmApi.getOsmApi().getBaseUrl())); 110 return cbRenderer; 163 /** makes the given path fit lblFilename, appends ellipsis on the left if it doesn’t fit. 164 * Idea: /home/user/josm → …/user/josm → …/josm; and take the first one that fits */ 165 static final private String makePathFit(String t) { 166 boolean hasEllipsis = false; 167 while(t != null && !t.isEmpty()) { 168 int txtwidth = lblFilename.getFontMetrics(lblFilename.getFont()).stringWidth(t); 169 if(txtwidth < lblFilename.getWidth() || t.lastIndexOf(separator) < ellipsis.length()) { 170 break; 171 } 172 // remove ellipsis, if present 173 t = hasEllipsis ? t.substring(ellipsis.length()) : t; 174 // cut next block, and re-add ellipsis 175 t = ellipsis + t.split(separator, 2)[1]; 176 hasEllipsis = true; 177 } 178 return t; 111 179 } 112 180 113 p rotected Component prepareSaveToFileRenderer(SaveLayerInfo info){114 cbRenderer.setSelected(info.isDoSaveToFile());115 lblRenderer.setToolTipText(tr("Select to upload layer ''{0}'' to the server ''{1}''", info.getName(), OsmApi.getOsmApi().getBaseUrl()));116 return cbRenderer;181 public void addCellEditorListener(CellEditorListener l) { 182 if (l != null) { 183 listeners.addIfAbsent(l); 184 } 117 185 } 118 186 119 protected void resetRenderers() { 120 lblRenderer.setOpaque(true); 121 lblRenderer.setBackground(UIManager.getColor("Table.background")); 122 lblRenderer.setIcon(null); 123 lblRenderer.setText(""); 124 lblRenderer.setFont(UIManager.getFont("Table.font")); 125 lblRenderer.setHorizontalAlignment(JLabel.LEFT); 187 protected void fireEditingCanceled() { 188 for (CellEditorListener l: listeners) { 189 l.editingCanceled(new ChangeEvent(this)); 190 } 191 } 126 192 127 cbRenderer.setSelected(false); 128 cbRenderer.setOpaque(true); 129 cbRenderer.setBackground(UIManager.getColor("Table.background")); 193 protected void fireEditingStopped() { 194 for (CellEditorListener l: listeners) { 195 l.editingStopped(new ChangeEvent(this)); 196 } 130 197 } 131 198 132 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 133 boolean hasFocus, int row, int column) { 199 public void cancelCellEditing() { 200 fireEditingCanceled(); 201 } 134 202 135 resetRenderers();136 if (value == null)137 return null;203 public Object getCellEditorValue() { 204 return value; 205 } 138 206 139 SaveLayerInfo info = (SaveLayerInfo)value; 140 switch(column) { 141 case 0: return prepareLayerNameRenderer(info); 142 case 1: return prepareUploadRequiredRenderer(info); 143 case 2: return prepareSaveToFileRequired(info); 144 case 3: return prepareFileNameRenderer(info); 145 case 4: return prepareUploadRenderer(info); 146 case 5: return prepareSaveToFileRenderer(info); 207 public boolean isCellEditable(EventObject anEvent) { 208 return true; 209 } 210 211 public void removeCellEditorListener(CellEditorListener l) { 212 listeners.remove(l); 213 } 214 215 public boolean shouldSelectCell(EventObject anEvent) { 216 return true; 217 } 218 219 public boolean stopCellEditing() { 220 if (tfFilename.getText() == null || tfFilename.getText().trim().equals("")) { 221 value = null; 222 } else { 223 value = new File(tfFilename.getText()); 147 224 } 148 return null; 225 fireEditingStopped(); 226 return true; 149 227 } 228 229 private class LaunchFileChooserAction extends AbstractAction { 230 public LaunchFileChooserAction() { 231 putValue(NAME, "..."); 232 putValue(SHORT_DESCRIPTION, tr("Launch a file chooser to select a file")); 233 } 234 235 public void actionPerformed(ActionEvent e) { 236 File f = SaveActionBase.createAndOpenSaveFileChooser(tr("Select filename"), "osm"); 237 if (f != null) { 238 tfFilename.setText(f.toString()); 239 stopCellEditing(); 240 } 241 } 242 } 150 243 } -
src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java
8 8 import java.awt.Component; 9 9 import java.awt.Dimension; 10 10 import java.awt.FlowLayout; 11 import java.awt.Graphics2D; 11 12 import java.awt.GridBagConstraints; 12 13 import java.awt.GridBagLayout; 14 import java.awt.Image; 13 15 import java.awt.event.ActionEvent; 14 16 import java.awt.event.WindowAdapter; 15 17 import java.awt.event.WindowEvent; 18 import java.awt.image.BufferedImage; 16 19 import java.beans.PropertyChangeEvent; 17 20 import java.beans.PropertyChangeListener; 18 21 import java.util.List; … … 23 26 24 27 import javax.swing.AbstractAction; 25 28 import javax.swing.DefaultListCellRenderer; 29 import javax.swing.ImageIcon; 26 30 import javax.swing.JComponent; 27 31 import javax.swing.JDialog; 28 32 import javax.swing.JLabel; … … 32 36 import javax.swing.JScrollPane; 33 37 import javax.swing.KeyStroke; 34 38 import javax.swing.WindowConstants; 39 import javax.swing.event.TableModelEvent; 40 import javax.swing.event.TableModelListener; 35 41 36 42 import org.openstreetmap.josm.Main; 37 43 import org.openstreetmap.josm.actions.UploadAction; … … 44 50 import org.openstreetmap.josm.tools.ImageProvider; 45 51 import org.openstreetmap.josm.tools.WindowGeometry; 46 52 47 public class SaveLayersDialog extends JDialog {53 public class SaveLayersDialog extends JDialog implements TableModelListener { 48 54 static public enum UserAction { 49 55 /** 50 56 * save/upload layers was successful, proceed with operation … … 75 81 getContentPane().setLayout(new BorderLayout()); 76 82 77 83 model = new SaveLayersModel(); 78 SaveLayersTable table ;79 JScrollPane pane = new JScrollPane(table = new SaveLayersTable(model));84 SaveLayersTable table = new SaveLayersTable(model); 85 JScrollPane pane = new JScrollPane(table); 80 86 model.addPropertyChangeListener(table); 87 table.getModel().addTableModelListener(this); 88 81 89 getContentPane().add(pane, BorderLayout.CENTER); 82 90 getContentPane().add(buildButtonRow(), BorderLayout.SOUTH); 83 table.getTableHeader().setPreferredSize(new Dimension(table.getTableHeader().getWidth(), 40));84 91 85 92 addWindowListener(new WindowClosingAdapter()); 86 93 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 87 94 } 88 95 96 private SideButton saveAndProceedActionButton = null; 97 89 98 /** 90 99 * builds the button row 91 100 * … … 97 106 98 107 saveAndProceedAction = new SaveAndProceedAction(); 99 108 model.addPropertyChangeListener(saveAndProceedAction); 100 pnl.add( new SideButton(saveAndProceedAction));109 pnl.add(saveAndProceedActionButton = new SideButton(saveAndProceedAction)); 101 110 102 111 discardAndProceedAction = new DiscardAndProceedAction(); 103 112 model.addPropertyChangeListener(discardAndProceedAction); … … 326 335 } 327 336 328 337 public void initForDiscardAndExit() { 329 putValue(NAME, tr(" Discard and Exit"));338 putValue(NAME, tr("Exit now!")); 330 339 putValue(SHORT_DESCRIPTION, tr("Exit JOSM without saving. Unsaved changes are lost.")); 331 340 putValue(SMALL_ICON, ImageProvider.get("exit")); 332 341 } 333 342 334 343 public void initForDiscardAndDelete() { 335 putValue(NAME, tr("D iscard and Delete"));344 putValue(NAME, tr("Delete now!")); 336 345 putValue(SHORT_DESCRIPTION, tr("Delete layers without saving. Unsaved changes are lost.")); 337 346 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 338 347 } … … 352 361 } 353 362 } 354 363 355 class SaveAndProceedAction extends AbstractAction implements PropertyChangeListener { 364 final class SaveAndProceedAction extends AbstractAction implements PropertyChangeListener { 365 private static final int is = 24; // icon size 366 private static final String BASE_ICON = "BASE_ICON"; 367 private final Image save = ImageProvider.get("save").getImage(); 368 private final Image upld = ImageProvider.get("upload").getImage(); 369 private final Image saveDis = new BufferedImage(is, is, BufferedImage.TYPE_4BYTE_ABGR); 370 private final Image upldDis = new BufferedImage(is, is, BufferedImage.TYPE_4BYTE_ABGR); 371 356 372 public SaveAndProceedAction() { 373 // get disabled versions of icons 374 new JLabel(ImageProvider.get("save")).getDisabledIcon().paintIcon(new JPanel(), saveDis.getGraphics(), 0, 0); 375 new JLabel(ImageProvider.get("upload")).getDisabledIcon().paintIcon(new JPanel(), upldDis.getGraphics(), 0, 0); 357 376 initForSaveAndExit(); 358 377 } 359 378 360 379 public void initForSaveAndExit() { 361 putValue(NAME, tr(" Save/Upload and Exit"));380 putValue(NAME, tr("Perform actions before exiting")); 362 381 putValue(SHORT_DESCRIPTION, tr("Exit JOSM with saving. Unsaved changes are uploaded and/or saved.")); 363 putValue(SMALL_ICON, ImageProvider.get("exit")); 382 putValue(BASE_ICON, ImageProvider.get("exit")); 383 redrawIcon(); 364 384 } 365 385 366 386 public void initForSaveAndDelete() { 367 putValue(NAME, tr(" Save/Upload and Delete"));387 putValue(NAME, tr("Perform actions before deleting")); 368 388 putValue(SHORT_DESCRIPTION, tr("Save/Upload layers before deleting. Unsaved changes are not lost.")); 369 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 389 putValue(BASE_ICON, ImageProvider.get("dialogs", "delete")); 390 redrawIcon(); 370 391 } 371 392 393 public void redrawIcon() { 394 try { // Can fail if model is not yet setup properly 395 Image base = ((ImageIcon) getValue(BASE_ICON)).getImage(); 396 BufferedImage newIco = new BufferedImage(is*3, is, BufferedImage.TYPE_4BYTE_ABGR); 397 Graphics2D g = newIco.createGraphics(); 398 g.drawImage(model.getLayersToUpload().isEmpty() ? upldDis : upld, is*0, 0, is, is, null); 399 g.drawImage(model.getLayersToSave().isEmpty() ? saveDis : save, is*1, 0, is, is, null); 400 g.drawImage(base, is*2, 0, is, is, null); 401 putValue(SMALL_ICON, new ImageIcon(newIco)); 402 } catch(Exception e) { 403 putValue(SMALL_ICON, getValue(BASE_ICON)); 404 } 405 } 406 372 407 public void actionPerformed(ActionEvent e) { 373 408 if (! confirmSaveLayerInfosOK()) 374 409 return; … … 545 580 canceled = true; 546 581 } 547 582 } 583 584 @Override 585 public void tableChanged(TableModelEvent arg0) { 586 boolean dis = model.getLayersToSave().isEmpty() && model.getLayersToUpload().isEmpty(); 587 if(saveAndProceedActionButton != null) { 588 saveAndProceedActionButton.setEnabled(!dis); 589 } 590 saveAndProceedAction.redrawIcon(); 591 } 548 592 } -
src/org/openstreetmap/josm/gui/io/SaveLayerInfoCellRenderer.java
1 // License: GPL. For details, see LICENSE file.2 package org.openstreetmap.josm.gui.io;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import java.awt.Color;7 import java.awt.Component;8 import java.awt.Font;9 import java.io.File;10 11 import javax.swing.JCheckBox;12 import javax.swing.JLabel;13 import javax.swing.JTable;14 import javax.swing.UIManager;15 import javax.swing.table.TableCellRenderer;16 17 import org.openstreetmap.josm.io.OsmApi;18 19 /**20 * This is a {@see TableCellRenderer} for rendering the various fields of a21 * {@see SaveLayerInfo} in the table {@see SaveLayersTable}.22 *23 *24 */25 class SaveLayerInfoCellRenderer implements TableCellRenderer {26 private JLabel lblRenderer;27 private JCheckBox cbRenderer;28 29 public SaveLayerInfoCellRenderer() {30 lblRenderer = new JLabel();31 cbRenderer = new JCheckBox();32 }33 34 protected Component prepareLayerNameRenderer(SaveLayerInfo info) {35 lblRenderer.setIcon(info.getLayer().getIcon());36 lblRenderer.setText(info.getName());37 lblRenderer.setToolTipText(info.getLayer().getToolTipText());38 return lblRenderer;39 }40 41 protected Component prepareUploadRequiredRenderer(SaveLayerInfo info) {42 lblRenderer.setIcon(null);43 lblRenderer.setHorizontalAlignment(JLabel.CENTER);44 String text = info.getLayer().requiresUploadToServer() ? tr("Yes") : tr("No");45 lblRenderer.setText(text);46 if (info.getLayer().requiresUploadToServer()) {47 lblRenderer.setToolTipText(tr("Layer ''{0}'' has modifications which should be uploaded to the server.", info.getName()));48 } else {49 lblRenderer.setToolTipText(tr("Layer ''{0}'' has no modifications to be uploaded.", info.getName()));50 }51 return lblRenderer;52 }53 54 protected Component prepareSaveToFileRequired(SaveLayerInfo info) {55 lblRenderer.setIcon(null);56 lblRenderer.setHorizontalAlignment(JLabel.CENTER);57 String text = info.getLayer().requiresSaveToFile() ? tr("Yes") : tr("No");58 lblRenderer.setText(text);59 if (info.getLayer().requiresSaveToFile()) {60 lblRenderer.setToolTipText(tr("Layer ''{0}'' has modifications which should be saved to its associated file ''{1}''.", info.getName(), info.getFile().toString()));61 } else {62 lblRenderer.setToolTipText(tr("Layer ''{0}'' has no modifications to be saved.", info.getName()));63 }64 return lblRenderer;65 }66 67 protected boolean canWrite(File f) {68 if (f == null) return false;69 if (f.isDirectory()) return false;70 if (f.exists() && f.canWrite()) return true;71 if (!f.exists() && f.getParentFile() != null && f.getParentFile().canWrite())72 return true;73 return false;74 }75 76 protected Component prepareFileNameRenderer(SaveLayerInfo info) {77 lblRenderer.setIcon(null);78 if (info.getFile() == null) {79 if (!info.isDoSaveToFile()) {80 lblRenderer.setText(tr("No file associated with this layer"));81 } else {82 lblRenderer.setBackground(new Color(255,197,197));83 lblRenderer.setText(tr("Please select a file"));84 }85 lblRenderer.setFont(lblRenderer.getFont().deriveFont(Font.ITALIC));86 lblRenderer.setToolTipText(tr("Layer ''{0}'' is not backed by a file", info.getName()));87 } else {88 String text = info.getFile().getName();89 String parent = info.getFile().getParent();90 if (parent != null) {91 if (parent.length() <= 10) {92 text = info.getFile().getPath();93 } else {94 text = parent.substring(0, 10) + "..." + File.separator + text;95 }96 }97 lblRenderer.setText(text);98 lblRenderer.setToolTipText(info.getFile().getAbsolutePath());99 if (info.isDoSaveToFile() && !canWrite(info.getFile())) {100 lblRenderer.setBackground(new Color(255,197,197));101 lblRenderer.setToolTipText(tr("File ''{0}'' is not writable. Please enter another file name.", info.getFile().getPath()));102 }103 }104 return lblRenderer;105 }106 107 protected Component prepareUploadRenderer(SaveLayerInfo info){108 cbRenderer.setSelected(info.isDoUploadToServer());109 lblRenderer.setToolTipText(tr("Select to upload layer ''{0}'' to the server ''{1}''", info.getName(), OsmApi.getOsmApi().getBaseUrl()));110 return cbRenderer;111 }112 113 protected Component prepareSaveToFileRenderer(SaveLayerInfo info){114 cbRenderer.setSelected(info.isDoSaveToFile());115 lblRenderer.setToolTipText(tr("Select to upload layer ''{0}'' to the server ''{1}''", info.getName(), OsmApi.getOsmApi().getBaseUrl()));116 return cbRenderer;117 }118 119 protected void resetRenderers() {120 lblRenderer.setOpaque(true);121 lblRenderer.setBackground(UIManager.getColor("Table.background"));122 lblRenderer.setIcon(null);123 lblRenderer.setText("");124 lblRenderer.setFont(UIManager.getFont("Table.font"));125 lblRenderer.setHorizontalAlignment(JLabel.LEFT);126 127 cbRenderer.setSelected(false);128 cbRenderer.setOpaque(true);129 cbRenderer.setBackground(UIManager.getColor("Table.background"));130 }131 132 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,133 boolean hasFocus, int row, int column) {134 135 resetRenderers();136 if (value == null)137 return null;138 139 SaveLayerInfo info = (SaveLayerInfo)value;140 switch(column) {141 case 0: return prepareLayerNameRenderer(info);142 case 1: return prepareUploadRequiredRenderer(info);143 case 2: return prepareSaveToFileRequired(info);144 case 3: return prepareFileNameRenderer(info);145 case 4: return prepareUploadRenderer(info);146 case 5: return prepareSaveToFileRenderer(info);147 }148 return null;149 }150 }
