source: josm/trunk/src/org/openstreetmap/josm/gui/widgets/TextContextualPopupMenu.java@ 6288

Last change on this file since 6288 was 6172, checked in by Don-vip, 11 years ago

fix #8849:

  • Used scaled down (16x16 pixels) of large (.svg) images if no size is explicitely defined
  • rendering of emergency=aed with recently added svg
  • optimizations/refactoring in icons rotating/rescaling code
  • fix of various warnings, javadoc
File size: 6.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.widgets;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.beans.PropertyChangeEvent;
8import java.beans.PropertyChangeListener;
9
10import javax.swing.AbstractAction;
11import javax.swing.Action;
12import javax.swing.ImageIcon;
13import javax.swing.JMenuItem;
14import javax.swing.JPopupMenu;
15import javax.swing.event.UndoableEditEvent;
16import javax.swing.event.UndoableEditListener;
17import javax.swing.text.DefaultEditorKit;
18import javax.swing.text.JTextComponent;
19import javax.swing.undo.CannotUndoException;
20import javax.swing.undo.UndoManager;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.tools.ImageProvider;
24
25/**
26 * A popup menu designed for text components. It displays the following actions:
27 * <ul>
28 * <li>Undo</li>
29 * <li>Cut</li>
30 * <li>Copy</li>
31 * <li>Paste</li>
32 * <li>Delete</li>
33 * <li>Select All</li>
34 * </ul>
35 * @since 5886
36 */
37public class TextContextualPopupMenu extends JPopupMenu {
38
39 protected JTextComponent component = null;
40 protected UndoAction undoAction = null;
41
42 protected final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
43 @Override public void propertyChange(PropertyChangeEvent evt) {
44 if (evt.getPropertyName().equals("editable")) {
45 removeAll();
46 addMenuEntries();
47 }
48 }
49 };
50
51 /**
52 * Creates a new {@link TextContextualPopupMenu}.
53 */
54 protected TextContextualPopupMenu() {
55 }
56
57 /**
58 * Attaches this contextual menu to the given text component.
59 * A menu can only be attached to a single component.
60 * @param component The text component that will display the menu and handle its actions.
61 * @return {@code this}
62 * @see #detach()
63 */
64 protected TextContextualPopupMenu attach(JTextComponent component) {
65 if (component != null && !isAttached()) {
66 this.component = component;
67 if (component.isEditable()) {
68 undoAction = new UndoAction();
69 component.getDocument().addUndoableEditListener(undoAction);
70 }
71 addMenuEntries();
72 component.addPropertyChangeListener("editable", propertyChangeListener);
73 }
74 return this;
75 }
76
77 private void addMenuEntries() {
78 if (component.isEditable()) {
79 add(new JMenuItem(undoAction));
80 addSeparator();
81 addMenuEntry(component, tr("Cut"), DefaultEditorKit.cutAction, null);
82 }
83 addMenuEntry(component, tr("Copy"), DefaultEditorKit.copyAction, "copy");
84 if (component.isEditable()) {
85 addMenuEntry(component, tr("Paste"), DefaultEditorKit.pasteAction, "paste");
86 addMenuEntry(component, tr("Delete"), DefaultEditorKit.deleteNextCharAction, null);
87 }
88 addSeparator();
89 addMenuEntry(component, tr("Select All"), DefaultEditorKit.selectAllAction, null);
90 }
91
92 /**
93 * Detaches this contextual menu from its text component.
94 * @return {@code this}
95 * @see #attach(JTextComponent)
96 */
97 protected TextContextualPopupMenu detach() {
98 if (isAttached()) {
99 component.removePropertyChangeListener("editable", propertyChangeListener);
100 removeAll();
101 if (undoAction != null) {
102 component.getDocument().removeUndoableEditListener(undoAction);
103 undoAction = null;
104 }
105 this.component = null;
106 }
107 return this;
108 }
109
110 /**
111 * Creates a new {@link TextContextualPopupMenu} and enables it for the given text component.
112 * @param component The component that will display the menu and handle its actions.
113 * @return The {@link PopupMenuLauncher} responsible of displaying the popup menu.
114 * Call {@link #disableMenuFor} with this object if you want to disable the menu later.
115 * @see #disableMenuFor(JTextComponent, PopupMenuLauncher)
116 */
117 public static PopupMenuLauncher enableMenuFor(JTextComponent component) {
118 PopupMenuLauncher launcher = new PopupMenuLauncher(new TextContextualPopupMenu().attach(component), true);
119 component.addMouseListener(launcher);
120 return launcher;
121 }
122
123 /**
124 * Disables the {@link TextContextualPopupMenu} attached to the given popup menu launcher and text component.
125 * @param component The component that currently displays the menu and handles its actions.
126 * @param launcher The {@link PopupMenuLauncher} obtained via {@link #enableMenuFor}.
127 * @see #enableMenuFor(JTextComponent)
128 */
129 public static void disableMenuFor(JTextComponent component, PopupMenuLauncher launcher) {
130 if (launcher.getMenu() instanceof TextContextualPopupMenu) {
131 ((TextContextualPopupMenu) launcher.getMenu()).detach();
132 component.removeMouseListener(launcher);
133 }
134 }
135
136 /**
137 * Determines if this popup is currently attached to a component.
138 * @return {@code true} if this popup is currently attached to a component, {@code false} otherwise.
139 */
140 public final boolean isAttached() {
141 return component != null;
142 }
143
144 protected void addMenuEntry(JTextComponent component, String label, String actionName, String iconName) {
145 Action action = component.getActionMap().get(actionName);
146 if (action != null) {
147 JMenuItem mi = new JMenuItem(action);
148 mi.setText(label);
149 if (iconName != null && Main.pref.getBoolean("text.popupmenu.useicons", true)) {
150 ImageIcon icon = new ImageProvider(iconName).setWidth(16).get();
151 if (icon != null) {
152 mi.setIcon(icon);
153 }
154 }
155 add(mi);
156 }
157 }
158
159 protected class UndoAction extends AbstractAction implements UndoableEditListener {
160
161 private final UndoManager undoManager = new UndoManager();
162
163 public UndoAction() {
164 super(tr("Undo"));
165 setEnabled(false);
166 }
167
168 @Override
169 public void undoableEditHappened(UndoableEditEvent e) {
170 undoManager.addEdit(e.getEdit());
171 setEnabled(undoManager.canUndo());
172 }
173
174 @Override
175 public void actionPerformed(ActionEvent e) {
176 try {
177 undoManager.undo();
178 } catch (CannotUndoException ex) {
179 // Ignored
180 } finally {
181 setEnabled(undoManager.canUndo());
182 }
183 }
184 }
185}
Note: See TracBrowser for help on using the repository browser.