| package org.eclipse.ui.examples.undo.views; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.dialogs.ElementListSelectionDialog; |
| import org.eclipse.ui.examples.undo.UndoExampleMessages; |
| import org.eclipse.ui.examples.undo.UndoPlugin; |
| import org.eclipse.ui.examples.undo.preferences.PreferenceConstants; |
| import org.eclipse.ui.operations.RedoActionHandler; |
| import org.eclipse.ui.operations.UndoActionHandler; |
| import org.eclipse.ui.part.*; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.commands.operations.IUndoableOperation; |
| import org.eclipse.core.commands.operations.OperationHistoryFactory; |
| import org.eclipse.core.commands.operations.IOperationHistory; |
| import org.eclipse.core.commands.operations.IOperationHistoryListener; |
| import org.eclipse.core.commands.operations.OperationHistoryEvent; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.*; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.jface.action.*; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.ui.*; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.SWT; |
| |
| /** |
| * This view shows what operations are being added to the operations history for |
| * undo. The view can be filtered by any operation context. A null operation |
| * context indicates that the view should not be filtered. |
| * |
| * <p> |
| * Selecting undo or redo from the context menu or the edit menu will perform a |
| * linear undo in the current context of the view. Selecting "Undo selected" |
| * allows experimentation with direct undo. Operations that are undoable may be |
| * undone independently of their order in the history. |
| */ |
| |
| public class UndoHistoryView extends ViewPart implements |
| ISelectionChangedListener { |
| private TableViewer viewer; |
| |
| private Action filterAction; |
| |
| private Action doubleClickAction; |
| |
| private Action selectiveUndoAction; |
| |
| private Action refreshListAction; |
| |
| private IOperationHistory history = OperationHistoryFactory |
| .getOperationHistory(); |
| |
| private IUndoContext fContext = IOperationHistory.GLOBAL_UNDO_CONTEXT; |
| |
| private UndoActionHandler undoAction; |
| |
| private RedoActionHandler redoAction; |
| |
| private boolean showDebug = UndoPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.PREF_SHOWDEBUG); |
| private IPropertyChangeListener propertyChangeListener; |
| |
| /* |
| * The content provider shows the operations in the undo portion of the |
| * operation history. The histor is filtered by the currently selected |
| * undo context. |
| */ |
| |
| class ViewContentProvider implements IStructuredContentProvider, |
| IOperationHistoryListener { |
| |
| public void inputChanged(Viewer v, Object oldInput, Object newInput) { |
| // we never change inputs, so we just use this as a place to add our |
| // listener. |
| history.addOperationHistoryListener(this); |
| } |
| |
| public void dispose() { |
| history.removeOperationHistoryListener(this); |
| } |
| |
| public Object[] getElements(Object input) { |
| // show the items in the operations history. |
| return history.getUndoHistory(fContext); |
| } |
| |
| public void historyNotification(OperationHistoryEvent event) { |
| if (viewer.getTable().isDisposed()) |
| return; |
| Display display = viewer.getTable().getDisplay(); |
| switch (event.getEventType()) { |
| case OperationHistoryEvent.OPERATION_ADDED: |
| case OperationHistoryEvent.OPERATION_REMOVED: |
| case OperationHistoryEvent.UNDONE: |
| case OperationHistoryEvent.REDONE: |
| if (event.getOperation().hasContext(fContext) |
| && display != null) { |
| display.syncExec(new Runnable() { |
| public void run() { |
| // refresh all labels in case any operation has |
| // changed dynamically |
| // without notifying the operation history. |
| if (!viewer.getTable().isDisposed()) |
| viewer.refresh(true); |
| } |
| }); |
| } |
| break; |
| } |
| } |
| } |
| |
| /* |
| * A simple label provider that uses a preference to determine |
| * whether the simple label or the debugging label (toString()) |
| * for an operation is shown. |
| */ |
| class ViewLabelProvider extends LabelProvider implements |
| ITableLabelProvider { |
| public String getColumnText(Object obj, int index) { |
| return getText(obj); |
| } |
| |
| public Image getColumnImage(Object obj, int index) { |
| return getImage(obj); |
| } |
| |
| public String getText(Object obj) { |
| if (!showDebug && obj instanceof IUndoableOperation) |
| return ((IUndoableOperation)obj).getLabel(); |
| return obj.toString(); |
| } |
| } |
| |
| /* |
| * Create a table viewer to show the list of operations. |
| */ |
| public void createPartControl(Composite parent) { |
| viewer = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL |
| | SWT.V_SCROLL); |
| viewer.setContentProvider(new ViewContentProvider()); |
| viewer.setLabelProvider(new ViewLabelProvider()); |
| viewer.setInput(getViewSite()); |
| makeActions(); |
| hookContextMenu(); |
| hookDoubleClickAction(); |
| addListeners(); |
| createGlobalActionHandlers(); |
| } |
| |
| /* |
| * Add any listeners needed by this view. |
| */ |
| private void addListeners() { |
| propertyChangeListener = new IPropertyChangeListener(){ |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getProperty() == PreferenceConstants.PREF_SHOWDEBUG) { |
| showDebug = UndoPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.PREF_SHOWDEBUG); |
| viewer.refresh(); |
| } |
| } |
| }; |
| UndoPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(propertyChangeListener); |
| viewer.getControl().addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent event) { |
| removeListeners(); |
| } |
| }); |
| } |
| |
| /* |
| * Remove listeners that were added to this view. |
| */ |
| private void removeListeners() { |
| UndoPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(propertyChangeListener); |
| } |
| |
| |
| /* |
| * Create global action handlers to control undo and redo. We use the action |
| * handlers rather than the UndoRedoActionGroup because this view |
| * dynamically sets the undo context of the handlers. Most views that simply |
| * desire an undo and redo menu action for their undo context can use |
| * UndoRedoActionGroup. |
| */ |
| private void createGlobalActionHandlers() { |
| // set up action handlers that operate on the current context |
| undoAction = new UndoActionHandler(this.getSite(), fContext); |
| redoAction = new RedoActionHandler(this.getSite(), fContext); |
| IActionBars actionBars = getViewSite().getActionBars(); |
| actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), |
| undoAction); |
| actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), |
| redoAction); |
| } |
| |
| /* |
| * Put up a dialog that shows all of the available undo contexts and allow |
| * the user to select one. |
| */ |
| private IUndoContext selectContext() { |
| // This would be better implemented as a view filter, but for now, we |
| // will use a dialog that collects the available undo contexts. |
| List input = new ArrayList(); |
| IUndoableOperation[] operations = history |
| .getUndoHistory(IOperationHistory.GLOBAL_UNDO_CONTEXT); |
| for (int i = 0; i < operations.length; i++) { |
| IUndoContext[] contexts = operations[i].getContexts(); |
| for (int j = 0; j < contexts.length; j++) { |
| if (!input.contains(contexts[j])) { |
| input.add(contexts[j]); |
| } |
| } |
| } |
| input.add(IOperationHistory.GLOBAL_UNDO_CONTEXT); |
| |
| ILabelProvider labelProvider = new LabelProvider() { |
| public String getText(Object element) { |
| return ((IUndoContext) element).getLabel(); |
| } |
| }; |
| |
| ElementListSelectionDialog dialog = new ElementListSelectionDialog( |
| getSite().getShell(), labelProvider); |
| dialog.setMultipleSelection(false); |
| dialog.setTitle(UndoExampleMessages.UndoHistoryView_ContextFilterDialog); |
| dialog.setMessage(UndoExampleMessages.UndoHistoryView_ChooseContextMessage); |
| dialog.setElements(input.toArray()); |
| dialog.setInitialSelections(new Object[] { fContext }); |
| if (dialog.open() == Window.OK) { |
| Object[] contexts = dialog.getResult(); |
| if (contexts[0] instanceof IUndoContext) |
| return (IUndoContext) contexts[0]; |
| else |
| return null; |
| } |
| return null; |
| } |
| |
| /* |
| * Reset the undo context on which the history is filtered. |
| */ |
| public void setContext(IUndoContext context) { |
| fContext = context; |
| // setting the context into the actions updates the menu labels, etc. |
| redoAction.setContext(context); |
| undoAction.setContext(context); |
| // need to refresh the viewer |
| viewer.refresh(false); |
| } |
| |
| /* |
| * Hook the context menu for the view |
| */ |
| private void hookContextMenu() { |
| MenuManager menuMgr = new MenuManager("#PopupMenu"); |
| menuMgr.setRemoveAllWhenShown(true); |
| menuMgr.addMenuListener(new IMenuListener() { |
| public void menuAboutToShow(IMenuManager manager) { |
| UndoHistoryView.this.fillContextMenu(manager); |
| } |
| }); |
| Menu menu = menuMgr.createContextMenu(viewer.getControl()); |
| viewer.getControl().setMenu(menu); |
| getSite().registerContextMenu(menuMgr, viewer); |
| } |
| |
| /* |
| * Fill the context menu for the view. |
| */ |
| private void fillContextMenu(IMenuManager manager) { |
| // First add the global undo/redo actions |
| undoAction.update(); |
| redoAction.update(); |
| manager.add(undoAction); |
| manager.add(redoAction); |
| manager.add(new Separator()); |
| |
| // Now add our specialized actions |
| manager.add(selectiveUndoAction); |
| manager.add(filterAction); |
| manager.add(refreshListAction); |
| |
| ISelection selection = viewer.getSelection(); |
| if (!selection.isEmpty()) { |
| IUndoableOperation operation = (IUndoableOperation) ((IStructuredSelection) selection) |
| .getFirstElement(); |
| selectiveUndoAction.setEnabled(operation.canUndo()); |
| } else { |
| selectiveUndoAction.setEnabled(false); |
| } |
| |
| // Other plug-ins can contribute actions here |
| manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| } |
| |
| /* |
| * Create the actions for the view. |
| */ |
| private void makeActions() { |
| filterAction = new Action() { |
| public void run() { |
| IUndoContext context = selectContext(); |
| if (fContext != context && context != null) { |
| setContext(context); |
| } |
| } |
| }; |
| filterAction.setText(UndoExampleMessages.UndoHistoryView_FilterText); |
| filterAction.setToolTipText(UndoExampleMessages.UndoHistoryView_FilterToolTipText); |
| filterAction.setImageDescriptor(PlatformUI.getWorkbench() |
| .getSharedImages().getImageDescriptor( |
| ISharedImages.IMG_OBJS_INFO_TSK)); |
| |
| selectiveUndoAction = new Action() { |
| public void run() { |
| ISelection selection = viewer.getSelection(); |
| IUndoableOperation operation = (IUndoableOperation) ((IStructuredSelection) selection) |
| .getFirstElement(); |
| if (operation.canUndo()) { |
| try { |
| history.undoOperation(operation, null, undoAction); |
| } catch (ExecutionException e) { |
| showMessage(UndoExampleMessages.UndoHistoryView_OperationException); |
| } |
| } else { |
| showMessage(UndoExampleMessages.UndoHistoryView_OperationInvalid); |
| } |
| } |
| }; |
| selectiveUndoAction.setText(UndoExampleMessages.UndoHistoryView_UndoSelected); |
| selectiveUndoAction.setToolTipText(UndoExampleMessages.UndoHistoryView_UndoSelectedToolTipText); |
| selectiveUndoAction.setImageDescriptor(PlatformUI.getWorkbench() |
| .getSharedImages().getImageDescriptor( |
| ISharedImages.IMG_TOOL_UNDO)); |
| |
| refreshListAction = new Action() { |
| public void run() { |
| if (!viewer.getTable().isDisposed()) |
| viewer.refresh(true); |
| } |
| }; |
| refreshListAction.setText(UndoExampleMessages.UndoHistoryView_RefreshList); |
| refreshListAction.setToolTipText(UndoExampleMessages.UndoHistoryView_RefreshListToolTipText); |
| |
| doubleClickAction = new Action() { |
| public void run() { |
| ISelection selection = viewer.getSelection(); |
| IUndoableOperation operation = (IUndoableOperation) ((IStructuredSelection) selection) |
| .getFirstElement(); |
| StringBuffer buf = new StringBuffer(operation.getLabel()); |
| buf.append("\n"); |
| buf.append("Enabled="); //$NON-NLS-1$ |
| buf.append(new Boolean(operation.canUndo()).toString()); |
| buf.append("\n"); |
| buf.append(operation.getClass().toString()); |
| showMessage(buf.toString()); |
| |
| } |
| }; |
| } |
| |
| /* |
| * Register a double click action with the double click event. |
| */ |
| private void hookDoubleClickAction() { |
| viewer.addDoubleClickListener(new IDoubleClickListener() { |
| public void doubleClick(DoubleClickEvent event) { |
| doubleClickAction.run(); |
| } |
| }); |
| } |
| |
| /* |
| * Show an info message |
| */ |
| private void showMessage(String message) { |
| MessageDialog.openInformation(viewer.getControl().getShell(), |
| UndoExampleMessages.UndoHistoryView_InfoDialogTitle, message); |
| } |
| |
| /* |
| * The selection has changed. |
| */ |
| public void selectionChanged(SelectionChangedEvent event) { |
| ISelection selection = viewer.getSelection(); |
| boolean enabled = !selection.isEmpty(); |
| selectiveUndoAction.setEnabled(enabled); |
| } |
| |
| /* |
| * Pass the focus request to the viewer's control. |
| */ |
| public void setFocus() { |
| viewer.getControl().setFocus(); |
| |
| } |
| } |