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