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

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

see #8606 - Fix user-agent used with JEditorPage.setPage() or JEditorPane(URL) + fix version number from previous commit

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