source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java@ 1343

Last change on this file since 1343 was 1343, checked in by stoecker, 15 years ago

java 1.5 patch

  • Property svn:eol-style set to native
File size: 18.7 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.preferences;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Container;
8import java.awt.Dimension;
9import java.awt.GridBagLayout;
10import java.awt.GridLayout;
11import java.awt.LayoutManager;
12import java.awt.Rectangle;
13import java.awt.datatransfer.DataFlavor;
14import java.awt.datatransfer.Transferable;
15import java.awt.datatransfer.UnsupportedFlavorException;
16import java.awt.event.ActionEvent;
17import java.awt.event.ActionListener;
18import java.awt.event.InputEvent;
19import java.io.IOException;
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.HashMap;
23import java.util.LinkedList;
24import java.util.List;
25import java.util.Map;
26
27import javax.swing.AbstractAction;
28import javax.swing.Action;
29import javax.swing.DefaultListCellRenderer;
30import javax.swing.DefaultListModel;
31import javax.swing.Icon;
32import javax.swing.JButton;
33import javax.swing.JComponent;
34import javax.swing.JLabel;
35import javax.swing.JList;
36import javax.swing.JMenuItem;
37import javax.swing.JPanel;
38import javax.swing.JPopupMenu;
39import javax.swing.JScrollPane;
40import javax.swing.JToolBar;
41import javax.swing.JTree;
42import javax.swing.ListCellRenderer;
43import javax.swing.MenuElement;
44import javax.swing.TransferHandler;
45import javax.swing.event.ListSelectionEvent;
46import javax.swing.event.ListSelectionListener;
47import javax.swing.tree.DefaultMutableTreeNode;
48import javax.swing.tree.DefaultTreeCellRenderer;
49import javax.swing.tree.DefaultTreeModel;
50import javax.swing.tree.TreePath;
51
52import org.openstreetmap.josm.Main;
53import org.openstreetmap.josm.tools.GBC;
54import org.openstreetmap.josm.tools.ImageProvider;
55
56public class ToolbarPreferences implements PreferenceSetting {
57
58 private final class Move implements ActionListener {
59 public void actionPerformed(ActionEvent e) {
60 if (e.getActionCommand().equals("<") && actionsTree.getSelectionCount() > 0) {
61
62 int leadItem = selected.getSize();
63 if (selectedList.getSelectedIndex() != -1) {
64 int[] indices = selectedList.getSelectedIndices();
65 leadItem = indices[indices.length - 1];
66 }
67 for (TreePath selectedAction : actionsTree.getSelectionPaths()) {
68 DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedAction.getLastPathComponent();
69 if (node.getUserObject() == null || node.getUserObject() instanceof Action) {
70 selected.add(leadItem++, ((Action)node.getUserObject()).getValue("toolbar"));
71 }
72 }
73 } else if (e.getActionCommand().equals(">") && selectedList.getSelectedIndex() != -1) {
74 while (selectedList.getSelectedIndex() != -1) {
75 selected.remove(selectedList.getSelectedIndex());
76 }
77 } else if (e.getActionCommand().equals("up")) {
78 int i = selectedList.getSelectedIndex();
79 Object o = selected.get(i);
80 if (i != 0) {
81 selected.remove(i);
82 selected.add(i-1, o);
83 selectedList.setSelectedIndex(i-1);
84 }
85 } else if (e.getActionCommand().equals("down")) {
86 int i = selectedList.getSelectedIndex();
87 Object o = selected.get(i);
88 if (i != selected.size()-1) {
89 selected.remove(i);
90 selected.add(i+1, o);
91 selectedList.setSelectedIndex(i+1);
92 }
93 }
94 }
95 }
96 private Move moveAction = new Move();
97
98 /**
99 * Key: Registered name (property "toolbar" of action).
100 * Value: The action to execute.
101 */
102 private Map<String, Action> actions = new HashMap<String, Action>();
103
104 private DefaultListModel selected = new DefaultListModel();
105
106 private DefaultMutableTreeNode rootActionsNode = new DefaultMutableTreeNode("Actions");
107 private DefaultTreeModel actionsTreeModel = new DefaultTreeModel(rootActionsNode);
108 private JTree actionsTree = new JTree(actionsTreeModel);
109 private JList selectedList = new JList(selected);
110
111 private String movingComponent;
112
113 public JToolBar control = new JToolBar();
114
115 private JButton upButton;
116 private JButton downButton;
117
118 public ToolbarPreferences() {
119 control.setFloatable(false);
120
121 actionsTree.setCellRenderer(new DefaultTreeCellRenderer() {
122 @Override
123 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
124 boolean leaf, int row, boolean hasFocus) {
125 DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
126 JLabel comp = (JLabel) super.getTreeCellRendererComponent(
127 tree, value, sel, expanded, leaf, row, hasFocus);
128 if (node.getUserObject() == null) {
129 comp.setText(tr("Separator"));
130 comp.setIcon(ImageProvider.get("preferences/separator"));
131 }
132 else if (node.getUserObject() instanceof Action) {
133 Action action = (Action) node.getUserObject();
134 comp.setText((String) action.getValue(Action.NAME));
135 comp.setIcon((Icon) action.getValue(Action.SMALL_ICON));
136 }
137 return comp;
138 }
139 });
140
141 ListCellRenderer renderer = new DefaultListCellRenderer(){
142 @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
143 String s;
144 Icon i;
145 if (value != null) {
146 Action action = actions.get(value);
147 s = (String) action.getValue(Action.NAME);
148 i = (Icon) action.getValue(Action.SMALL_ICON);
149 } else {
150 i = ImageProvider.get("preferences/separator");
151 s = tr("Separator");
152 }
153 JLabel l = (JLabel)super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
154 l.setIcon(i);
155 return l;
156 }
157 };
158 selectedList.setCellRenderer(renderer);
159 selectedList.addListSelectionListener(new ListSelectionListener(){
160 public void valueChanged(ListSelectionEvent e) {
161 boolean sel = selectedList.getSelectedIndex() != -1;
162 if (sel)
163 actionsTree.clearSelection();
164 upButton.setEnabled(sel);
165 downButton.setEnabled(sel);
166 }
167 });
168
169 selectedList.setDragEnabled(true);
170 selectedList.setTransferHandler(new TransferHandler() {
171 @Override
172 protected Transferable createTransferable(JComponent c) {
173 return new ActionTransferable(((JList)c).getSelectedValues());
174 }
175
176 @Override
177 public int getSourceActions(JComponent c) {
178 return TransferHandler.MOVE;
179 }
180
181 @Override
182 public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
183 for (DataFlavor f : transferFlavors) {
184 if (ACTION_FLAVOR.equals(f)) {
185 return true;
186 }
187 }
188 return false;
189 }
190
191 @Override
192 public void exportAsDrag(JComponent comp, InputEvent e, int action) {
193 super.exportAsDrag(comp, e, action);
194 movingComponent = "list";
195 }
196
197 @Override
198 public boolean importData(JComponent comp, Transferable t) {
199 try {
200 int dropIndex = selectedList.locationToIndex(selectedList.getMousePosition(true));
201 Object[] draggedData = (Object[]) t.getTransferData(ACTION_FLAVOR);
202
203 Object leadItem = dropIndex >= 0 ? selected.elementAt(dropIndex) : null;
204 int dataLength = draggedData.length;
205
206 if (leadItem != null)
207 for (int i = 0; i < dataLength; i++)
208 if (leadItem.equals(draggedData[i]))
209 return false;
210
211 int dragLeadIndex = -1;
212 boolean localDrop = "list".equals(movingComponent);
213
214 if (localDrop) {
215 dragLeadIndex = selected.indexOf(draggedData[0]);
216 for (int i = 0; i < dataLength; i++)
217 selected.removeElement(draggedData[i]);
218 }
219 int[] indices = new int[dataLength];
220
221 if (localDrop) {
222 int adjustedLeadIndex = selected.indexOf(leadItem);
223 int insertionAdjustment = dragLeadIndex <= adjustedLeadIndex ? 1 : 0;
224 for (int i = 0; i < dataLength; i++) {
225 selected.insertElementAt(draggedData[i], adjustedLeadIndex + insertionAdjustment + i);
226 indices[i] = adjustedLeadIndex + insertionAdjustment + i;
227 }
228 } else {
229 for (int i = 0; i < dataLength; i++) {
230 selected.add(dropIndex, draggedData[i]);
231 indices[i] = dropIndex + i;
232 }
233 }
234 selectedList.clearSelection();
235 selectedList.setSelectedIndices(indices);
236 movingComponent = "";
237 return true;
238 } catch (Exception e) {
239 e.printStackTrace();
240 }
241 return false;
242 }
243
244 @Override
245 protected void exportDone(JComponent source, Transferable data, int action) {
246 if (movingComponent.equals("list")) {
247 try {
248 Object[] draggedData = (Object[]) data.getTransferData(ACTION_FLAVOR);
249 boolean localDrop = selected.contains(draggedData[0]);
250 if (localDrop) {
251 int[] indices = selectedList.getSelectedIndices();
252 Arrays.sort(indices);
253 for (int i = indices.length - 1; i >= 0; i--) {
254 selected.remove(indices[i]);
255 }
256 }
257 } catch (Exception e) {
258 e.printStackTrace();
259 }
260 movingComponent = "";
261 }
262 }
263 });
264
265 actionsTree.setTransferHandler(new TransferHandler() {
266 private static final long serialVersionUID = 1L;
267
268 @Override
269 public int getSourceActions( JComponent c ){
270 return TransferHandler.MOVE;
271 }
272
273 @Override
274 protected void exportDone(JComponent source, Transferable data, int action) {
275 }
276
277 @Override
278 protected Transferable createTransferable(JComponent c) {
279 TreePath[] paths = actionsTree.getSelectionPaths();
280 List<String> dragActions = new LinkedList<String>();
281 for (TreePath path : paths) {
282 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
283 Object obj = node.getUserObject();
284 if (obj == null) {
285 dragActions.add(null);
286 }
287 else if (obj instanceof Action) {
288 dragActions.add((String) ((Action) obj).getValue("toolbar"));
289 }
290 }
291 return new ActionTransferable(dragActions.toArray());
292 }
293 });
294 actionsTree.setDragEnabled(true);
295 }
296
297 public void addGui(PreferenceDialog gui) {
298 final JPanel left = new JPanel(new GridBagLayout());
299 left.add(new JLabel(tr("Toolbar")), GBC.eol());
300 left.add(new JScrollPane(selectedList), GBC.std().fill(GBC.BOTH));
301
302 final JPanel right = new JPanel(new GridBagLayout());
303 right.add(new JLabel(tr("Available")), GBC.eol());
304 right.add(new JScrollPane(actionsTree), GBC.eol().fill(GBC.BOTH));
305
306 final JPanel buttons = new JPanel(new GridLayout(6,1));
307 buttons.add(upButton = createButton("up"));
308 buttons.add(createButton("<"));
309 buttons.add(createButton(">"));
310 buttons.add(downButton = createButton("down"));
311 upButton.setEnabled(false);
312 downButton.setEnabled(false);
313
314 final JPanel p = new JPanel();
315 p.setLayout(new LayoutManager(){
316 public void addLayoutComponent(String name, Component comp) {}
317 public void removeLayoutComponent(Component comp) {}
318 public Dimension minimumLayoutSize(Container parent) {
319 Dimension l = left.getMinimumSize();
320 Dimension r = right.getMinimumSize();
321 Dimension b = buttons.getMinimumSize();
322 return new Dimension(l.width+b.width+10+r.width,l.height+b.height+10+r.height);
323 }
324 public Dimension preferredLayoutSize(Container parent) {
325 Dimension l = new Dimension(200, 200); //left.getPreferredSize();
326 Dimension r = new Dimension(200, 200); //right.getPreferredSize();
327 return new Dimension(l.width+r.width+10+buttons.getPreferredSize().width,Math.max(l.height, r.height));
328 }
329 public void layoutContainer(Container parent) {
330 Dimension d = p.getSize();
331 Dimension b = buttons.getPreferredSize();
332 int width = (d.width-10-b.width)/2;
333 left.setBounds(new Rectangle(0,0,width,d.height));
334 right.setBounds(new Rectangle(width+10+b.width,0,width,d.height));
335 buttons.setBounds(new Rectangle(width+5, d.height/2-b.height/2, b.width, b.height));
336 }
337 });
338 p.add(left);
339 p.add(buttons);
340 p.add(right);
341
342 JPanel panel = gui.createPreferenceTab("toolbar", tr("Toolbar customization"),
343 tr("Customize the elements on the toolbar."), false);
344 panel.add(p, GBC.eol().fill(GBC.BOTH));
345
346 selected.removeAllElements();
347 for (String s : getToolString()) {
348 if (s.equals("|"))
349 selected.addElement(null);
350 else {
351 if (actions.get(s) != null) {
352 selected.addElement(s);
353 }
354 }
355 }
356 }
357
358 private void loadAction(DefaultMutableTreeNode node, MenuElement menu) {
359 Object userObject = null;
360 MenuElement menuElement = menu;
361 if (menu.getSubElements().length > 0 &&
362 menu.getSubElements()[0] instanceof JPopupMenu) {
363 menuElement = menu.getSubElements()[0];
364 }
365 for (MenuElement item : menuElement.getSubElements()) {
366 if (item instanceof JMenuItem) {
367 JMenuItem menuItem = ((JMenuItem)item);
368 if (menuItem.getAction() != null) {
369 Action action = menuItem.getAction();
370 userObject = action;
371 actions.put((String) action.getValue("toolbar"), action);
372 } else {
373 userObject = menuItem.getText();
374 }
375 }
376 DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(userObject);
377 node.add(newNode);
378 loadAction(newNode, item);
379 }
380 }
381
382 private void loadActions() {
383 rootActionsNode.removeAllChildren();
384 loadAction(rootActionsNode, Main.main.menu);
385 rootActionsNode.add(new DefaultMutableTreeNode(null));
386 actionsTree.updateUI();
387 actionsTree.setRootVisible(false);
388 actionsTree.expandPath(new TreePath(rootActionsNode));
389 }
390
391 private static final String[] deftoolbar = {"open", "save", "exportgpx", "|",
392 "download", "upload", "|", "undo", "redo", "|", "preference"};
393 private Collection<String> getToolString() {
394 return Main.pref.getCollection("toolbar", Arrays.asList(deftoolbar));
395 }
396
397 private JButton createButton(String name) {
398 JButton b = new JButton();
399 if (name.equals("up"))
400 b.setIcon(ImageProvider.get("dialogs", "up"));
401 else if (name.equals("down"))
402 b.setIcon(ImageProvider.get("dialogs", "down"));
403 else
404 b.setText(name);
405 b.addActionListener(moveAction);
406 b.setActionCommand(name);
407 return b;
408 }
409
410 public boolean ok() {
411 Collection<String> t = new LinkedList<String>();
412 for (int i = 0; i < selected.size(); ++i) {
413 if (selected.get(i) == null)
414 t.add("|");
415 else
416 t.add((String)((actions.get(selected.get(i))).getValue("toolbar")));
417 }
418 Main.pref.putCollection("toolbar", t);
419 refreshToolbarControl();
420 return false;
421 }
422
423 /**
424 * @return The parameter (for better chaining)
425 */
426 public Action register(Action action) {
427 actions.put((String) action.getValue("toolbar"), action);
428 return action;
429 }
430
431 /**
432 * Parse the toolbar preference setting and construct the toolbar GUI control.
433 *
434 * Call this, if anything has changed in the toolbar settings and you want to refresh
435 * the toolbar content (e.g. after registering actions in a plugin)
436 */
437 public void refreshToolbarControl() {
438 loadActions();
439 control.removeAll();
440 for (String s : getToolString()) {
441 if (s.equals("|"))
442 control.addSeparator();
443 else
444 control.add(actions.get(s));
445 }
446 control.setVisible(control.getComponentCount() != 0);
447 }
448
449 private static DataFlavor ACTION_FLAVOR = new DataFlavor(
450 AbstractAction.class, "ActionItem");
451
452 private class ActionTransferable implements Transferable {
453
454 private DataFlavor[] flavors = new DataFlavor[] { ACTION_FLAVOR };
455
456 private Object[] actions;
457
458 public ActionTransferable(Action action) {
459 this.actions = new Action[] { action };
460 }
461
462 public ActionTransferable(Object[] actions) {
463 this.actions = actions;
464 }
465
466 public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
467 return actions;
468 }
469
470 public DataFlavor[] getTransferDataFlavors() {
471 return flavors;
472 }
473
474 public boolean isDataFlavorSupported(DataFlavor flavor) {
475 return flavors[0] == flavor;
476 }
477 }
478}
Note: See TracBrowser for help on using the repository browser.