Ticket #12420: josm-selection-toggledialog_clickable-summary-title.patch

File josm-selection-toggledialog_clickable-summary-title.patch, 20.4 KB (added by cmuelle8, 10 years ago)

josm-selection-toggledialog_clickable-summary-title.patch

  • src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

     
    2424
    2525import javax.swing.AbstractAction;
    2626import javax.swing.AbstractListModel;
     27import javax.swing.Action;
    2728import javax.swing.DefaultListSelectionModel;
    2829import javax.swing.JComponent;
    2930import javax.swing.JList;
     
    4849import org.openstreetmap.josm.data.osm.Node;
    4950import org.openstreetmap.josm.data.osm.OsmPrimitive;
    5051import org.openstreetmap.josm.data.osm.OsmPrimitiveComparator;
     52import org.openstreetmap.josm.data.osm.PrimitiveId;
    5153import org.openstreetmap.josm.data.osm.Relation;
    5254import org.openstreetmap.josm.data.osm.Way;
    5355import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
     
    155157        );
    156158
    157159        buildContentPanel();
     160        setTitleActions(new Action[] {
     161                null,
     162                new SelectAction(SelectAction.RELATIONS),
     163                new SelectAction(SelectAction.WAYS),
     164                new SelectAction(SelectAction.NODES),
     165        });
     166
    158167        model.addListDataListener(new TitleUpdater());
    159168        model.addListDataListener(actZoomToJOSMSelection);
    160169
     
    168177                popupMenuHandler.setPrimitives(model.getSelected());
    169178            }
    170179        });
    171 
    172180        lstPrimitives.addMouseListener(new MouseEventHandler());
    173181
    174182        InputMapUtils.addEnterAction(lstPrimitives, actZoomToListSelection);
     
    273281     */
    274282    class TitleUpdater implements ListDataListener {
    275283        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            }
    277293        }
    278294
    279295        @Override
     
    327343     * of this dialog
    328344     */
    329345    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
    330350        /**
    331351         * Constructs a new {@code SelectAction}.
    332352         */
    333353        SelectAction() {
     354            this("");
     355        }
     356
     357        SelectAction(String cmd) {
     358            this.putValue(ACTION_COMMAND_KEY, cmd);
    334359            updateEnabledState();
    335360        }
    336361
    337362        @Override
    338363        public void actionPerformed(ActionEvent e) {
    339             Collection<OsmPrimitive> sel = model.getSelected();
    340             if (sel.isEmpty()) return;
    341364            OsmDataLayer editLayer = Main.main.getEditLayer();
    342365            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            }
    345390        }
    346391
    347392        protected void updateEnabledState() {
  • src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java

     
    99import java.awt.Container;
    1010import java.awt.Dimension;
    1111import java.awt.FlowLayout;
    12 import java.awt.Graphics;
    13 import java.awt.GridBagLayout;
    1412import java.awt.GridLayout;
    1513import java.awt.Rectangle;
    1614import java.awt.Toolkit;
     
    2624import java.util.ArrayList;
    2725import java.util.Arrays;
    2826import java.util.Collection;
     27import java.util.HashMap;
    2928import java.util.LinkedList;
    3029import java.util.List;
     30import java.util.Map;
    3131
    3232import javax.swing.AbstractAction;
     33import javax.swing.Action;
    3334import javax.swing.BorderFactory;
    3435import javax.swing.ButtonGroup;
     36import javax.swing.GroupLayout;
     37import javax.swing.GroupLayout.ParallelGroup;
     38import javax.swing.GroupLayout.SequentialGroup;
    3539import javax.swing.JButton;
    3640import javax.swing.JCheckBoxMenuItem;
    3741import javax.swing.JComponent;
    3842import javax.swing.JDialog;
    3943import javax.swing.JLabel;
    4044import javax.swing.JMenu;
     45import javax.swing.JMenuItem;
    4146import javax.swing.JOptionPane;
    4247import javax.swing.JPanel;
    4348import javax.swing.JPopupMenu;
    4449import javax.swing.JRadioButtonMenuItem;
    4550import javax.swing.JScrollPane;
    4651import javax.swing.JToggleButton;
     52import javax.swing.LayoutStyle;
    4753import javax.swing.SwingUtilities;
    4854
    4955import org.openstreetmap.josm.Main;
     
    5561import org.openstreetmap.josm.gui.MainMenu;
    5662import org.openstreetmap.josm.gui.ShowHideButtonListener;
    5763import org.openstreetmap.josm.gui.SideButton;
    58 import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
    5964import org.openstreetmap.josm.gui.help.HelpUtil;
    6065import org.openstreetmap.josm.gui.help.Helpful;
    6166import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
     
    6469import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
    6570import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
    6671import org.openstreetmap.josm.tools.Destroyable;
    67 import org.openstreetmap.josm.tools.GBC;
    6872import org.openstreetmap.josm.tools.ImageProvider;
    6973import org.openstreetmap.josm.tools.Shortcut;
    7074import org.openstreetmap.josm.tools.WindowGeometry;
     
    152156
    153157    protected JToggleButton button;
    154158    private JPanel buttonsPanel;
    155     private final transient List<javax.swing.Action> buttonActions = new ArrayList<>();
     159    private final transient List<Action> buttonActions = new ArrayList<>();
    156160
    157161    /** holds the menu entry in the windows menu. Required to properly
    158162     * toggle the checkbox on show/hide
     
    283287            if (isShowing) {
    284288                hideDialog();
    285289                if (dialogsPanel != null) {
    286                     dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
     290                    dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null);
    287291                }
    288292                hideNotify();
    289293            } else {
     
    292296                    expand();
    293297                }
    294298                if (isDocked && dialogsPanel != null) {
    295                     dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
     299                    dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
    296300                }
    297301                showNotify();
    298302            }
     
    326330            return;
    327331        if (isDialogInCollapsedView()) {
    328332            expand();
    329             dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, this);
     333            dialogsPanel.reconstruct(DialogsPanel.Action.COLLAPSED_TO_DEFAULT, this);
    330334        } else if (!isDialogShowing()) {
    331335            showDialog();
    332336            if (isDocked && isCollapsed) {
    333337                expand();
    334338            }
    335339            if (isDocked) {
    336                 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, this);
     340                dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, this);
    337341            }
    338342            showNotify();
    339343        }
     
    488492        /** the label which shows whether the toggle dialog is expanded or collapsed */
    489493        private final JLabel lblMinimized;
    490494        /** the label which displays the dialog's title **/
    491         private final JLabel lblTitle;
    492         private final JComponent lblTitleWeak;
     495        private final JLabel lblTitleIcon;
     496        private final JLabel[] lblTitle = new JLabel[4];
    493497        /** the button which shows whether buttons are dynamic or not */
    494498        private final JButton buttonsHide;
    495499        /** the contextual menu **/
    496500        private DialogPopupMenu popupMenu;
     501        /** the mouse event handler for the titlebar **/
     502        private MouseEventHandler mouseListener;
    497503
    498504        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);
    500512
    501513            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);
    503516
    504517            // 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);
    507521
    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            }
    523528
    524529            buttonsHide = new JButton(ImageProvider.get("misc", buttonHiding != ButtonHidingType.ALWAYS_SHOWN
    525530                ? /* ICON(misc/)*/ "buttonhide" :  /* ICON(misc/)*/ "buttonshow"));
     
    535540                        }
    536541                    }
    537542                    );
    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);
    539546
    540547            // show the pref button if applicable
    541548            if (preferenceClass != null) {
     
    557564                            }
    558565                        }
    559566                        );
    560                 add(pref);
     567                hg.addComponent(pref, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
     568                vg.addComponent(pref);
    561569            }
    562570
    563571            // show the sticky button
     
    569577                        @Override
    570578                        public void actionPerformed(ActionEvent e) {
    571579                            detach();
    572                             dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
     580                            dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null);
    573581                        }
    574582                    }
    575583                    );
    576             add(sticky);
     584            hg.addComponent(sticky, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
     585            vg.addComponent(sticky);
    577586
    578587            // show the close button
    579588            JButton close = new JButton(ImageProvider.get("misc", "close"));
     
    584593                        @Override
    585594                        public void actionPerformed(ActionEvent e) {
    586595                            hideDialog();
    587                             dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
     596                            dialogsPanel.reconstruct(DialogsPanel.Action.ELEMENT_SHRINKS, null);
    588597                            hideNotify();
    589598                        }
    590599                    }
    591600                    );
    592             add(close);
     601            hg.addComponent(close, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
     602            vg.addComponent(close);
     603
    593604            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();
    595618        }
    596619
    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            }
    600629        }
    601630
    602631        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();
    604637        }
    605638
    606639        public class DialogPopupMenu extends JPopupMenu {
     
    619652                    buttonHidingMenu.add(rb);
    620653                }
    621654                add(buttonHidingMenu);
    622                 for (javax.swing.Action action: buttonActions) {
     655                for (Action action: buttonActions) {
    623656                    add(action);
    624657                }
    625658            }
     
    627660
    628661        public final void registerMouseListener() {
    629662            popupMenu = new DialogPopupMenu();
    630             addMouseListener(new MouseEventHandler());
     663            addMouseListener(mouseListener = new MouseEventHandler());
    631664        }
    632665
    633666        class MouseEventHandler extends PopupMenuLauncher {
     667            Map<JComponent, Action> actions = new HashMap<>();
     668
    634669            /**
    635670             * Constructs a new {@code MouseEventHandler}.
    636671             */
     
    643678                if (SwingUtilities.isLeftMouseButton(e)) {
    644679                    if (isCollapsed) {
    645680                        expand();
    646                         dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
     681                        dialogsPanel.reconstruct(DialogsPanel.Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
     682                        updateTooltips();
    647683                    } 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());
    650711                    }
    651712                }
     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                }
    652739            }
    653740        }
    654741    }
     
    671758                        if (isDialogInCollapsedView()) {
    672759                            expand();
    673760                        }
    674                         dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
     761                        dialogsPanel.reconstruct(DialogsPanel.Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
    675762                    } else {
    676763                        hideDialog();
    677764                        hideNotify();
     
    747834     * @param title The dialog's title
    748835     */
    749836    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);
    751858        if (detachedDialog != null) {
    752             detachedDialog.setTitle(title);
     859            detachedDialog.setTitle(titleBar.getTitle());
    753860        }
    754861    }
    755862
     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
    756871    protected void setIsShowing(boolean val) {
    757872        isShowing = val;
    758873        Main.pref.put(preferencePrefix+".visible", val);
     
    8891004                buttonsPanel.add(buttonRowPanel);
    8901005                for (SideButton button : buttonRow) {
    8911006                    buttonRowPanel.add(button);
    892                     javax.swing.Action action = button.getAction();
     1007                    Action action = button.getAction();
    8931008                    if (action != null) {
    8941009                        buttonActions.add(action);
    8951010                    } else {