/******************************************************************************* * Copyright (c) 2007, 2008 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.keys.model; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.jface.bindings.Binding; import org.eclipse.jface.bindings.BindingManager; import org.eclipse.jface.bindings.TriggerSequence; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; /** * @since 3.4 * */ public class ConflictModel extends CommonModel { public static final String PROP_CONFLICTS = "conflicts"; //$NON-NLS-1$ public static final String PROP_CONFLICTS_ADD = "conflictsAdd"; //$NON-NLS-1$ public static final String PROP_CONFLICTS_REMOVE = "conflictsRemove"; //$NON-NLS-1$ /** * The set of conflicts for the currently selected element. */ private Collection conflicts; private BindingManager bindingManager; private BindingModel bindingModel; /** * A mapping of binding element to known conflicts. */ private Map conflictsMap; /** * @param kc */ public ConflictModel(KeyController kc) { super(kc); } /** * @return Returns the conflicts. */ public Collection getConflicts() { return conflicts; } /** * Sets the conflicts to the given collection. Any conflicts in the * collection that do not exist in the <code>bindingModel</code> are * removed. * * @param conflicts * The conflicts to set. */ public void setConflicts(Collection conflicts) { Object old = this.conflicts; this.conflicts = conflicts; if (this.conflicts != null) { Iterator i = this.conflicts.iterator(); Map bindingToElement = bindingModel.getBindingToElement(); while (i.hasNext()) { Object next = i.next(); if (!bindingToElement.containsValue(next) && !next.equals(getSelectedElement())) { i.remove(); } } } controller.firePropertyChange(this, PROP_CONFLICTS, old, conflicts); } public void updateConflictsFor(BindingElement source) { updateConflictsFor(source, false); } public void updateConflictsFor(BindingElement oldValue, BindingElement newValue) { updateConflictsFor(oldValue, newValue, false); } public void updateConflictsFor(BindingElement source, boolean removal) { updateConflictsFor(null, source, removal); } private void updateConflictsFor(BindingElement oldValue, BindingElement newValue, boolean removal) { updateConflictsFor(newValue, oldValue == null ? null : oldValue .getTrigger(), newValue == null ? null : newValue.getTrigger(), removal); } public void updateConflictsFor(BindingElement newValue, TriggerSequence oldTrigger, TriggerSequence newTrigger, boolean removal) { Collection matches = (Collection) conflictsMap.get(newValue); if (matches != null) { if (newTrigger == null || removal) { // we need to clear this match matches.remove(newValue); conflictsMap.remove(newValue); if (matches == conflicts) { controller.firePropertyChange(this, PROP_CONFLICTS_REMOVE, null, newValue); } if (matches.size() == 1) { BindingElement tbe = (BindingElement) matches.iterator() .next(); conflictsMap.remove(tbe); tbe.setConflict(Boolean.FALSE); if (matches == conflicts) { setConflicts(null); } } return; } else if (oldTrigger != null && !newTrigger.equals(oldTrigger)) { // we need to clear this match matches.remove(newValue); conflictsMap.remove(newValue); if (matches == conflicts) { controller.firePropertyChange(this, PROP_CONFLICTS_REMOVE, null, newValue); } if (matches.size() == 1) { BindingElement tbe = (BindingElement) matches.iterator() .next(); conflictsMap.remove(tbe); tbe.setConflict(Boolean.FALSE); if (matches == conflicts) { setConflicts(null); } } } else { return; } } if (newValue.getTrigger() == null || !(newValue.getModelObject() instanceof Binding)) { return; } Binding binding = (Binding) newValue.getModelObject(); TriggerSequence trigger = binding.getTriggerSequence(); matches = (Collection) bindingManager .getActiveBindingsDisregardingContext().get(trigger); ArrayList localConflicts = new ArrayList(); if (matches != null) { localConflicts.add(newValue); Iterator i = matches.iterator(); while (i.hasNext()) { Binding b = (Binding) i.next(); if (binding != b && b.getContextId().equals(binding.getContextId()) && b.getSchemeId().equals(binding.getSchemeId())) { Object element = bindingModel.getBindingToElement().get(b); if (element != null) { localConflicts.add(element); } } } } if (localConflicts.size() > 1) { // first find if it is already a conflict collection Collection knownConflicts = null; Iterator i = localConflicts.iterator(); while (i.hasNext() && knownConflicts == null) { BindingElement tbe = (BindingElement) i.next(); knownConflicts = (Collection) conflictsMap.get(tbe); } if (knownConflicts != null) { knownConflicts.add(newValue); conflictsMap.put(newValue, knownConflicts); newValue.setConflict(Boolean.TRUE); if (knownConflicts == conflicts) { controller.firePropertyChange(this, PROP_CONFLICTS_ADD, null, newValue); } else if (newValue == getSelectedElement()) { setConflicts(knownConflicts); } return; } boolean isSelected = false; i = localConflicts.iterator(); while (i.hasNext()) { BindingElement tbe = (BindingElement) i.next(); if (tbe != null) { conflictsMap.put(tbe, localConflicts); tbe.setConflict(Boolean.TRUE); } if (tbe == getSelectedElement()) { isSelected = true; } } if (isSelected) { setConflicts(localConflicts); } } } public void init(BindingManager manager, BindingModel model) { bindingManager = manager; bindingModel = model; conflictsMap = new HashMap(); Iterator i = bindingModel.getBindings().iterator(); while (i.hasNext()) { BindingElement be = (BindingElement) i.next(); if (be.getModelObject() instanceof Binding) { updateConflictsFor(be); } } controller.addPropertyChangeListener(new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if (event.getSource() == ConflictModel.this && CommonModel.PROP_SELECTED_ELEMENT.equals(event .getProperty())) { if (event.getNewValue() != null) { updateConflictsFor( (BindingElement) event.getOldValue(), (BindingElement) event.getNewValue()); setConflicts((Collection) conflictsMap.get(event .getNewValue())); } else { setConflicts(null); } } else if (BindingModel.PROP_BINDING_REMOVE.equals(event .getProperty())) { updateConflictsFor((BindingElement) event.getOldValue(), (BindingElement) event.getNewValue(), true); } } }); } }