source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java@ 9438

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

see #12282 - handle warnings for mappaint styles:

  • Log warnings that occur when loading style
  • Display them in Mappaint dialog (Info action)
  • Drop redundant error icon
  • Ignore XML styles in styles validation test
  • Make styles validation test fail if at least a warning occur
  • Property svn:eol-style set to native
File size: 27.9 KB
RevLine 
[3843]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
[9334]4import static org.openstreetmap.josm.tools.I18n.marktr;
[3843]5import static org.openstreetmap.josm.tools.I18n.tr;
6
[3863]7import java.awt.Component;
[3843]8import java.awt.Dimension;
[3863]9import java.awt.Font;
10import java.awt.GridBagLayout;
[3894]11import java.awt.Insets;
[3843]12import java.awt.Point;
[3855]13import java.awt.Rectangle;
[3843]14import java.awt.event.ActionEvent;
[4175]15import java.awt.event.ActionListener;
[3843]16import java.awt.event.KeyEvent;
17import java.awt.event.MouseEvent;
[3863]18import java.io.BufferedInputStream;
19import java.io.BufferedReader;
20import java.io.File;
[4072]21import java.io.IOException;
[3863]22import java.io.InputStream;
23import java.io.InputStreamReader;
[7082]24import java.nio.charset.StandardCharsets;
[9280]25import java.nio.file.Files;
26import java.nio.file.StandardCopyOption;
[3863]27import java.util.ArrayList;
[4363]28import java.util.Arrays;
[9334]29import java.util.Collection;
[3863]30import java.util.List;
[3843]31
32import javax.swing.AbstractAction;
[4175]33import javax.swing.DefaultButtonModel;
[3843]34import javax.swing.DefaultListSelectionModel;
[9334]35import javax.swing.ImageIcon;
[3894]36import javax.swing.JCheckBox;
[3863]37import javax.swing.JFileChooser;
38import javax.swing.JLabel;
[7450]39import javax.swing.JMenu;
[3843]40import javax.swing.JPanel;
41import javax.swing.JPopupMenu;
42import javax.swing.JScrollPane;
[3863]43import javax.swing.JTabbedPane;
[3843]44import javax.swing.JTable;
[3855]45import javax.swing.JViewport;
[3843]46import javax.swing.ListSelectionModel;
[3863]47import javax.swing.SingleSelectionModel;
[3894]48import javax.swing.SwingConstants;
[3848]49import javax.swing.SwingUtilities;
[3843]50import javax.swing.UIManager;
[3894]51import javax.swing.border.EmptyBorder;
[3863]52import javax.swing.event.ChangeEvent;
53import javax.swing.event.ChangeListener;
[3843]54import javax.swing.event.ListSelectionEvent;
55import javax.swing.event.ListSelectionListener;
[5573]56import javax.swing.filechooser.FileFilter;
[3843]57import javax.swing.table.AbstractTableModel;
[3863]58import javax.swing.table.DefaultTableCellRenderer;
[3894]59import javax.swing.table.TableCellRenderer;
[3855]60import javax.swing.table.TableModel;
[3843]61
62import org.openstreetmap.josm.Main;
[5573]63import org.openstreetmap.josm.actions.ExtensionFileFilter;
[6426]64import org.openstreetmap.josm.actions.JosmAction;
65import org.openstreetmap.josm.actions.PreferencesAction;
[3863]66import org.openstreetmap.josm.gui.ExtendedDialog;
67import org.openstreetmap.josm.gui.PleaseWaitRunnable;
[3843]68import org.openstreetmap.josm.gui.SideButton;
69import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
[3855]70import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.MapPaintSylesUpdateListener;
[7450]71import org.openstreetmap.josm.gui.mappaint.StyleSetting;
[3843]72import org.openstreetmap.josm.gui.mappaint.StyleSource;
[5573]73import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
[3863]74import org.openstreetmap.josm.gui.preferences.SourceEntry;
[6426]75import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
[5573]76import org.openstreetmap.josm.gui.util.FileFilterAllFiles;
[7896]77import org.openstreetmap.josm.gui.util.GuiHelper;
[7578]78import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
79import org.openstreetmap.josm.gui.widgets.FileChooserManager;
[3863]80import org.openstreetmap.josm.gui.widgets.HtmlPanel;
[5886]81import org.openstreetmap.josm.gui.widgets.JosmTextArea;
[3843]82import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
[3863]83import org.openstreetmap.josm.tools.GBC;
[8323]84import org.openstreetmap.josm.tools.ImageOverlay;
[3843]85import org.openstreetmap.josm.tools.ImageProvider;
[8323]86import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
[5200]87import org.openstreetmap.josm.tools.InputMapUtils;
[3843]88import org.openstreetmap.josm.tools.Shortcut;
[3896]89import org.openstreetmap.josm.tools.Utils;
[3843]90
[7185]91public class MapPaintDialog extends ToggleDialog {
[3843]92
[3855]93 protected StylesTable tblStyles;
[3843]94 protected StylesModel model;
95 protected DefaultListSelectionModel selectionModel;
96
97 protected OnOffAction onoffAction;
98 protected ReloadAction reloadAction;
[3894]99 protected MoveUpDownAction upAction;
100 protected MoveUpDownAction downAction;
101 protected JCheckBox cbWireframe;
[3843]102
[8426]103 /**
104 * Action that opens the map paint preferences.
105 */
[6426]106 public static final JosmAction PREFERENCE_ACTION = PreferencesAction.forPreferenceSubTab(
[7668]107 tr("Map paint preferences"), null, MapPaintPreference.class, /* ICON */ "dialogs/mappaintpreference");
[6426]108
[5886]109 /**
110 * Constructs a new {@code MapPaintDialog}.
111 */
[3843]112 public MapPaintDialog() {
113 super(tr("Map Paint Styles"), "mapstyle", tr("configure the map painting style"),
[5030]114 Shortcut.registerShortcut("subwindow:mappaint", tr("Toggle: {0}", tr("MapPaint")),
[6969]115 KeyEvent.VK_M, Shortcut.ALT_SHIFT), 150, false, MapPaintPreference.class);
[3843]116 build();
117 }
118
119 protected void build() {
120 model = new StylesModel();
[3894]121
122 cbWireframe = new JCheckBox();
123 JLabel wfLabel = new JLabel(tr("Wireframe View"), ImageProvider.get("dialogs/mappaint", "wireframe_small"), JLabel.HORIZONTAL);
124 wfLabel.setFont(wfLabel.getFont().deriveFont(Font.PLAIN));
[8426]125 wfLabel.setLabelFor(cbWireframe);
[4175]126
127 cbWireframe.setModel(new DefaultButtonModel() {
128 @Override
129 public void setSelected(boolean b) {
130 super.setSelected(b);
131 tblStyles.setEnabled(!b);
132 onoffAction.updateEnabledState();
133 upAction.updateEnabledState();
134 downAction.updateEnabledState();
135 }
136 });
137 cbWireframe.addActionListener(new ActionListener() {
[6084]138 @Override
[4175]139 public void actionPerformed(ActionEvent e) {
140 Main.main.menu.wireFrameToggleAction.actionPerformed(null);
141 }
142 });
[8510]143 cbWireframe.setBorder(new EmptyBorder(new Insets(1, 1, 1, 1)));
[4175]144
[3855]145 tblStyles = new StylesTable(model);
[8510]146 tblStyles.setSelectionModel(selectionModel = new DefaultListSelectionModel());
[3843]147 tblStyles.addMouseListener(new PopupMenuHandler());
[8377]148 tblStyles.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
[3843]149 tblStyles.setBackground(UIManager.getColor("Panel.background"));
150 tblStyles.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
151 tblStyles.setTableHeader(null);
152 tblStyles.getColumnModel().getColumn(0).setMaxWidth(1);
153 tblStyles.getColumnModel().getColumn(0).setResizable(false);
[3894]154 tblStyles.getColumnModel().getColumn(0).setCellRenderer(new MyCheckBoxRenderer());
[3863]155 tblStyles.getColumnModel().getColumn(1).setCellRenderer(new StyleSourceRenderer());
[3843]156 tblStyles.setShowGrid(false);
157 tblStyles.setIntercellSpacing(new Dimension(0, 0));
158
[3894]159 JPanel p = new JPanel(new GridBagLayout());
160 p.add(cbWireframe, GBC.std(0, 0));
161 p.add(wfLabel, GBC.std(1, 0).weight(1, 0));
162 p.add(tblStyles, GBC.std(0, 1).span(2).fill());
[3843]163
[4363]164 reloadAction = new ReloadAction();
165 onoffAction = new OnOffAction();
166 upAction = new MoveUpDownAction(false);
167 downAction = new MoveUpDownAction(true);
168 selectionModel.addListSelectionListener(onoffAction);
169 selectionModel.addListSelectionListener(reloadAction);
170 selectionModel.addListSelectionListener(upAction);
171 selectionModel.addListSelectionListener(downAction);
[5219]172
[5200]173 // Toggle style on Enter and Spacebar
174 InputMapUtils.addEnterAction(tblStyles, onoffAction);
175 InputMapUtils.addSpacebarAction(tblStyles, onoffAction);
[5219]176
[6426]177 createLayout(p, true, Arrays.asList(
[5030]178 new SideButton(onoffAction, false),
179 new SideButton(upAction, false),
180 new SideButton(downAction, false),
[6426]181 new SideButton(PREFERENCE_ACTION, false)
182 ));
[3843]183 }
184
[4175]185 protected static class StylesTable extends JTable {
[3855]186
187 public StylesTable(TableModel dm) {
188 super(dm);
189 }
190
191 public void scrollToVisible(int row, int col) {
192 if (!(getParent() instanceof JViewport))
193 return;
194 JViewport viewport = (JViewport) getParent();
195 Rectangle rect = getCellRect(row, col, true);
196 Point pt = viewport.getViewPosition();
197 rect.setLocation(rect.x - pt.x, rect.y - pt.y);
198 viewport.scrollRectToVisible(rect);
199 }
200 }
201
[5538]202 @Override
[3855]203 public void showNotify() {
204 MapPaintStyles.addMapPaintSylesUpdateListener(model);
[4175]205 Main.main.menu.wireFrameToggleAction.addButtonModel(cbWireframe.getModel());
[3855]206 }
207
208 @Override
209 public void hideNotify() {
[4175]210 Main.main.menu.wireFrameToggleAction.removeButtonModel(cbWireframe.getModel());
[3855]211 MapPaintStyles.removeMapPaintSylesUpdateListener(model);
212 }
213
214 protected class StylesModel extends AbstractTableModel implements MapPaintSylesUpdateListener {
215
[8426]216 private final Class<?>[] columnClasses = {Boolean.class, StyleSource.class};
217
[8308]218 private transient List<StyleSource> data = new ArrayList<>();
[3863]219
[8426]220 /**
221 * Constructs a new {@code StylesModel}.
222 */
[3863]223 public StylesModel() {
[7005]224 data = new ArrayList<>(MapPaintStyles.getStyles().getStyleSources());
[3863]225 }
226
[3855]227 private StyleSource getRow(int i) {
[3863]228 return data.get(i);
[3843]229 }
230
231 @Override
232 public int getColumnCount() {
233 return 2;
234 }
235
236 @Override
237 public int getRowCount() {
[3863]238 return data.size();
[3843]239 }
[4072]240
[3843]241 @Override
242 public Object getValueAt(int row, int column) {
243 if (column == 0)
[3855]244 return getRow(row).active;
[3843]245 else
[3863]246 return getRow(row);
[3843]247 }
248
249 @Override
250 public boolean isCellEditable(int row, int column) {
251 return column == 0;
252 }
253
254 @Override
255 public Class<?> getColumnClass(int column) {
256 return columnClasses[column];
257 }
258
259 @Override
260 public void setValueAt(Object aValue, int row, int column) {
261 if (row < 0 || row >= getRowCount() || aValue == null)
262 return;
263 if (column == 0) {
[3855]264 MapPaintStyles.toggleStyleActive(row);
[3843]265 }
266 }
267
[3855]268 /**
269 * Make sure the first of the selected entry is visible in the
270 * views of this model.
271 */
[3863]272 public void ensureSelectedIsVisible() {
[3855]273 int index = selectionModel.getMinSelectionIndex();
274 if (index < 0) return;
275 if (index >= getRowCount()) return;
276 tblStyles.scrollToVisible(index, 0);
277 tblStyles.repaint();
278 }
279
280 @Override
281 public void mapPaintStylesUpdated() {
[7005]282 data = new ArrayList<>(MapPaintStyles.getStyles().getStyleSources());
[3843]283 fireTableDataChanged();
[3855]284 tblStyles.repaint();
[3843]285 }
286
[3855]287 @Override
288 public void mapPaintStyleEntryUpdated(int idx) {
[7005]289 data = new ArrayList<>(MapPaintStyles.getStyles().getStyleSources());
[3855]290 fireTableRowsUpdated(idx, idx);
291 tblStyles.repaint();
[3843]292 }
293 }
294
[3894]295 private class MyCheckBoxRenderer extends JCheckBox implements TableCellRenderer {
296
[8426]297 /**
298 * Constructs a new {@code MyCheckBoxRenderer}.
299 */
[8836]300 MyCheckBoxRenderer() {
[3894]301 setHorizontalAlignment(SwingConstants.CENTER);
302 setVerticalAlignment(SwingConstants.CENTER);
303 }
304
[6084]305 @Override
[8510]306 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
[4072]307 if (value == null)
308 return this;
[3894]309 boolean b = (Boolean) value;
310 setSelected(b);
311 setEnabled(!cbWireframe.isSelected());
312 return this;
313 }
314 }
315
316 private class StyleSourceRenderer extends DefaultTableCellRenderer {
[3863]317 @Override
318 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
[4072]319 if (value == null)
320 return this;
[3863]321 StyleSource s = (StyleSource) value;
[8510]322 JLabel label = (JLabel) super.getTableCellRendererComponent(table,
[3863]323 s.getDisplayString(), isSelected, hasFocus, row, column);
324 label.setIcon(s.getIcon());
325 label.setToolTipText(s.getToolTipText());
[3894]326 label.setEnabled(!cbWireframe.isSelected());
[3863]327 return label;
328 }
329 }
330
[4175]331 protected class OnOffAction extends AbstractAction implements ListSelectionListener {
[8426]332 /**
333 * Constructs a new {@code OnOffAction}.
334 */
[3843]335 public OnOffAction() {
[5030]336 putValue(NAME, tr("On/Off"));
[3843]337 putValue(SHORT_DESCRIPTION, tr("Turn selected styles on or off"));
338 putValue(SMALL_ICON, ImageProvider.get("apply"));
339 updateEnabledState();
340 }
341
342 protected void updateEnabledState() {
[3894]343 setEnabled(!cbWireframe.isSelected() && tblStyles.getSelectedRowCount() > 0);
[3843]344 }
345
346 @Override
[4175]347 public void valueChanged(ListSelectionEvent e) {
348 updateEnabledState();
349 }
350
351 @Override
[3843]352 public void actionPerformed(ActionEvent e) {
353 int[] pos = tblStyles.getSelectedRows();
[3855]354 MapPaintStyles.toggleStyleActive(pos);
355 selectionModel.clearSelection();
356 for (int p: pos) {
357 selectionModel.addSelectionInterval(p, p);
358 }
[3843]359 }
360 }
361
[3855]362 /**
363 * The action to move down the currently selected entries in the list.
364 */
[4175]365 protected class MoveUpDownAction extends AbstractAction implements ListSelectionListener {
[3863]366
[8285]367 private final int increment;
[3863]368
[8426]369 /**
370 * Constructs a new {@code MoveUpDownAction}.
371 * @param isDown {@code true} to move the entry down, {@code false} to move it up
372 */
[3855]373 public MoveUpDownAction(boolean isDown) {
374 increment = isDown ? 1 : -1;
[8510]375 putValue(NAME, isDown ? tr("Down") : tr("Up"));
[3855]376 putValue(SMALL_ICON, isDown ? ImageProvider.get("dialogs", "down") : ImageProvider.get("dialogs", "up"));
377 putValue(SHORT_DESCRIPTION, isDown ? tr("Move the selected entry one row down.") : tr("Move the selected entry one row up."));
378 updateEnabledState();
379 }
380
381 public void updateEnabledState() {
382 int[] sel = tblStyles.getSelectedRows();
[3894]383 setEnabled(!cbWireframe.isSelected() && MapPaintStyles.canMoveStyles(sel, increment));
[3855]384 }
385
386 @Override
387 public void actionPerformed(ActionEvent e) {
388 int[] sel = tblStyles.getSelectedRows();
389 MapPaintStyles.moveStyles(sel, increment);
390
391 selectionModel.clearSelection();
392 for (int row: sel) {
393 selectionModel.addSelectionInterval(row + increment, row + increment);
394 }
395 model.ensureSelectedIsVisible();
396 }
[4175]397
[6084]398 @Override
[4175]399 public void valueChanged(ListSelectionEvent e) {
400 updateEnabledState();
401 }
[3855]402 }
[4072]403
[3843]404 protected class ReloadAction extends AbstractAction implements ListSelectionListener {
[8426]405 /**
406 * Constructs a new {@code ReloadAction}.
407 */
[3843]408 public ReloadAction() {
409 putValue(NAME, tr("Reload from file"));
410 putValue(SHORT_DESCRIPTION, tr("reload selected styles from file"));
411 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
[3894]412 setEnabled(getEnabledState());
[3843]413 }
414
[3894]415 protected boolean getEnabledState() {
416 if (cbWireframe.isSelected())
417 return false;
[3843]418 int[] pos = tblStyles.getSelectedRows();
[3894]419 if (pos.length == 0)
420 return false;
[3843]421 for (int i : pos) {
[3894]422 if (!model.getRow(i).isLocal())
423 return false;
[3843]424 }
[3894]425 return true;
[3843]426 }
427
428 @Override
429 public void valueChanged(ListSelectionEvent e) {
[3894]430 setEnabled(getEnabledState());
[3843]431 }
432
433 @Override
434 public void actionPerformed(ActionEvent e) {
[3848]435 final int[] rows = tblStyles.getSelectedRows();
[3855]436 MapPaintStyles.reloadStyles(rows);
[3848]437 Main.worker.submit(new Runnable() {
438 @Override
439 public void run() {
440 SwingUtilities.invokeLater(new Runnable() {
441 @Override
442 public void run() {
[3855]443 selectionModel.clearSelection();
444 for (int r: rows) {
445 selectionModel.addSelectionInterval(r, r);
[3848]446 }
447 }
448 });
449 }
450 });
[3843]451 }
452 }
[4072]453
[3863]454 protected class SaveAsAction extends AbstractAction {
455
[8426]456 /**
457 * Constructs a new {@code SaveAsAction}.
458 */
[3863]459 public SaveAsAction() {
460 putValue(NAME, tr("Save as..."));
461 putValue(SHORT_DESCRIPTION, tr("Save a copy of this Style to file and add it to the list"));
462 putValue(SMALL_ICON, ImageProvider.get("copy"));
463 setEnabled(tblStyles.getSelectedRows().length == 1);
464 }
465
466 @Override
467 public void actionPerformed(ActionEvent e) {
468 int sel = tblStyles.getSelectionModel().getLeadSelectionIndex();
469 if (sel < 0 || sel >= model.getRowCount())
470 return;
471 final StyleSource s = model.getRow(sel);
472
[7578]473 FileChooserManager fcm = new FileChooserManager(false, "mappaint.clone-style.lastDirectory", System.getProperty("user.home"));
[5438]474 String suggestion = fcm.getInitialDirectory() + File.separator + s.getFileNamePart();
[5573]475
476 FileFilter ff;
477 if (s instanceof MapCSSStyleSource) {
[5576]478 ff = new ExtensionFileFilter("mapcss,css,zip", "mapcss", tr("Map paint style file (*.mapcss, *.zip)"));
[5573]479 } else {
[5576]480 ff = new ExtensionFileFilter("xml,zip", "xml", tr("Map paint style file (*.xml, *.zip)"));
[5573]481 }
482 fcm.createFileChooser(false, null, Arrays.asList(ff, FileFilterAllFiles.getInstance()), ff, JFileChooser.FILES_ONLY)
483 .getFileChooser().setSelectedFile(new File(suggestion));
[7578]484 AbstractFileChooser fc = fcm.openFileChooser();
[5438]485 if (fc == null)
[3863]486 return;
[5457]487 Main.worker.submit(new SaveToFileTask(s, fc.getSelectedFile()));
[3863]488 }
489
490 private class SaveToFileTask extends PleaseWaitRunnable {
[9078]491 private final StyleSource s;
492 private final File file;
[3863]493
494 private boolean canceled;
495 private boolean error;
496
[8836]497 SaveToFileTask(StyleSource s, File file) {
[3863]498 super(tr("Reloading style sources"));
499 this.s = s;
500 this.file = file;
501 }
502
503 @Override
504 protected void cancel() {
505 canceled = true;
506 }
507
508 @Override
509 protected void realRun() {
510 getProgressMonitor().indeterminateSubTask(
511 tr("Save style ''{0}'' as ''{1}''", s.getDisplayString(), file.getPath()));
512 try {
[6289]513 InputStream in = s.getSourceInputStream();
[9280]514 try (InputStream bis = new BufferedInputStream(in)) {
515 Files.copy(bis, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
[6289]516 } finally {
517 s.closeSourceInputStream(in);
[3863]518 }
519 } catch (IOException e) {
[9280]520 Main.warn(e);
[3863]521 error = true;
522 }
523 }
524
525 @Override
526 protected void finish() {
527 SwingUtilities.invokeLater(new Runnable() {
528 @Override
529 public void run() {
530 if (!error && !canceled) {
531 SourceEntry se = new SourceEntry(s);
532 se.url = file.getPath();
533 MapPaintStyles.addStyle(se);
[8836]534 tblStyles.getSelectionModel().setSelectionInterval(model.getRowCount() - 1, model.getRowCount() - 1);
[3863]535 model.ensureSelectedIsVisible();
536 }
537 }
538 });
539 }
540 }
541 }
542
[8426]543 /**
544 * Displays information about selected paint style in a new dialog.
545 */
[3863]546 protected class InfoAction extends AbstractAction {
547
[8285]548 private boolean errorsTabLoaded;
[9334]549 private boolean warningsTabLoaded;
[8285]550 private boolean sourceTabLoaded;
[3863]551
[8426]552 /**
553 * Constructs a new {@code InfoAction}.
554 */
[3863]555 public InfoAction() {
556 putValue(NAME, tr("Info"));
557 putValue(SHORT_DESCRIPTION, tr("view meta information, error log and source definition"));
558 putValue(SMALL_ICON, ImageProvider.get("info"));
559 setEnabled(tblStyles.getSelectedRows().length == 1);
560 }
561
562 @Override
563 public void actionPerformed(ActionEvent e) {
564 int sel = tblStyles.getSelectionModel().getLeadSelectionIndex();
565 if (sel < 0 || sel >= model.getRowCount())
566 return;
567 final StyleSource s = model.getRow(sel);
[4222]568 ExtendedDialog info = new ExtendedDialog(Main.parent, tr("Map Style info"), new String[] {tr("Close")});
[3863]569 info.setPreferredSize(new Dimension(600, 400));
570 info.setButtonIcons(new String[] {"ok.png"});
571
572 final JTabbedPane tabs = new JTabbedPane();
573
574 tabs.add("Info", buildInfoPanel(s));
575 JLabel lblInfo = new JLabel(tr("Info"));
576 lblInfo.setFont(lblInfo.getFont().deriveFont(Font.PLAIN));
577 tabs.setTabComponentAt(0, lblInfo);
578
[9334]579 final JPanel pErrors = addErrorOrWarningTab(tabs, lblInfo,
580 s.getErrors(), marktr("Errors"), 1, ImageProvider.get("misc", "error"));
581 final JPanel pWarnings = addErrorOrWarningTab(tabs, lblInfo,
582 s.getWarnings(), marktr("Warnings"), 2, ImageProvider.get("warning-small"));
[3863]583
584 final JPanel pSource = new JPanel(new GridBagLayout());
585 tabs.addTab("Source", pSource);
586 JLabel lblSource = new JLabel(tr("Source"));
587 lblSource.setFont(lblSource.getFont().deriveFont(Font.PLAIN));
[9334]588 tabs.setTabComponentAt(3, lblSource);
[3863]589
590 tabs.getModel().addChangeListener(new ChangeListener() {
591 @Override
592 public void stateChanged(ChangeEvent e) {
593 if (!errorsTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 1) {
594 errorsTabLoaded = true;
[9334]595 buildErrorsOrWarningPanel(s.getErrors(), pErrors);
[3863]596 }
[9334]597 if (!warningsTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 2) {
598 warningsTabLoaded = true;
599 buildErrorsOrWarningPanel(s.getWarnings(), pWarnings);
600 }
601 if (!sourceTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 3) {
[3863]602 sourceTabLoaded = true;
603 buildSourcePanel(s, pSource);
604 }
605 }
606 });
607 info.setContent(tabs, false);
608 info.showDialog();
609 }
610
[9334]611 private JPanel addErrorOrWarningTab(final JTabbedPane tabs, JLabel lblInfo,
612 Collection<?> items, String title, int pos, ImageIcon icon) {
613 final JPanel pErrors = new JPanel(new GridBagLayout());
614 tabs.add(title, pErrors);
615 if (items.isEmpty()) {
616 JLabel lblErrors = new JLabel(tr(title));
617 lblErrors.setFont(lblInfo.getFont().deriveFont(Font.PLAIN));
618 lblErrors.setEnabled(false);
619 tabs.setTabComponentAt(pos, lblErrors);
620 tabs.setEnabledAt(pos, false);
621 } else {
622 JLabel lblErrors = new JLabel(tr(title), icon, JLabel.HORIZONTAL);
623 tabs.setTabComponentAt(pos, lblErrors);
624 }
625 return pErrors;
626 }
627
[3863]628 private JPanel buildInfoPanel(StyleSource s) {
629 JPanel p = new JPanel(new GridBagLayout());
[3896]630 StringBuilder text = new StringBuilder("<table cellpadding=3>");
631 text.append(tableRow(tr("Title:"), s.getDisplayString()));
[6920]632 if (s.url.startsWith("http://") || s.url.startsWith("https://")) {
[3896]633 text.append(tableRow(tr("URL:"), s.url));
[3863]634 } else if (s.url.startsWith("resource://")) {
[3896]635 text.append(tableRow(tr("Built-in Style, internal path:"), s.url));
[3863]636 } else {
[3896]637 text.append(tableRow(tr("Path:"), s.url));
[3863]638 }
[3896]639 if (s.icon != null) {
640 text.append(tableRow(tr("Icon:"), s.icon));
641 }
642 if (s.getBackgroundColorOverride() != null) {
643 text.append(tableRow(tr("Background:"), Utils.toString(s.getBackgroundColorOverride())));
644 }
[8379]645 text.append(tableRow(tr("Style is currently active?"), s.active ? tr("Yes") : tr("No")))
646 .append("</table>");
[3863]647 p.add(new JScrollPane(new HtmlPanel(text.toString())), GBC.eol().fill(GBC.BOTH));
648 return p;
649 }
650
[3896]651 private String tableRow(String firstColumn, String secondColumn) {
652 return "<tr><td><b>" + firstColumn + "</b></td><td>" + secondColumn + "</td></tr>";
653 }
654
[3863]655 private void buildSourcePanel(StyleSource s, JPanel p) {
[5886]656 JosmTextArea txtSource = new JosmTextArea();
[7896]657 txtSource.setFont(GuiHelper.getMonospacedFont(txtSource));
[3863]658 txtSource.setEditable(false);
659 p.add(new JScrollPane(txtSource), GBC.std().fill());
660
661 try {
[6289]662 InputStream is = s.getSourceInputStream();
[7082]663 try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
[7030]664 String line;
665 while ((line = reader.readLine()) != null) {
[8846]666 txtSource.append(line + '\n');
[6289]667 }
668 } finally {
669 s.closeSourceInputStream(is);
[3863]670 }
671 } catch (IOException ex) {
672 txtSource.append("<ERROR: failed to read file!>");
673 }
674 }
675
[9334]676 private <T> void buildErrorsOrWarningPanel(Collection<T> items, JPanel p) {
[5886]677 JosmTextArea txtErrors = new JosmTextArea();
[7896]678 txtErrors.setFont(GuiHelper.getMonospacedFont(txtErrors));
[3863]679 txtErrors.setEditable(false);
680 p.add(new JScrollPane(txtErrors), GBC.std().fill());
[9334]681 for (T t : items) {
[8376]682 txtErrors.append(t + "\n");
[3863]683 }
684 }
685 }
686
[3843]687 class PopupMenuHandler extends PopupMenuLauncher {
688 @Override
689 public void launch(MouseEvent evt) {
[3894]690 if (cbWireframe.isSelected())
691 return;
[5958]692 super.launch(evt);
[3843]693 }
[5958]694
695 @Override
696 protected void showMenu(MouseEvent evt) {
697 menu = new MapPaintPopup();
698 super.showMenu(evt);
699 }
[3843]700 }
701
[5958]702 /**
703 * The popup menu displayed when right-clicking a map paint entry
704 */
[3843]705 public class MapPaintPopup extends JPopupMenu {
[5886]706 /**
707 * Constructs a new {@code MapPaintPopup}.
708 */
[3843]709 public MapPaintPopup() {
710 add(reloadAction);
[3863]711 add(new SaveAsAction());
[7450]712
713 JMenu setMenu = new JMenu(tr("Style settings"));
[8323]714 setMenu.setIcon(new ImageProvider("preference").setMaxSize(ImageSizes.POPUPMENU).addOverlay(
715 new ImageOverlay(new ImageProvider("dialogs/mappaint", "pencil"), 0.5, 0.5, 1.0, 1.0)).get());
[7553]716 setMenu.setToolTipText(tr("Customize the style"));
[7450]717 add(setMenu);
718
719 int sel = tblStyles.getSelectionModel().getLeadSelectionIndex();
720 StyleSource style = null;
721 if (sel >= 0 && sel < model.getRowCount()) {
722 style = model.getRow(sel);
723 }
724 if (style == null || style.settings.isEmpty()) {
725 setMenu.setEnabled(false);
726 } else {
727 for (StyleSetting s : style.settings) {
728 s.addMenuEntry(setMenu);
729 }
730 }
731
[3863]732 addSeparator();
733 add(new InfoAction());
[3843]734 }
735 }
736}
Note: See TracBrowser for help on using the repository browser.