All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zaproxy.zap.utils.ZapTextComponentUndoManager Maven / Gradle / Ivy

/*
 * Zed Attack Proxy (ZAP) and its related class files.
 *
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 *
 * Copyright 2012 The ZAP Development Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.zaproxy.zap.utils;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import org.parosproxy.paros.Constant;

/**
 * {@code ZapTextComponentUndoManager} manages a list of {@code UndoableEdit}s, providing a way to
 * undo or redo the appropriate edits with undo and redo actions accessible through {@code
 * KeyStroke}s created with {@code Constant.ACCELERATOR_UNDO} and {@code Constant.ACCELERATOR_REDO},
 * respectively.
 *
 * 

The default is to maintain a window of 100 undoable edits. When the limit is reached older * undoable edits start to be discarded when new ones are saved. The limit can be changed with the * method {@code setLimit(int)}. * *

There are three policies that affect if, and when, the undoable edits are saved: * *

    *
  • {@code UndoManagerPolicy.DEFAULT} *
  • {@code UndoManagerPolicy.ALWAYS_ENABLED} *
  • {@code UndoManagerPolicy.ALWAYS_DISABLED} *
* * The policy can be changed with the method {@code setUndoManagerPolicy}. * *

The {@code ZapTextComponentUndoManager} listens to changes to the {@code Document} of the * {@code JTextComponent} used with the {@code ZapTextComponentUndoManager}, so there is no need to * do anything if the document is changed. * * @since 1.4.1 * @see #setLimit(int) * @see #setUndoManagerPolicy(UndoManagerPolicy) * @see UndoManagerPolicy * @see UndoManager */ public class ZapTextComponentUndoManager extends UndoManager implements PropertyChangeListener { /** * There are three policies that affect if, and when, the undoable edits are saved: * *

    *
  • {@code UndoManagerPolicy.DEFAULT} *
  • {@code UndoManagerPolicy.ALWAYS_ENABLED} *
  • {@code UndoManagerPolicy.ALWAYS_DISABLED} *
* * @see #DEFAULT * @see #ALWAYS_ENABLED * @see #ALWAYS_DISABLED */ public enum UndoManagerPolicy { /** * The undoable edits are saved exactly when the {@code JTextComponent} is enabled and * editable. * *

The {@code ZapTextComponentUndoManager} listens to the changes in the properties * "enabled" and "editable", so that can change accordingly to save or not the undoable * edits. */ DEFAULT, /** * The undoable edits are always saved, even if the {@code JTextComponent} is not editable * and/or enabled. */ ALWAYS_ENABLED, /** The undoable edits are not saved. */ ALWAYS_DISABLED }; private static final long serialVersionUID = -5728632360771625298L; private final JTextComponent textComponent; private final UndoAction undoAction; private final RedoAction redoAction; private boolean enabled; private UndoManagerPolicy policy; /** * Creates a new {@code ZapTextComponentUndoManager} with a {@code DEFAULT} policy. * * @param textComponent the {@code JTextComponent} that will have undoable edits. * @throws NullPointerException if textComponent is {@code null}. * @see UndoManagerPolicy#DEFAULT */ public ZapTextComponentUndoManager(JTextComponent textComponent) { super(); if (textComponent == null) { throw new NullPointerException("The textComponent must not be null."); } this.textComponent = textComponent; this.undoAction = new UndoAction(this); this.redoAction = new RedoAction(this); this.enabled = false; this.policy = null; setUndoManagerPolicy(UndoManagerPolicy.DEFAULT); } /** * Sets the new policy. * * @param policy the new policy * @throws NullPointerException if policy is {@code null} * @see UndoManagerPolicy */ public final void setUndoManagerPolicy(UndoManagerPolicy policy) throws NullPointerException { if (policy == null) { throw new NullPointerException("The policy must not be null."); } if (this.policy == policy) { return; } final UndoManagerPolicy oldPolicy = this.policy; this.policy = policy; if (oldPolicy == UndoManagerPolicy.DEFAULT) { this.textComponent.removePropertyChangeListener("editable", this); this.textComponent.removePropertyChangeListener("enabled", this); } if (this.policy == UndoManagerPolicy.DEFAULT) { this.textComponent.addPropertyChangeListener("editable", this); this.textComponent.addPropertyChangeListener("enabled", this); } handleUndoManagerPolicy(); } @Override public void propertyChange(PropertyChangeEvent evt) { final String propertyName = evt.getPropertyName(); if ("document".equals(propertyName)) { if (this.enabled) { ((Document) evt.getOldValue()).removeUndoableEditListener(this); ((Document) evt.getNewValue()).addUndoableEditListener(this); if (policy == UndoManagerPolicy.DEFAULT) { handleUndoManagerDefaultPolicy(); } } } else if (policy == UndoManagerPolicy.DEFAULT && ("editable".equals(propertyName) || "enabled".equals(propertyName))) { handleUndoManagerDefaultPolicy(); } } private void setEnabled(boolean enabled) { if (enabled != this.enabled) { this.enabled = enabled; if (enabled) { this.textComponent.addPropertyChangeListener("document", this); this.textComponent.getDocument().addUndoableEditListener(this); this.textComponent.getActionMap().put(UndoAction.ACTION_NAME, undoAction); this.textComponent.getActionMap().put(RedoAction.ACTION_NAME, redoAction); this.textComponent.getInputMap().put(UndoAction.KEY_STROKE, UndoAction.ACTION_NAME); this.textComponent.getInputMap().put(RedoAction.KEY_STROKE, RedoAction.ACTION_NAME); } else { this.textComponent.removePropertyChangeListener("document", this); this.textComponent.getDocument().removeUndoableEditListener(this); this.textComponent.getActionMap().remove(UndoAction.ACTION_NAME); this.textComponent.getActionMap().remove(RedoAction.ACTION_NAME); this.textComponent.getInputMap().remove(UndoAction.KEY_STROKE); this.textComponent.getInputMap().remove(RedoAction.KEY_STROKE); } } } private void handleUndoManagerPolicy() { switch (policy) { case ALWAYS_DISABLED: this.setEnabled(false); break; case ALWAYS_ENABLED: this.setEnabled(true); break; case DEFAULT: default: handleUndoManagerDefaultPolicy(); } } private void handleUndoManagerDefaultPolicy() { this.setEnabled(this.textComponent.isEditable() && this.textComponent.isEnabled()); } private static final class UndoAction extends AbstractAction { private static final long serialVersionUID = 6681683056944213164L; public static final String ACTION_NAME = "Undo"; public static final KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(Constant.ACCELERATOR_UNDO); private UndoManager undoManager; public UndoAction(UndoManager undoManager) { super(ACTION_NAME); this.undoManager = undoManager; } @Override public void actionPerformed(ActionEvent evt) { try { if (undoManager.canUndo()) { undoManager.undo(); } } catch (CannotUndoException e) { } } } private static final class RedoAction extends AbstractAction { private static final long serialVersionUID = -7098526742716575130L; public static final String ACTION_NAME = "Redo"; public static final KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(Constant.ACCELERATOR_REDO); private UndoManager undoManager; public RedoAction(UndoManager undoManager) { super(ACTION_NAME); this.undoManager = undoManager; } @Override public void actionPerformed(ActionEvent evt) { try { if (undoManager.canRedo()) { undoManager.redo(); } } catch (CannotRedoException e) { } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy