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

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

see #9518 - Automatically reload local styles using new Java 7 WatchService API

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