source: josm/trunk/src/org/openstreetmap/josm/gui/io/LayerNameAndFilePathTableCell.java@ 12687

Last change on this file since 12687 was 12537, checked in by Don-vip, 7 years ago

PMD - VariableNamingConventions

  • Property svn:eol-style set to native
File size: 9.1 KB
RevLine 
[5003]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Dimension;
9import java.awt.Font;
10import java.awt.GridBagLayout;
11import java.awt.event.ActionEvent;
12import java.awt.event.FocusAdapter;
13import java.awt.event.FocusEvent;
14import java.io.File;
15import java.util.EventObject;
16
17import javax.swing.AbstractAction;
18import javax.swing.BorderFactory;
19import javax.swing.JButton;
20import javax.swing.JLabel;
21import javax.swing.JPanel;
22import javax.swing.JTable;
23import javax.swing.event.CellEditorListener;
24import javax.swing.table.TableCellEditor;
25import javax.swing.table.TableCellRenderer;
26
27import org.openstreetmap.josm.actions.SaveActionBase;
[6912]28import org.openstreetmap.josm.gui.util.CellEditorSupport;
29import org.openstreetmap.josm.gui.widgets.JosmTextField;
[5003]30import org.openstreetmap.josm.tools.GBC;
31
[9754]32/**
33 * Display and edit layer name and file path in a <code>JTable</code>.
[10308]34 *
[9754]35 * Note: Do not use the same object both as <code>TableCellRenderer</code> and
36 * <code>TableCellEditor</code> - this can mess up the current editor component
37 * by subsequent calls to the renderer (#12462).
38 */
[5003]39class LayerNameAndFilePathTableCell extends JPanel implements TableCellRenderer, TableCellEditor {
[12537]40 private static final Color COLOR_ERROR = new Color(255, 197, 197);
[10308]41 private static final String ELLIPSIS = '…' + File.separator;
[5003]42
[5463]43 private final JLabel lblLayerName = new JLabel();
44 private final JLabel lblFilename = new JLabel("");
[5886]45 private final JosmTextField tfFilename = new JosmTextField();
[5003]46 private final JButton btnFileChooser = new JButton(new LaunchFileChooserAction());
47
[12537]48 private static final GBC DEFAULT_CELL_STYLE = GBC.eol().fill(GBC.HORIZONTAL).insets(2, 0, 2, 0);
[5003]49
[8308]50 private final transient CellEditorSupport cellEditorSupport = new CellEditorSupport(this);
[5003]51 private File value;
52
53 /** constructor that sets the default on each element **/
[8836]54 LayerNameAndFilePathTableCell() {
[5003]55 setLayout(new GridBagLayout());
56
57 lblLayerName.setPreferredSize(new Dimension(lblLayerName.getPreferredSize().width, 19));
58 lblLayerName.setFont(lblLayerName.getFont().deriveFont(Font.BOLD));
59
60 lblFilename.setPreferredSize(new Dimension(lblFilename.getPreferredSize().width, 19));
61 lblFilename.setOpaque(true);
[8426]62 lblFilename.setLabelFor(btnFileChooser);
[5003]63
64 tfFilename.setToolTipText(tr("Either edit the path manually in the text field or click the \"...\" button to open a file chooser."));
65 tfFilename.setPreferredSize(new Dimension(tfFilename.getPreferredSize().width, 19));
66 tfFilename.addFocusListener(
67 new FocusAdapter() {
[6889]68 @Override
69 public void focusGained(FocusEvent e) {
[5003]70 tfFilename.selectAll();
71 }
72 }
[5463]73 );
[5003]74 // hide border
75 tfFilename.setBorder(BorderFactory.createLineBorder(getBackground()));
76
77 btnFileChooser.setPreferredSize(new Dimension(20, 19));
78 btnFileChooser.setOpaque(true);
79 }
80
81 /** renderer used while not editing the file path **/
[6084]82 @Override
[5003]83 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
84 boolean hasFocus, int row, int column) {
85 removeAll();
[10021]86 if (value == null) return this;
[8510]87 SaveLayerInfo info = (SaveLayerInfo) value;
[5003]88 StringBuilder sb = new StringBuilder();
[8379]89 sb.append("<html>")
[9751]90 .append(addLblLayerName(info));
91 if (info.isSavable()) {
92 add(btnFileChooser, GBC.std());
93 sb.append("<br>")
94 .append(addLblFilename(info));
95 }
96 sb.append("</html>");
[5003]97 setToolTipText(sb.toString());
98 return this;
99 }
100
[6084]101 @Override
[6912]102 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
[5003]103 removeAll();
[8510]104 SaveLayerInfo info = (SaveLayerInfo) value;
[5003]105 value = info.getFile();
106 tfFilename.setText(value == null ? "" : value.toString());
107
108 StringBuilder sb = new StringBuilder();
[8379]109 sb.append("<html>")
[9751]110 .append(addLblLayerName(info));
[5003]111
[9751]112 if (info.isSavable()) {
113 add(btnFileChooser, GBC.std());
114 add(tfFilename, GBC.eol().fill(GBC.HORIZONTAL).insets(1, 0, 0, 0));
115 tfFilename.selectAll();
[5003]116
[9751]117 sb.append("<br>")
118 .append(tfFilename.getToolTipText());
119 }
120 sb.append("</html>");
[5003]121 setToolTipText(sb.toString());
122 return this;
123 }
124
125 private static boolean canWrite(File f) {
[11893]126 if (f == null || f.isDirectory()) return false;
[5003]127 if (f.exists() && f.canWrite()) return true;
[11893]128 return !f.exists() && f.getParentFile() != null && f.getParentFile().canWrite();
[5003]129 }
130
[9246]131 /**
132 * Adds layer name label to (this) using the given info. Returns tooltip that should be added to the panel
133 * @param info information, user preferences and save/upload states of the layer
134 * @return tooltip that should be added to the panel
135 */
[5003]136 private String addLblLayerName(SaveLayerInfo info) {
137 lblLayerName.setIcon(info.getLayer().getIcon());
138 lblLayerName.setText(info.getName());
[12537]139 add(lblLayerName, DEFAULT_CELL_STYLE);
[5003]140 return tr("The bold text is the name of the layer.");
141 }
142
[9246]143 /**
144 * Adds filename label to (this) using the given info. Returns tooltip that should be added to the panel
145 * @param info information, user preferences and save/upload states of the layer
146 * @return tooltip that should be added to the panel
147 */
[5003]148 private String addLblFilename(SaveLayerInfo info) {
[10308]149 String tooltip;
[5003]150 boolean error = false;
151 if (info.getFile() == null) {
152 error = info.isDoSaveToFile();
153 lblFilename.setText(tr("Click here to choose save path"));
154 lblFilename.setFont(lblFilename.getFont().deriveFont(Font.ITALIC));
155 tooltip = tr("Layer ''{0}'' is not backed by a file", info.getName());
156 } else {
157 String t = info.getFile().getPath();
158 lblFilename.setText(makePathFit(t));
159 tooltip = info.getFile().getAbsolutePath();
160 if (info.isDoSaveToFile() && !canWrite(info.getFile())) {
161 error = true;
162 tooltip = tr("File ''{0}'' is not writable. Please enter another file name.", info.getFile().getPath());
163 }
164 }
165
[12537]166 lblFilename.setBackground(error ? COLOR_ERROR : getBackground());
167 btnFileChooser.setBackground(error ? COLOR_ERROR : getBackground());
[5003]168
[12537]169 add(lblFilename, DEFAULT_CELL_STYLE);
[5003]170 return tr("Click cell to change the file path.") + "<br/>" + tooltip;
171 }
172
[9246]173 /**
[10873]174 * Makes the given path fit lblFilename, appends ellipsis on the left if it doesn't fit.
[9246]175 * Idea: /home/user/josm → …/user/josm → …/josm; and take the first one that fits
176 * @param t complete path
177 * @return shorter path
178 */
[5463]179 private String makePathFit(String t) {
[5003]180 boolean hasEllipsis = false;
[8510]181 while (t != null && !t.isEmpty()) {
[5003]182 int txtwidth = lblFilename.getFontMetrics(lblFilename.getFont()).stringWidth(t);
[10308]183 if (txtwidth < lblFilename.getWidth() || t.lastIndexOf(File.separator) < ELLIPSIS.length()) {
[5003]184 break;
185 }
186 // remove ellipsis, if present
[10308]187 t = hasEllipsis ? t.substring(ELLIPSIS.length()) : t;
[5003]188 // cut next block, and re-add ellipsis
[10308]189 t = ELLIPSIS + t.substring(t.indexOf(File.separator) + 1);
[5003]190 hasEllipsis = true;
191 }
192 return t;
193 }
194
[6084]195 @Override
[5003]196 public void addCellEditorListener(CellEditorListener l) {
[6912]197 cellEditorSupport.addCellEditorListener(l);
[5003]198 }
199
[6084]200 @Override
[5003]201 public void cancelCellEditing() {
[6912]202 cellEditorSupport.fireEditingCanceled();
[5003]203 }
204
[6084]205 @Override
[5003]206 public Object getCellEditorValue() {
207 return value;
208 }
209
[6084]210 @Override
[5003]211 public boolean isCellEditable(EventObject anEvent) {
212 return true;
213 }
214
[6084]215 @Override
[5003]216 public void removeCellEditorListener(CellEditorListener l) {
[6912]217 cellEditorSupport.removeCellEditorListener(l);
[5003]218 }
219
[6084]220 @Override
[5003]221 public boolean shouldSelectCell(EventObject anEvent) {
222 return true;
223 }
224
[6084]225 @Override
[5003]226 public boolean stopCellEditing() {
[6087]227 if (tfFilename.getText() == null || tfFilename.getText().trim().isEmpty()) {
[5003]228 value = null;
229 } else {
230 value = new File(tfFilename.getText());
231 }
[6912]232 cellEditorSupport.fireEditingStopped();
[5003]233 return true;
234 }
235
236 private class LaunchFileChooserAction extends AbstractAction {
[8836]237 LaunchFileChooserAction() {
[5003]238 putValue(NAME, "...");
239 putValue(SHORT_DESCRIPTION, tr("Launch a file chooser to select a file"));
240 }
241
[6084]242 @Override
[5003]243 public void actionPerformed(ActionEvent e) {
244 File f = SaveActionBase.createAndOpenSaveFileChooser(tr("Select filename"), "osm");
245 if (f != null) {
246 tfFilename.setText(f.toString());
247 stopCellEditing();
248 }
249 }
250 }
251}
Note: See TracBrowser for help on using the repository browser.