Package org.rssowl.ui.internal.undo

Source Code of org.rssowl.ui.internal.undo.UndoStack

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2009 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.ui.internal.undo;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Display;
import org.rssowl.core.internal.InternalOwl;
import org.rssowl.core.util.LoggingSafeRunnable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* The {@link UndoStack} keeps a list of {@link IUndoOperation} and supports
* undo/redo of these. The stack has a maximum capacity as defined by
* <code>MAX_SIZE</code>.
*
* @author bpasero
*/
public class UndoStack {
  private static final int MAX_SIZE = 20;
  private static UndoStack singleton = new UndoStack();

  private final List<IUndoOperation> fOperations = Collections.synchronizedList(new ArrayList<IUndoOperation>());
  private int fCurrentIndex = 0;
  private final List<IUndoRedoListener> fListeners = new ArrayList<IUndoRedoListener>();

  private UndoStack() {}

  /**
   * @return the singleton instance of the {@link UndoStack}.
   */
  public static UndoStack getInstance() {
    if (singleton == null)
      singleton = new UndoStack();

    return singleton;
  }

  /**
   * Clears all Operations from the Stack.
   */
  public void clear() {
    fOperations.clear();
  }

  /**
   * @param listener the listener to be notified when Undo or Redo was
   * performed, or when an operation was added to the stack.
   */
  public void addListener(IUndoRedoListener listener) {
    if (!fListeners.contains(listener))
      fListeners.add(listener);
  }

  /**
   * @param listener the listener to remove from the list of listeners.
   */
  public void removeListener(IUndoRedoListener listener) {
    fListeners.remove(listener);
  }

  /**
   * Adds the given operation to the stack.
   *
   * @param operation the operation to add to the stack.
   */
  public synchronized void addOperation(IUndoOperation operation) {
    Assert.isNotNull(operation);

    /* Handle case where User executed Undo-Operation */
    if (fCurrentIndex < (fOperations.size() - 1)) {

      /* Remove all following Undo-Operations */
      List<IUndoOperation> toDelete = new ArrayList<IUndoOperation>();
      for (int i = fCurrentIndex + 1; i < fOperations.size(); i++)
        toDelete.add(fOperations.get(i));

      fOperations.removeAll(toDelete);
    }

    /* Add operation and constrain size */
    fOperations.add(operation);
    if (fOperations.size() > MAX_SIZE) {
      List<IUndoOperation> toDelete = new ArrayList<IUndoOperation>();
      for (int i = 0; i < fOperations.size() - MAX_SIZE; i++)
        toDelete.add(fOperations.get(i));

      fOperations.removeAll(toDelete);
    }

    /* Set pointer to last element */
    fCurrentIndex = fOperations.size() - 1;

    /* Notify Listeners */
    notifyOperationAdded();
  }

  /**
   * @return Returns the name for the next undo-operation or a generic one if
   * undo is not supported currently.
   */
  public String getUndoName() {
    if (!isUndoSupported())
      return Messages.UndoStack_UNDO;

    return NLS.bind(Messages.UndoStack_UNDO_N, fOperations.get(fCurrentIndex).getName());
  }

  /**
   * @return Returns the name for the next redo-operation or a generic one if
   * redo is not supported currently.
   */
  public String getRedoName() {
    if (!isRedoSupported())
      return Messages.UndoStack_REDO;

    return NLS.bind(Messages.UndoStack_REDO_N, fOperations.get(fCurrentIndex + 1).getName());
  }

  /**
   * @return Returns <code>true</code> if undo is supported and
   * <code>false</code> otherwise.
   */
  public boolean isUndoSupported() {
    return fCurrentIndex >= 0 && !fOperations.isEmpty();
  }

  /**
   * @return Returns <code>true</code> if redo is supported and
   * <code>false</code> otherwise.
   */
  public boolean isRedoSupported() {
    return fCurrentIndex < (fOperations.size() - 1);
  }

  /**
   * Navigates backwards in the list of operations if possible and undos the
   * operation.
   */
  public synchronized void undo() {
    if (!isUndoSupported())
      return;

    final IUndoOperation undoOperation = fOperations.get(fCurrentIndex);
    Runnable undoRunnable = new Runnable() {
      public void run() {
        undoOperation.undo();
      }
    };

    if (undoOperation.isLongRunning() && !InternalOwl.TESTING)
      BusyIndicator.showWhile(Display.getDefault(), undoRunnable);
    else
      undoRunnable.run();

    fCurrentIndex--;
    notifyUndoPerformed();
  }

  /**
   * Navigates forwards in the list of operations if possible and redos the
   * operation.
   */
  public synchronized void redo() {
    if (!isRedoSupported())
      return;

    fCurrentIndex++;

    final IUndoOperation redoOperation = fOperations.get(fCurrentIndex);
    Runnable redoRunnable = new Runnable() {
      public void run() {
        redoOperation.redo();
      }
    };

    if (redoOperation.isLongRunning() && !InternalOwl.TESTING)
      BusyIndicator.showWhile(Display.getDefault(), redoRunnable);
    else
      redoRunnable.run();

    notifyRedoPerformed();
  }

  private void notifyUndoPerformed() {
    for (final IUndoRedoListener listener : fListeners) {
      SafeRunnable.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          listener.undoPerformed();
        }
      });
    }
  }

  private void notifyRedoPerformed() {
    for (final IUndoRedoListener listener : fListeners) {
      SafeRunnable.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          listener.redoPerformed();
        }
      });
    }
  }

  private void notifyOperationAdded() {
    for (final IUndoRedoListener listener : fListeners) {
      SafeRunnable.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          listener.operationAdded();
        }
      });
    }
  }
}
TOP

Related Classes of org.rssowl.ui.internal.undo.UndoStack

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.