/******************************************************************************* * Copyright (c) 2011 Association for Decentralized Information Management in * Industry THTH ry. * 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.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.ui.tester; import org.eclipse.core.expressions.PropertyTester; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.contexts.IContextActivation; import org.eclipse.ui.contexts.IContextService; import org.simantics.DatabaseJob; import org.simantics.Simantics; import org.simantics.db.Session; import org.simantics.db.UndoContext; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.service.UndoRedoSupport; import org.simantics.ui.SimanticsUI; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.SWTUtils; /** * An eclipse property tester for org.simantics.db database undo/redoability. * * @author Kalle Kondelin */ public class UndoPropertyTester extends PropertyTester implements UndoRedoSupport.ChangeListener { private static final String PROP_CAN_REDO = "canRedo"; private static final String PROP_CAN_UNDO = "canUndo"; private static final String SIMANTICS_UNDO_CONTEXT = "org.simantics.ui.undoContext"; public static final boolean DEBUG = false; public static final String UNDO_ENABLED = "org.simantics.undo.enabled"; UndoRedoSupport undoSupport = null; IContextActivation activation = null; public UndoPropertyTester() { if (DEBUG) System.out.println("UndoPropertyTester: " + this); } @Override public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { if (DEBUG) System.out.println("UndoPropertyTester: receiver=" + receiver); String undoEnabled = System.getProperty(UNDO_ENABLED); if(undoEnabled != null && "false".equals(undoEnabled)) return false; if (property.matches(PROP_CAN_UNDO)) return canUndo(); else if (property.matches(PROP_CAN_REDO)) return canRedo(); else return false; } private boolean canUndo() { ISessionContext ctx = Simantics.getSessionContext(); if (ctx == null) { if (DEBUG) System.out.println("UndoPropertyTester: no can do undo."); return false; } try { Session s = ctx.peekSession(); if (null == s) { if (DEBUG) System.out.println("UndoPropertyTester: session is null, no can do undo."); return false; } if (DatabaseJob.inProgress()) return true; if (null == undoSupport) { undoSupport = s.getService(UndoRedoSupport.class); undoSupport.subscribe(this); } UndoContext uc = undoSupport.getUndoContext(s); if (uc == null) return false; boolean ret = !uc.getAll().isEmpty(); if (DEBUG) System.out.println("UndoPropertyTester: " + (ret ? "" : "no ")+ "can do undo."); return ret; } catch (Exception e) { ErrorLogger.getDefault().logError("Undo/Redo support failed.", e); if (DEBUG) System.out.println("UndoPropertyTester: no can do undo"); return false; } } private boolean canRedo() { ISessionContext ctx = Simantics.getSessionContext(); if (ctx == null) { if (DEBUG) System.out.println("UndoPropertyTester: no can do redo."); return false; } try { Session s = ctx.peekSession(); if (null == s) { if (DEBUG) System.out.println("UndoPropertyTester: session is null, no can do redo."); return false; } if (DatabaseJob.inProgress()) return true; if (null == undoSupport) { undoSupport = s.getService(UndoRedoSupport.class); undoSupport.subscribe(this); } UndoContext uc = undoSupport.getUndoContext(s); if (uc == null) return false; boolean ret = !uc.getRedoList().isEmpty(); if (DEBUG) System.out.println("UndoPropertyTester: " + (ret ? "" : "no ")+ "can do redo."); return ret; } catch (Exception e) { ErrorLogger.getDefault().logError("Undo/Redo support failed.", e); if (DEBUG) System.out.println("UndoPropertyTester: no can do redo."); return false; } } @Override public void onChanged() { if (DEBUG) System.out.println("UndoPropertyTester: on change."); Display display = PlatformUI.getWorkbench().getDisplay(); SWTUtils.asyncExec(display, new Runnable() { @Override public void run() { handleChange(); } }); } private int oldUndo = 0; private int oldRedo = 0; private void handleChange() { int newUndo = oldUndo; int newRedo = oldRedo; try { ISessionContext ctx = Simantics.getSessionContext(); if (DEBUG) System.out.println("UndoPropertyTester: handle change, ctx=" + ctx); if (ctx == null) return; Session session = ctx.peekSession(); if (DEBUG) System.out.println("UndoPropertyTester: handle change, session=" + session); if (session == null) return; UndoContext uc = undoSupport.getUndoContext(session); if (uc == null) return; newUndo = uc.getAll().size(); newRedo = uc.getRedoList().size(); if (DEBUG) { System.out.println("on undo change: " + oldUndo + "->" + newUndo); System.out.println("on redo change: " + oldRedo + "->" + newRedo); } boolean undoOn = oldUndo == 0 && newUndo == 1; boolean undoOff = oldUndo > 0 && newUndo == 0; boolean redoOn = oldRedo == 0 && newRedo == 1; boolean redoOff = oldRedo > 0 && newRedo == 0; if (undoOn || undoOff || redoOn || redoOff) toggleContext(); } catch (DatabaseException e) { ErrorLogger.getDefault().logError("Undo/Redo support failed.", e); } oldUndo = newUndo; oldRedo = newRedo; } private void toggleContext() { IContextService contextService = (IContextService)PlatformUI.getWorkbench().getService(IContextService.class); if (null != activation) { if (DEBUG) System.out.println("UndoPropertyTester: deactivate."); try { contextService.deactivateContext(activation); } catch (Throwable t) { ErrorLogger.getDefault().logError("Undo/Redo support failed.", t); } activation = null; if (DEBUG) System.out.println("UndoPropertyTester: deactivated."); } else { if (DEBUG) System.out.println("UndoPropertyTester: activate."); try { activation = contextService.activateContext(SIMANTICS_UNDO_CONTEXT); } catch (Throwable t) { ErrorLogger.getDefault().logError("Undo/Redo support failed.", t); activation = null; } if (DEBUG) System.out.println("UndoPropertyTester: activated=" + activation); } } }