Package org.openstreetmap.josm.gui.widgets

Source Code of org.openstreetmap.josm.gui.widgets.TextContextualPopupMenu$UndoAction

// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.widgets;

import static org.openstreetmap.josm.tools.I18n.tr;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.tools.ImageProvider;

/**
* A popup menu designed for text components. It displays the following actions:
* <ul>
* <li>Undo</li>
* <li>Cut</li>
* <li>Copy</li>
* <li>Paste</li>
* <li>Delete</li>
* <li>Select All</li>
* </ul>
* @since 5886
*/
public class TextContextualPopupMenu extends JPopupMenu {

    protected JTextComponent component = null;
    protected UndoAction undoAction = null;

    protected final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
        @Override public void propertyChange(PropertyChangeEvent evt) {
            if ("editable".equals(evt.getPropertyName())) {
                removeAll();
                addMenuEntries();
            }
        }
    };

    /**
     * Creates a new {@link TextContextualPopupMenu}.
     */
    protected TextContextualPopupMenu() {
    }

    /**
     * Attaches this contextual menu to the given text component.
     * A menu can only be attached to a single component.
     * @param component The text component that will display the menu and handle its actions.
     * @return {@code this}
     * @see #detach()
     */
    protected TextContextualPopupMenu attach(JTextComponent component) {
        if (component != null && !isAttached()) {
            this.component = component;
            if (component.isEditable()) {
                undoAction = new UndoAction();
                component.getDocument().addUndoableEditListener(undoAction);
            }
            addMenuEntries();
            component.addPropertyChangeListener("editable", propertyChangeListener);
        }
        return this;
    }

    private void addMenuEntries() {
        if (component.isEditable()) {
            add(new JMenuItem(undoAction));
            addSeparator();
            addMenuEntry(component, tr("Cut"), DefaultEditorKit.cutAction, null);
        }
        addMenuEntry(component, tr("Copy"), DefaultEditorKit.copyAction, "copy");
        if (component.isEditable()) {
            addMenuEntry(component, tr("Paste"), DefaultEditorKit.pasteAction, "paste");
            addMenuEntry(component, tr("Delete"), DefaultEditorKit.deleteNextCharAction, null);
        }
        addSeparator();
        addMenuEntry(component, tr("Select All"), DefaultEditorKit.selectAllAction, null);
    }

    /**
     * Detaches this contextual menu from its text component.
     * @return {@code this}
     * @see #attach(JTextComponent)
     */
    protected TextContextualPopupMenu detach() {
        if (isAttached()) {
            component.removePropertyChangeListener("editable", propertyChangeListener);
            removeAll();
            if (undoAction != null) {
                component.getDocument().removeUndoableEditListener(undoAction);
                undoAction = null;
            }
            this.component = null;
        }
        return this;
    }

    /**
     * Creates a new {@link TextContextualPopupMenu} and enables it for the given text component.
     * @param component The component that will display the menu and handle its actions.
     * @return The {@link PopupMenuLauncher} responsible of displaying the popup menu.
     *         Call {@link #disableMenuFor} with this object if you want to disable the menu later.
     * @see #disableMenuFor(JTextComponent, PopupMenuLauncher)
     */
    public static PopupMenuLauncher enableMenuFor(JTextComponent component) {
        PopupMenuLauncher launcher = new PopupMenuLauncher(new TextContextualPopupMenu().attach(component), true);
        component.addMouseListener(launcher);
        return launcher;
    }

    /**
     * Disables the {@link TextContextualPopupMenu} attached to the given popup menu launcher and text component.
     * @param component The component that currently displays the menu and handles its actions.
     * @param launcher The {@link PopupMenuLauncher} obtained via {@link #enableMenuFor}.
     * @see #enableMenuFor(JTextComponent)
     */
    public static void disableMenuFor(JTextComponent component, PopupMenuLauncher launcher) {
        if (launcher.getMenu() instanceof TextContextualPopupMenu) {
            ((TextContextualPopupMenu) launcher.getMenu()).detach();
            component.removeMouseListener(launcher);
        }
    }

    /**
     * Determines if this popup is currently attached to a component.
     * @return {@code true} if this popup is currently attached to a component, {@code false} otherwise.
     */
    public final boolean isAttached() {
        return component != null;
    }

    protected void addMenuEntry(JTextComponent component,  String label, String actionName, String iconName) {
        Action action = component.getActionMap().get(actionName);
        if (action != null) {
            JMenuItem mi = new JMenuItem(action);
            mi.setText(label);
            if (iconName != null && Main.pref.getBoolean("text.popupmenu.useicons", true)) {
                ImageIcon icon = new ImageProvider(iconName).setWidth(16).get();
                if (icon != null) {
                    mi.setIcon(icon);
                }
            }
            add(mi);
        }
    }

    protected static class UndoAction extends AbstractAction implements UndoableEditListener {

        private final UndoManager undoManager = new UndoManager();

        public UndoAction() {
            super(tr("Undo"));
            setEnabled(false);
        }

        @Override
        public void undoableEditHappened(UndoableEditEvent e) {
            undoManager.addEdit(e.getEdit());
            setEnabled(undoManager.canUndo());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                undoManager.undo();
            } catch (CannotUndoException ex) {
                // Ignored
            } finally {
                setEnabled(undoManager.canUndo());
            }
        }
    }
}
TOP

Related Classes of org.openstreetmap.josm.gui.widgets.TextContextualPopupMenu$UndoAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.