Ticket #12420: josm-selection-toggledialog_clickable-summary-title.patch
File josm-selection-toggledialog_clickable-summary-title.patch, 20.4 KB (added by , 10 years ago) |
---|
-
src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
24 24 25 25 import javax.swing.AbstractAction; 26 26 import javax.swing.AbstractListModel; 27 import javax.swing.Action; 27 28 import javax.swing.DefaultListSelectionModel; 28 29 import javax.swing.JComponent; 29 30 import javax.swing.JList; … … 48 49 import org.openstreetmap.josm.data.osm.Node; 49 50 import org.openstreetmap.josm.data.osm.OsmPrimitive; 50 51 import org.openstreetmap.josm.data.osm.OsmPrimitiveComparator; 52 import org.openstreetmap.josm.data.osm.PrimitiveId; 51 53 import org.openstreetmap.josm.data.osm.Relation; 52 54 import org.openstreetmap.josm.data.osm.Way; 53 55 import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent; … … 155 157 ); 156 158 157 159 buildContentPanel(); 160 setTitleActions(new Action[] { 161 null, 162 new SelectAction(SelectAction.RELATIONS), 163 new SelectAction(SelectAction.WAYS), 164 new SelectAction(SelectAction.NODES), 165 }); 166 158 167 model.addListDataListener(new TitleUpdater()); 159 168 model.addListDataListener(actZoomToJOSMSelection); 160 169 … … 168 177 popupMenuHandler.setPrimitives(model.getSelected()); 169 178 } 170 179 }); 171 172 180 lstPrimitives.addMouseListener(new MouseEventHandler()); 173 181 174 182 InputMapUtils.addEnterAction(lstPrimitives, actZoomToListSelection); … … 273 281 */ 274 282 class TitleUpdater implements ListDataListener { 275 283 protected void updateTitle() { 276 setTitle(model.getJOSMSelectionSummary()); 284 String[] s = model.getJOSMSelectionSummary().split("/"); 285 String[] t = s[0].split(" ", 2); 286 setTitle(t[0]); 287 if (t.length > 1) { 288 s[0] = " " + t[1]; 289 s[1] = "/" + s[1]; 290 s[2] = "/" + s[2]; 291 setTitleSuffixes(s); 292 } 277 293 } 278 294 279 295 @Override … … 327 343 * of this dialog 328 344 */ 329 345 class SelectAction extends AbstractSelectAction implements ListSelectionListener { 346 static final String NODES = "Select {0} nodes"; 347 static final String WAYS = "Select {0} ways"; 348 static final String RELATIONS = "Select {0} relations"; 349 330 350 /** 331 351 * Constructs a new {@code SelectAction}. 332 352 */ 333 353 SelectAction() { 354 this(""); 355 } 356 357 SelectAction(String cmd) { 358 this.putValue(ACTION_COMMAND_KEY, cmd); 334 359 updateEnabledState(); 335 360 } 336 361 337 362 @Override 338 363 public void actionPerformed(ActionEvent e) { 339 Collection<OsmPrimitive> sel = model.getSelected();340 if (sel.isEmpty()) return;341 364 OsmDataLayer editLayer = Main.main.getEditLayer(); 342 365 if (editLayer == null) return; 343 editLayer.data.setSelected(sel); 344 model.selectionModel.setSelectionInterval(0, sel.size()-1); 366 367 Collection<? extends PrimitiveId> sel; 368 boolean clearsel = true; 369 370 switch ((String) this.getValue(ACTION_COMMAND_KEY)) { 371 case NODES: 372 sel = editLayer.data.getSelectedNodes(); 373 break; 374 case WAYS: 375 sel = editLayer.data.getSelectedWays(); 376 break; 377 case RELATIONS: 378 sel = editLayer.data.getSelectedRelations(); 379 break; 380 default: 381 sel = model.getSelected(); 382 clearsel = !clearsel; 383 break; 384 } 385 386 if (!sel.isEmpty()) { 387 editLayer.data.setSelected(sel); 388 model.selectionModel.setSelectionInterval(0, clearsel ? 0 : sel.size()-1); 389 } 345 390 } 346 391 347 392 protected void updateEnabledState() { -
src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
9 9 import java.awt.Container; 10 10 import java.awt.Dimension; 11 11 import java.awt.FlowLayout; 12 import java.awt.Graphics;13 import java.awt.GridBagLayout;14 12 import java.awt.GridLayout; 15 13 import java.awt.Rectangle; 16 14 import java.awt.Toolkit; … … 26 24 import java.util.ArrayList; 27 25 import java.util.Arrays; 28 26 import java.util.Collection; 27 import java.util.HashMap; 29 28 import java.util.LinkedList; 30 29 import java.util.List; 30 import java.util.Map; 31 31 32 32 import javax.swing.AbstractAction; 33 import javax.swing.Action; 33 34 import javax.swing.BorderFactory; 34 35 import javax.swing.ButtonGroup; 36 import javax.swing.GroupLayout; 37 import javax.swing.GroupLayout.ParallelGroup; 38 import javax.swing.GroupLayout.SequentialGroup; 35 39 import javax.swing.JButton; 36 40 import javax.swing.JCheckBoxMenuItem; 37 41 import javax.swing.JComponent; 38 42 import javax.swing.JDialog; 39 43 import javax.swing.JLabel; 40 44 import javax.swing.JMenu; 45 import javax.swing.JMenuItem; 41 46 import javax.swing.JOptionPane; 42 47 import javax.swing.JPanel; 43 48 import javax.swing.JPopupMenu; 44 49 import javax.swing.JRadioButtonMenuItem; 45 50 import javax.swing.JScrollPane; 46 51 import javax.swing.JToggleButton; 52 import javax.swing.LayoutStyle; 47 53 import javax.swing.SwingUtilities; 48 54 49 55 import org.openstreetmap.josm.Main; … … 55 61 import org.openstreetmap.josm.gui.MainMenu; 56 62 import org.openstreetmap.josm.gui.ShowHideButtonListener; 57 63 import org.openstreetmap.josm.gui.SideButton; 58 import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;59 64 import org.openstreetmap.josm.gui.help.HelpUtil; 60 65 import org.openstreetmap.josm.gui.help.Helpful; 61 66 import org.openstreetmap.josm.gui.preferences.PreferenceDialog; … … 64 69 import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting; 65 70 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; 66 71 import org.openstreetmap.josm.tools.Destroyable; 67 import org.openstreetmap.josm.tools.GBC;68 72 import org.openstreetmap.josm.tools.ImageProvider; 69 73 import org.openstreetmap.josm.tools.Shortcut; 70 74 import org.openstreetmap.josm.tools.WindowGeometry; … … 152 156 153 157 protected JToggleButton button; 154 158 private JPanel buttonsPanel; 155 private final transient List< javax.swing.Action> buttonActions = new ArrayList<>();159 private final transient List<Action> buttonActions = new ArrayList<>(); 156 160 157 161 /** holds the menu entry in the windows menu. Required to properly 158 162 * toggle the checkbox on show/hide … … 283 287 if (isShowing) { 284 288 hideDialog(); 285 289 if (dialogsPanel != null) { 286 dialogsPanel.reconstruct( Action.ELEMENT_SHRINKS, null);290 dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null); 287 291 } 288 292 hideNotify(); 289 293 } else { … … 292 296 expand(); 293 297 } 294 298 if (isDocked && dialogsPanel != null) { 295 dialogsPanel.reconstruct( Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);299 dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this); 296 300 } 297 301 showNotify(); 298 302 } … … 326 330 return; 327 331 if (isDialogInCollapsedView()) { 328 332 expand(); 329 dialogsPanel.reconstruct( Action.COLLAPSED_TO_DEFAULT, this);333 dialogsPanel.reconstruct(DialogsPanel.Action.COLLAPSED_TO_DEFAULT, this); 330 334 } else if (!isDialogShowing()) { 331 335 showDialog(); 332 336 if (isDocked && isCollapsed) { 333 337 expand(); 334 338 } 335 339 if (isDocked) { 336 dialogsPanel.reconstruct( Action.INVISIBLE_TO_DEFAULT, this);340 dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, this); 337 341 } 338 342 showNotify(); 339 343 } … … 488 492 /** the label which shows whether the toggle dialog is expanded or collapsed */ 489 493 private final JLabel lblMinimized; 490 494 /** the label which displays the dialog's title **/ 491 private final JLabel lblTitle ;492 private final J Component lblTitleWeak;495 private final JLabel lblTitleIcon; 496 private final JLabel[] lblTitle = new JLabel[4]; 493 497 /** the button which shows whether buttons are dynamic or not */ 494 498 private final JButton buttonsHide; 495 499 /** the contextual menu **/ 496 500 private DialogPopupMenu popupMenu; 501 /** the mouse event handler for the titlebar **/ 502 private MouseEventHandler mouseListener; 497 503 498 504 public TitleBar(String toggleDialogName, String iconName) { 499 setLayout(new GridBagLayout()); 505 GroupLayout gl = new GroupLayout(this); 506 setLayout(gl); 507 508 SequentialGroup hg = gl.createSequentialGroup(); 509 ParallelGroup vg = gl.createParallelGroup(); 510 gl.setHorizontalGroup(hg); 511 gl.setVerticalGroup(vg); 500 512 501 513 lblMinimized = new JLabel(ImageProvider.get("misc", "normal")); 502 add(lblMinimized); 514 hg.addComponent(lblMinimized, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 515 vg.addComponent(lblMinimized); 503 516 504 517 // scale down the dialog icon 505 lblTitle = new JLabel("", new ImageProvider("dialogs", iconName).setWidth(16).get(), JLabel.TRAILING); 506 lblTitle.setIconTextGap(8); 518 lblTitleIcon = new JLabel(new ImageProvider("dialogs", iconName).setWidth(16).get()); 519 hg.addComponent(lblTitleIcon, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 520 vg.addComponent(lblTitleIcon); 507 521 508 JPanel conceal = new JPanel(); 509 conceal.add(lblTitle); 510 conceal.setVisible(false); 511 add(conceal, GBC.std()); 512 513 // Cannot add the label directly since it would displace other elements on resize 514 lblTitleWeak = new JComponent() { 515 @Override 516 public void paintComponent(Graphics g) { 517 lblTitle.paint(g); 518 } 519 }; 520 lblTitleWeak.setPreferredSize(new Dimension(Integer.MAX_VALUE, 20)); 521 lblTitleWeak.setMinimumSize(new Dimension(0, 20)); 522 add(lblTitleWeak, GBC.std().fill(GBC.HORIZONTAL)); 522 hg.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED); 523 for (int i = 0; i < lblTitle.length; i++) { 524 lblTitle[i] = new JLabel(""); 525 hg.addComponent(lblTitle[i], 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 526 vg.addComponent(lblTitle[i]); 527 } 523 528 524 529 buttonsHide = new JButton(ImageProvider.get("misc", buttonHiding != ButtonHidingType.ALWAYS_SHOWN 525 530 ? /* ICON(misc/)*/ "buttonhide" : /* ICON(misc/)*/ "buttonshow")); … … 535 540 } 536 541 } 537 542 ); 538 add(buttonsHide); 543 hg.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE); 544 hg.addComponent(buttonsHide, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 545 vg.addComponent(buttonsHide); 539 546 540 547 // show the pref button if applicable 541 548 if (preferenceClass != null) { … … 557 564 } 558 565 } 559 566 ); 560 add(pref); 567 hg.addComponent(pref, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 568 vg.addComponent(pref); 561 569 } 562 570 563 571 // show the sticky button … … 569 577 @Override 570 578 public void actionPerformed(ActionEvent e) { 571 579 detach(); 572 dialogsPanel.reconstruct( Action.ELEMENT_SHRINKS, null);580 dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null); 573 581 } 574 582 } 575 583 ); 576 add(sticky); 584 hg.addComponent(sticky, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 585 vg.addComponent(sticky); 577 586 578 587 // show the close button 579 588 JButton close = new JButton(ImageProvider.get("misc", "close")); … … 584 593 @Override 585 594 public void actionPerformed(ActionEvent e) { 586 595 hideDialog(); 587 dialogsPanel.reconstruct( Action.ELEMENT_SHRINKS, null);596 dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null); 588 597 hideNotify(); 589 598 } 590 599 } 591 600 ); 592 add(close); 601 hg.addComponent(close, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); 602 vg.addComponent(close); 603 593 604 setToolTipText(tr("Click to minimize/maximize the panel content")); 594 setTitle(toggleDialogName); 605 lblTitle[0].setText(toggleDialogName); 606 } 607 608 public void setTitle(String s) { 609 setTitle(new String[]{s}, 0); 610 } 611 612 public void setTitle(String[] s, int from) { 613 for (int i = from; i < lblTitle.length; i++) { 614 lblTitle[i].setText(i-from < s.length ? s[i-from] : ""); 615 lblTitle[i].repaint(); 616 } 617 mouseListener.update(); 595 618 } 596 619 597 public void setTitle(String title) { 598 lblTitle.setText(title); 599 lblTitleWeak.repaint(); 620 public void setTitleActions(Action[] actions) { 621 int i = -1; 622 for (final JLabel l: lblTitle) { 623 if (++i < actions.length && actions[i] != null) { 624 mouseListener.actions.put(l, actions[i]); 625 l.addMouseListener(mouseListener); 626 popupMenu.insert(actions[i], 1); 627 } 628 } 600 629 } 601 630 602 631 public String getTitle() { 603 return lblTitle.getText(); 632 StringBuffer r = new StringBuffer(0x80); 633 for (JLabel l: lblTitle) { 634 r.append(l.getText()); 635 } 636 return r.toString(); 604 637 } 605 638 606 639 public class DialogPopupMenu extends JPopupMenu { … … 619 652 buttonHidingMenu.add(rb); 620 653 } 621 654 add(buttonHidingMenu); 622 for ( javax.swing.Action action: buttonActions) {655 for (Action action: buttonActions) { 623 656 add(action); 624 657 } 625 658 } … … 627 660 628 661 public final void registerMouseListener() { 629 662 popupMenu = new DialogPopupMenu(); 630 addMouseListener( new MouseEventHandler());663 addMouseListener(mouseListener = new MouseEventHandler()); 631 664 } 632 665 633 666 class MouseEventHandler extends PopupMenuLauncher { 667 Map<JComponent, Action> actions = new HashMap<>(); 668 634 669 /** 635 670 * Constructs a new {@code MouseEventHandler}. 636 671 */ … … 643 678 if (SwingUtilities.isLeftMouseButton(e)) { 644 679 if (isCollapsed) { 645 680 expand(); 646 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this); 681 dialogsPanel.reconstruct(DialogsPanel.Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this); 682 updateTooltips(); 647 683 } else { 648 collapse(); 649 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null); 684 Action a = actions.get(e.getComponent()); 685 if (a != null && a.isEnabled()) { 686 a.actionPerformed(new ActionEvent(e.getSource(), e.getID(), 687 (String) a.getValue(Action.ACTION_COMMAND_KEY))); 688 } else { 689 collapse(); 690 dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null); 691 updateTooltips(); 692 } 693 } 694 } 695 } 696 697 public void update() { 698 short enabledActions = 0; 699 for (JComponent l: actions.keySet()) { 700 if (update((JLabel) l).isEnabled()) enabledActions++; 701 } 702 for (Action a: actions.values()) { 703 if (a instanceof SelectionListDialog.SelectAction) { 704 a.setEnabled(a.isEnabled() && enabledActions > 1); 705 } 706 } 707 for (Component mi: popupMenu.getComponents()) { 708 if (mi instanceof JMenuItem) { 709 Action a = ((JMenuItem) mi).getAction(); 710 if (actions.containsValue(a)) mi.setVisible(a.isEnabled()); 650 711 } 651 712 } 713 updateTooltips(); 714 } 715 716 private Action update(JLabel l) { 717 Action a = actions.get(l); 718 String s = ""; 719 720 if (a instanceof SelectionListDialog.SelectAction) { 721 s = l.getText().replaceAll("\\D", "").replaceAll("^0+", ""); 722 a.setEnabled(s.length() > 0); 723 } 724 725 if (a != null) { 726 String name = tr((String) a.getValue(Action.ACTION_COMMAND_KEY), s); 727 a.putValue(Action.NAME, name); 728 a.putValue(Action.SHORT_DESCRIPTION, name); 729 } 730 731 return a; 732 } 733 734 private void updateTooltips() { 735 for (JComponent l: actions.keySet()) { 736 Action a = actions.get(l); 737 l.setToolTipText(isCollapsed || !a.isEnabled() ? getToolTipText() : (String) a.getValue(Action.NAME)); 738 } 652 739 } 653 740 } 654 741 } … … 671 758 if (isDialogInCollapsedView()) { 672 759 expand(); 673 760 } 674 dialogsPanel.reconstruct( Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);761 dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this); 675 762 } else { 676 763 hideDialog(); 677 764 hideNotify(); … … 747 834 * @param title The dialog's title 748 835 */ 749 836 public void setTitle(String title) { 750 titleBar.setTitle(title); 837 setTitleImpl(new String[]{title}, 0); 838 } 839 840 /** 841 * Sets the title and title suffix strings all at once. 842 * @param title The dialog's title 843 */ 844 public void setTitle(String[] title) { 845 setTitleImpl(title, 0); 846 } 847 848 /** 849 * Sets title suffixes. 850 * @param suffixes An array of strings to be used as title suffixes. 851 */ 852 public void setTitleSuffixes(String[] suffixes) { 853 setTitleImpl(suffixes, 1); 854 } 855 856 protected void setTitleImpl(String[] s, int from) { 857 titleBar.setTitle(s, from); 751 858 if (detachedDialog != null) { 752 detachedDialog.setTitle(title );859 detachedDialog.setTitle(titleBar.getTitle()); 753 860 } 754 861 } 755 862 863 /** 864 * Sets actions for titles. 865 * @param actions Action to perform when title and/or its suffixes are clicked, or when chosen from title popup menu. 866 */ 867 public void setTitleActions(Action[] actions) { 868 titleBar.setTitleActions(actions); 869 } 870 756 871 protected void setIsShowing(boolean val) { 757 872 isShowing = val; 758 873 Main.pref.put(preferencePrefix+".visible", val); … … 889 1004 buttonsPanel.add(buttonRowPanel); 890 1005 for (SideButton button : buttonRow) { 891 1006 buttonRowPanel.add(button); 892 javax.swing.Action action = button.getAction();1007 Action action = button.getAction(); 893 1008 if (action != null) { 894 1009 buttonActions.add(action); 895 1010 } else {