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

Last change on this file since 9751 was 9751, checked in by Don-vip, 8 years ago

see #12462 - Extend Save Layers dialog for more layer types (patch by holgermappt, modified for checkstyle compliance)

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