【原創】命令堆疊(二十七)

阿-甘發表於2008-07-23

  在GEF框架中,通常會用到命令執行、撤銷和重複的操作,在Eclipse中,也大量地採用Command、CommandManager和ICommandListener等機制來控制命令的執行及監聽。在此將簡要介紹GEF命令堆疊(CommandStack)的執行方式,有興趣的讀者可以跟蹤Eclipse原始碼,查詢其他框架命令的執行和撤銷。

  命令堆疊(CommandStack)

  GEF框架會維護CommandStack,通過CommandStack來執行、撤銷和重複命令的操作。CommandStack中有兩個堆疊(Stack)型別的資料——undoable和redoable:通過undoable,CommandStack知道有哪些命令可以撤銷;通過redoable,CommandStack知道有哪些命令可能被重複。

  當使用者執行撤銷操作時(例如按快捷鍵【Ctrl+Z】),GEF框架會呼叫CommandStack的undo方法,執行撤銷的操作。當使用者執行重複的操作時(例如按快捷鍵【Ctrl+Y】),GEF框架會呼叫CommandStack的redo方法,執行重複的操作。undo和redo方法的程式碼片斷如以下程式碼如示。

  public void undo() {

  Command command = (Command)undoable.pop();

  notifyListeners(command, PRE_UNDO);

  try {

  command.undo();

  redoable.push(command);

  notifyListeners();

  } finally {

  notifyListeners(command, POST_UNDO);

  }

  }

  public void redo() {

  if (!canRedo())

  return;

  Command command = (Command)redoable.pop();

  notifyListeners(command, PRE_REDO);

  try {

  command.redo();

  undoable.push(command);

  notifyListeners();

  } finally {

  notifyListeners(command, POST_REDO);

  }

  }

  undo和redo方法會從相應堆疊的頂部取出命令,執行命令的undo和redo操作,然後把取出的命令放入另外一個堆疊中。通過這種機制,GEF框架能夠重複和撤銷使用者建立的命令,從而完成重複和撤銷的操作。

  CommandStack不但完成重複和撤銷命令的操作,還會協助完成命令的執行,當GEF框架要執行命令時,會呼叫CommandStack的execute方法執行相關命令,如以下程式碼片段所示。

  public void execute(Command command) {

  if (command == null || !command.canExecute())

  return;

  flushRedo();

  notifyListeners(command, PRE_EXECUTE);

  try {

  command.execute();

  if (getUndoLimit() > 0) {

  while (undoable.size() >= getUndoLimit()) {

  ((Command)undoable.remove(0)).dispose();

  if (saveLocation > -1)

  saveLocation--;

  }

  }

  if (saveLocation > undoable.size())

  saveLocation = -1;

  undoable.push(command);

  notifyListeners();

  } finally {

  notifyListeners(command, POST_EXECUTE);

  }

  }

  CommandStack會呼叫command的execute方法執行命令,然後把command放入撤銷命令的堆疊中。

  另外,讀者可以看到,在execute、undo和redo方法中都會呼叫notifyListeners方法,CommandStack通過notifyListeners方法通知所有註冊的監聽器,命令堆疊已經發生了改變。

  監聽器

  在GEF編輯器中,使用者可以通過“getEditDomain().getCommandStack()”程式碼獲得編輯器的命令堆疊,在CommandStack中可以通過addCommandStackListener方法新增命令堆疊的監聽器,監聽器是CommandStackListener型別的物件。CommandStackListener介面定義如例程1所示。

  例程1 CommandStackListener.java

  package org.eclipse.gef.commands;

  import java.util.EventObject;

  public interface CommandStackListener {

  void commandStackChanged(EventObject event);

  }

  CommandStackListener介面中宣告瞭一個方法commandStackChanged,當命令堆疊發生改變時,commandStackChanged方法將會執行,如以下程式碼片段所示。

  public void commandStackChanged(EventObject event)

  {

  updateActions(stackActionIDs);

  setDirty(getCommandStack().isDirty());

  }

  protected void setDirty(boolean dirty)

  {

  if (isDirty != dirty)

  {

  isDirty = dirty;

  //通知Eclipse,當前編輯器已經被修改

  firePropertyChange(IEditorPart.PROP_DIRTY);

  }

  }

  如以上程式碼所示,當命令堆疊改變時,編輯器將更新相應的Action,另外通過fireProperty Change方法通知編輯器,當前編輯的內容已經被修改。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/13081368/viewspace-407098/,如需轉載,請註明出處,否則將追究法律責任。

相關文章