Ticket #1988: toolbar_preferences.patch

File toolbar_preferences.patch, 20.2 KB (added by Igor Shubovych <igor.shubovych@…>, 17 years ago)

New version of patch

  • src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java

    ### Eclipse Workspace Patch 1.0
    #P JOSM
     
    1010import java.awt.GridLayout;
    1111import java.awt.LayoutManager;
    1212import java.awt.Rectangle;
     13import java.awt.datatransfer.DataFlavor;
     14import java.awt.datatransfer.Transferable;
     15import java.awt.datatransfer.UnsupportedFlavorException;
    1316import java.awt.event.ActionEvent;
    1417import java.awt.event.ActionListener;
     18import java.awt.event.InputEvent;
     19import java.io.IOException;
     20import java.util.Arrays;
    1521import java.util.HashMap;
    16 import java.util.TreeMap;
     22import java.util.LinkedList;
     23import java.util.List;
    1724import java.util.Map;
    1825
     26import javax.swing.AbstractAction;
    1927import javax.swing.Action;
    2028import javax.swing.DefaultListCellRenderer;
    2129import javax.swing.DefaultListModel;
    2230import javax.swing.Icon;
    2331import javax.swing.JButton;
     32import javax.swing.JComponent;
    2433import javax.swing.JLabel;
    2534import javax.swing.JList;
     35import javax.swing.JMenuItem;
    2636import javax.swing.JPanel;
     37import javax.swing.JPopupMenu;
    2738import javax.swing.JScrollPane;
    2839import javax.swing.JToolBar;
     40import javax.swing.JTree;
    2941import javax.swing.ListCellRenderer;
     42import javax.swing.MenuElement;
     43import javax.swing.TransferHandler;
    3044import javax.swing.event.ListSelectionEvent;
    3145import javax.swing.event.ListSelectionListener;
     46import javax.swing.tree.DefaultMutableTreeNode;
     47import javax.swing.tree.DefaultTreeCellRenderer;
     48import javax.swing.tree.DefaultTreeModel;
     49import javax.swing.tree.TreePath;
    3250
    3351import org.openstreetmap.josm.Main;
    3452import org.openstreetmap.josm.tools.GBC;
     
    3856
    3957    private final class Move implements ActionListener {
    4058        public void actionPerformed(ActionEvent e) {
    41             if (e.getActionCommand().equals("<<")) {
    42                 while (unselected.size() > 1) {
    43                     selected.addElement(unselected.get(0));
    44                     unselected.remove(0);
     59            if (e.getActionCommand().equals("<") && actionsTree.getSelectionCount() > 0) {
     60               
     61                int leadItem = selected.getSize();
     62                if (selectedList.getSelectedIndex() != -1) {
     63                    int[] indices = selectedList.getSelectedIndices();
     64                    leadItem = indices[indices.length - 1];
    4565                }
    46             } else if (e.getActionCommand().equals("<") && unselectedList.getSelectedIndex() != -1) {
    47                 while (unselectedList.getSelectedIndex() != -1 && unselectedList.getSelectedIndex() != unselected.size()-1) {
    48                     selected.addElement(unselectedList.getSelectedValue());
    49                     unselected.remove(unselectedList.getSelectedIndex());
     66                for (TreePath selectedAction : actionsTree.getSelectionPaths()) {
     67                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedAction.getLastPathComponent();
     68                    if (node.getUserObject() == null || node.getUserObject() instanceof Action) {
     69                        selected.add(leadItem++, ((Action)node.getUserObject()).getValue("toolbar"));
     70                    }
    5071                }
    51                 if (unselectedList.getSelectedIndex() == unselected.size()-1)
    52                     selected.addElement(null);
    5372            } else if (e.getActionCommand().equals(">") && selectedList.getSelectedIndex() != -1) {
    5473                while (selectedList.getSelectedIndex() != -1) {
    55                     if (selectedList.getSelectedValue() != null)
    56                         unselected.add(unselected.size()-1, selectedList.getSelectedValue());
    5774                    selected.remove(selectedList.getSelectedIndex());
    5875                }
    59             } else if (e.getActionCommand().equals(">>")) {
    60                 while (selected.size() > 0) {
    61                     if (selected.get(0) != null)
    62                         unselected.add(unselected.size()-1, selected.get(0));
    63                     selected.remove(0);
    64                 }
    6576            } else if (e.getActionCommand().equals("up")) {
    6677                int i = selectedList.getSelectedIndex();
    6778                Object o = selected.get(i);
     
    90101    private Map<String, Action> actions = new HashMap<String, Action>();
    91102
    92103    private DefaultListModel selected = new DefaultListModel();
    93     private DefaultListModel unselected = new DefaultListModel();
     104   
     105    private DefaultMutableTreeNode rootActionsNode = new DefaultMutableTreeNode("Actions");
     106    private DefaultTreeModel actionsTreeModel = new DefaultTreeModel(rootActionsNode);
     107    private JTree actionsTree = new JTree(actionsTreeModel);
    94108    private JList selectedList = new JList(selected);
    95     private JList unselectedList = new JList(unselected);
     109   
     110    private String movingComponent;
    96111
    97112    public JToolBar control = new JToolBar();
    98113
    99114    private JButton upButton;
    100115    private JButton downButton;
    101 
     116   
    102117    public ToolbarPreferences() {
    103118        control.setFloatable(false);
     119       
     120        actionsTree.setCellRenderer(new DefaultTreeCellRenderer() {
     121            @Override
     122            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
     123                    boolean leaf, int row, boolean hasFocus) {
     124                DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
     125                JLabel comp = (JLabel) super.getTreeCellRendererComponent(
     126                        tree, value, sel, expanded, leaf, row, hasFocus);
     127                if (node.getUserObject() == null) {
     128                    comp.setText(tr("Separator"));
     129                    comp.setIcon(ImageProvider.get("preferences/separator"));
     130                }
     131                else if (node.getUserObject() instanceof Action) {
     132                    Action action = (Action) node.getUserObject();
     133                    comp.setText((String) action.getValue(Action.NAME));
     134                    comp.setIcon((Icon) action.getValue(Action.SMALL_ICON));
     135                }
     136                return comp;
     137            }
     138        });
    104139
    105         final ListCellRenderer oldRenderer = selectedList.getCellRenderer();
    106140        ListCellRenderer renderer = new DefaultListCellRenderer(){
    107141            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    108                 String s = tr("Separator");
    109                 Icon i = ImageProvider.get("preferences/separator");
     142                String s;
     143                Icon i;
    110144                if (value != null) {
    111                     s = (String)((Action)value).getValue(Action.NAME);
    112                     i = (Icon)((Action)value).getValue(Action.SMALL_ICON);
     145                    Action action = actions.get(value);
     146                    s = (String) action.getValue(Action.NAME);
     147                    i = (Icon) action.getValue(Action.SMALL_ICON);
     148                } else {
     149                    i = ImageProvider.get("preferences/separator");
     150                    s = tr("Separator");
    113151                }
    114                 JLabel l = (JLabel)oldRenderer.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
     152                JLabel l = (JLabel)super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
    115153                l.setIcon(i);
    116154                return l;
    117155            }
    118156        };
    119157        selectedList.setCellRenderer(renderer);
    120         unselectedList.setCellRenderer(renderer);
    121 
    122         unselectedList.addListSelectionListener(new ListSelectionListener(){
    123             public void valueChanged(ListSelectionEvent e) {
    124                 if ((unselectedList.getSelectedIndex() != -1))
    125                     selectedList.clearSelection();
    126                 upButton.setEnabled(selectedList.getSelectedIndex() != -1);
    127                 downButton.setEnabled(selectedList.getSelectedIndex() != -1);
    128             }
    129         });
    130158        selectedList.addListSelectionListener(new ListSelectionListener(){
    131159            public void valueChanged(ListSelectionEvent e) {
    132160                boolean sel = selectedList.getSelectedIndex() != -1;
    133161                if (sel)
    134                     unselectedList.clearSelection();
     162                    actionsTree.clearSelection();
    135163                upButton.setEnabled(sel);
    136164                downButton.setEnabled(sel);
    137165            }
    138166        });
    139     }
     167       
     168        selectedList.setDragEnabled(true);
     169        selectedList.setTransferHandler(new TransferHandler() {
     170            @Override
     171            protected Transferable createTransferable(JComponent c) {
     172                return new ActionTransferable(((JList)c).getSelectedValues());
     173            }
    140174
    141     public void addGui(PreferenceDialog gui) {
    142         selected.removeAllElements();
    143         unselected.removeAllElements();
    144         Map<String, Action> us = new TreeMap<String, Action>();
    145         for (Action a : actions.values())
    146         {
    147             us.put(a.getValue(Action.NAME).toString()+a.toString(), a);
    148         }
    149         for (String a : us.keySet())
    150             unselected.addElement(us.get(a));
    151         unselected.addElement(null);
     175            @Override
     176            public int getSourceActions(JComponent c) {
     177                return TransferHandler.MOVE;
     178            }
     179
     180            @Override
     181            public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
     182                for (DataFlavor f : transferFlavors) {
     183                    if (ACTION_FLAVOR.equals(f)) {
     184                        return true;
     185                    }
     186                }
     187                return false;
     188            }
     189           
     190            @Override
     191            public void exportAsDrag(JComponent comp, InputEvent e, int action) {
     192                super.exportAsDrag(comp, e, action);
     193                movingComponent = "list";
     194            }
     195           
     196            @Override
     197            public boolean importData(JComponent comp, Transferable t) {
     198                try {
     199                    int dropIndex = selectedList.locationToIndex(selectedList.getDropLocation().getDropPoint());
     200                    Object[] draggedData = (Object[]) t.getTransferData(ACTION_FLAVOR);
     201
     202                    Object leadItem = dropIndex >= 0 ? selected.elementAt(dropIndex) : null;
     203                    int dataLength = draggedData.length;
     204
     205                    if (leadItem != null)
     206                        for (int i = 0; i < dataLength; i++)
     207                            if (leadItem.equals(draggedData[i]))
     208                                return false;
     209
     210                    int dragLeadIndex = -1;
     211                    boolean localDrop = "list".equals(movingComponent);
    152212
     213                    if (localDrop) {
     214                        dragLeadIndex = selected.indexOf(draggedData[0]);
     215                        for (int i = 0; i < dataLength; i++)
     216                            selected.removeElement(draggedData[i]);
     217                    }
     218                    int[] indices = new int[dataLength];
     219
     220                    if (localDrop) {
     221                        int adjustedLeadIndex = selected.indexOf(leadItem);
     222                        int insertionAdjustment = dragLeadIndex <= adjustedLeadIndex ? 1 : 0;
     223                        for (int i = 0; i < dataLength; i++) {
     224                            selected.insertElementAt(draggedData[i], adjustedLeadIndex + insertionAdjustment + i);
     225                            indices[i] = adjustedLeadIndex + insertionAdjustment + i;
     226                        }
     227                    } else {
     228                        for (int i = 0; i < dataLength; i++) {
     229                            selected.add(dropIndex, draggedData[i]);
     230                            indices[i] = dropIndex + i;
     231                        }
     232                    }
     233                    selectedList.clearSelection();
     234                    selectedList.setSelectedIndices(indices);
     235                    movingComponent = "";
     236                    return true;
     237                } catch (Exception e) {
     238                    e.printStackTrace();
     239                }
     240                return false;
     241            }
     242           
     243            @Override
     244            protected void exportDone(JComponent source, Transferable data, int action) {
     245                if (movingComponent.equals("list")) {
     246                    try {
     247                        Object[] draggedData = (Object[]) data.getTransferData(ACTION_FLAVOR);
     248                        boolean localDrop = selected.contains(draggedData[0]);
     249                        if (localDrop) {
     250                            int[] indices = selectedList.getSelectedIndices();
     251                            Arrays.sort(indices);
     252                            for (int i = indices.length - 1; i >= 0; i--) {
     253                                selected.remove(indices[i]);
     254                            }
     255                        }
     256                    } catch (Exception e) {
     257                        e.printStackTrace();
     258                    }
     259                    movingComponent = "";
     260                }
     261            }
     262        });
     263       
     264        actionsTree.setTransferHandler(new TransferHandler() {
     265            private static final long serialVersionUID = 1L;
     266       
     267            @Override
     268            public int getSourceActions( JComponent c ){
     269                return TransferHandler.MOVE;
     270            }
     271           
     272            @Override
     273            protected void exportDone(JComponent source, Transferable data, int action) {
     274            }
     275           
     276            @Override
     277            protected Transferable createTransferable(JComponent c) {
     278                TreePath[] paths = actionsTree.getSelectionPaths();
     279                List<String> dragActions = new LinkedList<String>();
     280                for (TreePath path : paths) {
     281                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
     282                    Object obj = node.getUserObject();
     283                    if (obj == null) {
     284                        dragActions.add(null);
     285                    }
     286                    else if (obj instanceof Action) {
     287                        dragActions.add((String) ((Action) obj).getValue("toolbar"));
     288                    }
     289                }
     290                return new ActionTransferable(dragActions.toArray());
     291            }
     292        });
     293        actionsTree.setDragEnabled(true);
     294    }
     295   
     296    public void addGui(PreferenceDialog gui) {
    153297        final JPanel left = new JPanel(new GridBagLayout());
    154298        left.add(new JLabel(tr("Toolbar")), GBC.eol());
    155299        left.add(new JScrollPane(selectedList), GBC.std().fill(GBC.BOTH));
    156300
    157301        final JPanel right = new JPanel(new GridBagLayout());
    158302        right.add(new JLabel(tr("Available")), GBC.eol());
    159         right.add(new JScrollPane(unselectedList), GBC.eol().fill(GBC.BOTH));
     303        right.add(new JScrollPane(actionsTree), GBC.eol().fill(GBC.BOTH));
    160304
    161305        final JPanel buttons = new JPanel(new GridLayout(6,1));
    162306        buttons.add(upButton = createButton("up"));
    163         buttons.add(createButton("<<"));
    164307        buttons.add(createButton("<"));
    165308        buttons.add(createButton(">"));
    166         buttons.add(createButton(">>"));
    167309        buttons.add(downButton = createButton("down"));
    168310        upButton.setEnabled(false);
    169311        downButton.setEnabled(false);
     
    179321                return new Dimension(l.width+b.width+10+r.width,l.height+b.height+10+r.height);
    180322            }
    181323            public Dimension preferredLayoutSize(Container parent) {
    182                 Dimension l = left.getPreferredSize();
    183                 Dimension r = right.getPreferredSize();
     324                Dimension l = new Dimension(200, 200); //left.getPreferredSize();
     325                Dimension r = new Dimension(200, 200); //right.getPreferredSize();
    184326                return new Dimension(l.width+r.width+10+buttons.getPreferredSize().width,Math.max(l.height, r.height));
    185327            }
    186328            public void layoutContainer(Container parent) {
     
    200342                tr("Customize the elements on the toolbar."), false);
    201343        panel.add(p, GBC.eol().fill(GBC.BOTH));
    202344
     345        selected.removeAllElements();
    203346        for (String s : getToolString()) {
    204347            if (s.equals("|"))
    205348                selected.addElement(null);
    206349            else {
    207                 Action a = actions.get(s);
    208                 if (a != null) {
    209                     selected.addElement(a);
    210                     unselected.removeElement(a);
     350                if (actions.get(s) != null) {
     351                    selected.addElement(s);
     352                }
     353            }
     354        }
     355    }
     356   
     357    private void loadAction(DefaultMutableTreeNode node, MenuElement menu) {
     358        Object userObject = null;
     359        MenuElement menuElement = menu;
     360        if (menu.getSubElements().length > 0 &&
     361                menu.getSubElements()[0] instanceof JPopupMenu) {
     362            menuElement = menu.getSubElements()[0];
     363        }
     364        for (MenuElement item : menuElement.getSubElements()) {
     365            if (item instanceof JMenuItem) {
     366                JMenuItem menuItem = ((JMenuItem)item);
     367                if (menuItem.getAction() != null) {
     368                    Action action = menuItem.getAction();
     369                    userObject = action;
     370                    actions.put((String) action.getValue("toolbar"), action);
     371                } else {
     372                    userObject = menuItem.getText();
    211373                }
    212374            }
     375            DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(userObject);
     376            node.add(newNode);
     377            loadAction(newNode, item);
    213378        }
    214379    }
    215380
     381    private void loadActions() {
     382        rootActionsNode.removeAllChildren();
     383        loadAction(rootActionsNode, Main.main.menu);
     384        rootActionsNode.add(new DefaultMutableTreeNode(null));
     385        actionsTree.updateUI();
     386        actionsTree.setRootVisible(false);
     387        actionsTree.expandPath(new TreePath(rootActionsNode));
     388    }
     389
    216390    private String[] getToolString() {
    217         String s = Main.pref.get("toolbar", "open;save;exportgpx;|;download;upload;|;undo;redo;|;preference");
     391        String s = Main.pref.get("toolbar",
     392                "open;save;exportgpx;|;download;upload;|;undo;redo;|;preference");
    218393        if (s == null || s.equals("null") || s.equals(""))
    219394            return new String[0];
    220395        return s.split(";");
     
    239414            if (selected.get(i) == null)
    240415                b.append("|");
    241416            else
    242                 b.append(((Action)selected.get(i)).getValue("toolbar"));
     417                b.append((actions.get(selected.get(i))).getValue("toolbar"));
    243418            b.append(";");
    244419        }
    245420        String s = b.toString();
     
    256431     * @return The parameter (for better chaining)
    257432     */
    258433    public Action register(Action action) {
    259         actions.put((String)action.getValue("toolbar"), action);
     434//        actions.put((String) action.getValue("toolbar"), action);
    260435        return action;
    261436    }
    262437
     
    267442     * the toolbar content (e.g. after registering actions in a plugin)
    268443     */
    269444    public void refreshToolbarControl() {
     445        loadActions();
    270446        control.removeAll();
    271447        for (String s : getToolString()) {
    272448            if (s.equals("|"))
     
    276452        }
    277453        control.setVisible(control.getComponentCount() != 0);
    278454    }
    279 }
     455
     456    private static DataFlavor ACTION_FLAVOR = new DataFlavor(
     457            AbstractAction.class, "ActionItem");
     458   
     459    private class ActionTransferable implements Transferable {
     460       
     461        private DataFlavor[] flavors = new DataFlavor[] { ACTION_FLAVOR };
     462       
     463        private Object[] actions;
     464       
     465        public ActionTransferable(Action action) {
     466            this.actions = new Action[] { action };
     467        }
     468       
     469        public ActionTransferable(Object[] actions) {
     470            this.actions = actions;
     471        }
     472
     473        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
     474            return actions;
     475        }
     476
     477        public DataFlavor[] getTransferDataFlavors() {
     478            return flavors;
     479        }
     480
     481        public boolean isDataFlavorSupported(DataFlavor flavor) {
     482            return flavors[0] == flavor;
     483        }
     484    }
     485 }