/******************************************************************************* * Copyright (c) 2006-2013 The RCP Company and others. * 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: * The RCP Company - initial API and implementation *******************************************************************************/ package com.rcpcompany.uibindings.internal.sourceProviders; import java.util.EventObject; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.command.CommandStackListener; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.ui.AbstractSourceProvider; import org.eclipse.ui.ISources; import com.rcpcompany.uibindings.Constants; import com.rcpcompany.uibindings.IManager; import com.rcpcompany.uibindings.IUIBindingsPackage; import com.rcpcompany.uibindings.internal.Activator; import com.rcpcompany.utils.logging.LogUtils; /** * Source Provider for property testers in the framework. * <p> * If a property change is fired - using {@link #fireSourceChanged(int, Map)} - for any of full * property names, then all the expressions that uses this property will be re-evaluated. * * @author Tonny Madsen, The RCP Company */ public class ManagerSourceProvider extends AbstractSourceProvider { /** * The names of the sources supported by this source provider. * <p> * <b>NOTE:</b> If you update this list, remember to update the services extension as well! */ public static final String[] PROVIDED_SOURCE_NAMES = new String[] { Constants.SOURCES_CAN_UNDO, Constants.SOURCES_CAN_REDO, }; /** * Constructs and returns a new source provider. */ public ManagerSourceProvider() { theManager.getEditingDomain().getCommandStack().addCommandStackListener(myCommandStackListener); theManager.eAdapters().add(myManagerListener); initializeMap(myOldState); reportSourceChanges(); } @Override public void dispose() { theManager.eAdapters().remove(myManagerListener); } /** * Listener for the current {@link EditingDomain} of the {@link IManager}. */ private final Adapter myManagerListener = new AdapterImpl() { @Override public void notifyChanged(Notification msg) { if (msg.isTouch()) return; if (msg.getFeature() == IUIBindingsPackage.Literals.MANAGER__EDITING_DOMAIN) { if (msg.getOldValue() != null) { ((EditingDomain) msg.getOldValue()).getCommandStack().removeCommandStackListener( myCommandStackListener); } if (msg.getNewValue() != null) { ((EditingDomain) msg.getNewValue()).getCommandStack().addCommandStackListener( myCommandStackListener); } reportSourceChanges(); } }; }; /** * Listener for the command stack of the current {@link EditingDomain}. */ private final CommandStackListener myCommandStackListener = new CommandStackListener() { @Override public void commandStackChanged(EventObject event) { reportSourceChanges(); } }; /** * The manager itself. */ private final IManager theManager = IManager.Factory.getManager(); /** * The previous state reported by the provider. */ private final Map<String, Object> myOldState = new HashMap<String, Object>(); @Override public Map<String, Object> getCurrentState() { return myOldState; } /** * Checks if the current state have changed, and reports these. * * @param event the current event * @return the resulting map */ public Map<String, Object> reportSourceChanges() { final Map<String, Object> newState = getNewState(); for (final Iterator<Map.Entry<String, Object>> is = newState.entrySet().iterator(); is.hasNext();) { final Map.Entry<String, Object> i = is.next(); final String s = i.getKey(); final Object n = i.getValue(); final Object o = myOldState.get(s); if (o == null ? n == null : o.equals(n)) { is.remove(); } else { myOldState.put(s, n); } } if (newState.size() != 0) { /* * Reset the property testers as well, when any of values changes */ newState.put(Constants.PREFIX + Constants.PROPERTY_CAN_UNDO, true); newState.put(Constants.PREFIX + Constants.PROPERTY_CAN_REDO, true); newState.put(Constants.PREFIX + Constants.PROPERTY_IS_SAVE_NEEDED, true); if (Activator.getDefault().TRACE_SOURCE_PROVIDER) { final StringBuilder sb = new StringBuilder("Binding sources change:"); for (final Map.Entry<String, Object> i : newState.entrySet()) { final String s = i.getKey(); sb.append("\n ").append(s).append("='"); final Object v = i.getValue(); if (v == null) { sb.append("<null>"); } else if (v == IEvaluationContext.UNDEFINED_VARIABLE) { sb.append("<undef>"); } else { sb.append(v.toString()); } sb.append('\''); } LogUtils.debug(this, sb.toString()); } fireSourceChanged(ISources.ACTIVE_CURRENT_SELECTION, newState); } return myOldState; } protected Map<String, Object> getNewState() { final Map<String, Object> newState = new HashMap<String, Object>(); final EditingDomain editingDomain = theManager.getEditingDomain(); final CommandStack commandStack = editingDomain.getCommandStack(); newState.put(Constants.SOURCES_CAN_UNDO, commandStack.canUndo()); newState.put(Constants.SOURCES_CAN_REDO, commandStack.canRedo()); return newState; } private void initializeMap(final Map<String, Object> map) { map.put(Constants.SOURCES_CAN_UNDO, false); map.put(Constants.SOURCES_CAN_REDO, false); } @Override public String[] getProvidedSourceNames() { return PROVIDED_SOURCE_NAMES; } }