X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fhints%2FHintStack.java;h=2be216d30df840a8e9147501b2b19e42b215b3ba;hb=refs%2Fchanges%2F38%2F238%2F2;hp=0aad098d7a556c1c091ff3ba8236245b1b702305;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/hints/HintStack.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/hints/HintStack.java index 0aad098d7..2be216d30 100644 --- a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/hints/HintStack.java +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/hints/HintStack.java @@ -1,336 +1,336 @@ -/******************************************************************************* - * Copyright (c) 2007, 2015 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 - * Semantum Oy - added getHintsUnsafe - *******************************************************************************/ -/* - * - * @author Toni Kalajainen - */ -package org.simantics.utils.datastructures.hints; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.prioritystack.IPriorityStack; -import org.simantics.utils.datastructures.prioritystack.IPriorityStackListener; -import org.simantics.utils.datastructures.prioritystack.PriorityStack; -import org.simantics.utils.threads.Executable; -import org.simantics.utils.threads.IThreadWorkQueue; -import org.simantics.utils.threads.ThreadUtils; - - -public class HintStack extends AbstractHintObservable implements IHintStack { - - /** Stack of hint contexts */ - PriorityStack stack = - new PriorityStack(IHintContext.class); - - IPriorityStackListener stackListener = - new IPriorityStackListener() { - @Override - public void itemAdded(IPriorityStack sender, IHintContext item) { - item.addHintListener(ctxListener); - ArrayList executables = new ArrayList(); - synchronized(HintStack.this.stack) { - if (!hasListeners()) return; - Map hints = item.getHints(); - if (hints.size()==0) return; - - Set keys = new HashSet(hints.keySet()); - Map oldValues = new HashMap(); - // Check if there is a change to the stack - IHintContext list[] = stack.toArray(); - - int index = stack.indexOf(item); - - // Remove all keys that are overridden by higher priority keys - for (int i=index+1; i=0; i--) - { - Map lowerLevelHints = list[i].getHints(); - lowerLevelHints.keySet().retainAll(keys); - keys.removeAll(lowerLevelHints.keySet()); - oldValues.putAll(lowerLevelHints); - } - - // Send events for all new hints - for (Key key : keys) - { - Object newValue = hints.get(key); - addFireKeyChangedExecutables(executables, HintStack.this, key, null, newValue); - } - - // Send events for all hints that were overridden - for (Entry hint : oldValues.entrySet()) - { - Key key = hint.getKey(); - Object oldValue = hint.getValue(); - Object newValue = hints.get(key); - addFireKeyChangedExecutables(executables, HintStack.this, key, oldValue, newValue); - } - } - ThreadUtils.multiSyncExec(executables); - } - @Override - public void itemRemoved(IPriorityStack sender, IHintContext item) { - item.removeHintListener(ctxListener); - ArrayList executables = new ArrayList(); - synchronized(HintStack.this.stack) { - if (!hasListeners()) return; - Map hints = item.getHints(); - if (hints.size()==0) return; - - Set keys = new HashSet(hints.keySet()); - Map overriddenValues = new HashMap(); - // Check if there is a change to the stack - IHintContext list[] = stack.toArray(); - - int index = stack.indexOf(item); - - // Remove all keys that are overridden by higher priority keys - for (int i=index+1; i=0; i--) - { - Map lowerLevelHints = list[i].getHints(); - lowerLevelHints.keySet().retainAll(keys); - keys.removeAll(lowerLevelHints.keySet()); - overriddenValues.putAll(lowerLevelHints); - } - - // Send events for all values were removed and were never overridden - for (Key key : keys) - { - Object oldValue = hints.get(key); - addFireKeyRemovedExecutables(executables, HintStack.this, key, oldValue); - } - - // Send events. overridden hints have become effective - for (Entry hint : overriddenValues.entrySet()) - { - Key key = hint.getKey(); - Object newValue = hint.getValue(); - Object oldValue = hints.get(key); - addFireKeyChangedExecutables(executables, HintStack.this, key, oldValue, newValue); - } - } - ThreadUtils.multiSyncExec(executables); - } - }; - - IHintListener ctxListener = new IHintListener() { - @Override - public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { - Runnable notifications; - synchronized(HintStack.this.stack) { - IHintContext list[] = stack.toArray(); - - int index = stack.indexOf((IHintContext)sender); - if (index<0) return; - - // Check whether the key is overridden - for (int i=index+1; i=0; i--) - { - oldValue = list[i].getHint(key); - if (oldValue!=null) break; - } - } - notifications = createFireKeyChangedRunnable(HintStack.this, key, oldValue, newValue); - } - notifications.run(); - } - @Override - public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { - Runnable notification; - synchronized(HintStack.this.stack) { - IHintContext list[] = stack.toArray(); - - int index = stack.indexOf((IHintContext)sender); - if (index<0) return; - - // Check whether the key was overridden - for (int i=index+1; i=0; i--) - { - newValue = list[i].getHint(key); - if (newValue!=null) break; - } - if (newValue!=null) - notification = createFireKeyChangedRunnable(HintStack.this, key, oldValue, newValue); - else - notification = createFireKeyRemovedRunnable(HintStack.this, key, oldValue); - } - notification.run(); - } - }; - - public HintStack() { - stack.addStackListener(stackListener); - } - - @Override - public void addHintContext(IHintContext hints, int priority) { - stack.add(hints, priority); - } - - @SuppressWarnings("unchecked") - @Override - public E getHint(Key key) { - IHintContext list [] = stack.toArray(); - for (int i=list.length-1; i>=0; i--) - { - IHintContext ctx = list[i]; - Object value = ctx.getHint(key); - if (value!=null) return (E) value; - } - return null; - } - - @Override - public boolean containsHint(Key key) { - IHintContext list [] = stack.toArray(); - for (int i=list.length-1; i>=0; i--) - { - IHintContext ctx = list[i]; - if (ctx.containsHint(key)) - return true; - } - return false; - } - - @Override - public boolean removeHintContext(IHintContext hints) { - return stack.remove(hints); - } - - @Override - public synchronized Map getHints() { - Map result = new HashMap(); - for (IHintContext ctx : stack.toArray()) - result.putAll(ctx.getHints()); - return result; - } - - @Override - public synchronized Map getHintsUnsafe() { - return getHints(); - } - - @Override - public Map getHintsOfClass(Class clazz) { - Map result = new HashMap(); - for (IHintContext ctx : stack.toArray()) - result.putAll(ctx.getHintsOfClass(clazz)); - return result; - } - - /** - * Returns a hint context whose read operations originate from the stack, and - * write operations are performed on a local stack - * - * @param ctx the hint context to write into - * @return write-localized hint context based on this hint stack - */ - public IHintContext createStackRead(final IHintContext ctx) - { - return new IHintContext() { - @Override - public void clearWithoutNotification() { - ctx.clearWithoutNotification(); - } - @SuppressWarnings("unchecked") - @Override - public E removeHint(Key key) { - return (E) ctx.removeHint(key); - } - @Override - public void setHint(Key key, Object value) { - ctx.setHint(key, value); - } - @Override - public void addHintListener(IHintListener listener) { - HintStack.this.addHintListener(listener); - } - @Override - public void addHintListener(IThreadWorkQueue threadAccess, IHintListener listener) { - HintStack.this.addHintListener(threadAccess, listener); - } - @Override - public void addKeyHintListener(Key key, IHintListener listener) { - HintStack.this.addKeyHintListener(key, listener); - } - @Override - public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) { - HintStack.this.addKeyHintListener(threadAccess, key, listener); - } - @Override - public boolean containsHint(Key key) { - return HintStack.this.containsHint(key); - } - @SuppressWarnings("unchecked") - @Override - public E getHint(Key key) { - return (E) HintStack.this.getHint(key); - } - @Override - public Map getHints() { - return HintStack.this.getHints(); - } - @Override - public Map getHintsUnsafe() { - return HintStack.this.getHintsUnsafe(); - } - @Override - public void removeHintListener(IHintListener listener) { - HintStack.this.removeHintListener(listener); - } - @Override - public void removeHintListener(IThreadWorkQueue threadAccess, IHintListener listener) { - HintStack.this.removeHintListener(threadAccess, listener); - } - @Override - public void removeKeyHintListener(Key key, IHintListener listener) { - HintStack.this.removeKeyHintListener(key, listener); - } - @Override - public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) { - HintStack.this.removeKeyHintListener(threadAccess, key, listener); - } - @Override - public Map getHintsOfClass(Class clazz) { - return HintStack.this.getHintsOfClass(clazz); - } - @Override - public void setHints(Map hints) { - ctx.setHints(hints); - }}; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2015 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 + * Semantum Oy - added getHintsUnsafe + *******************************************************************************/ +/* + * + * @author Toni Kalajainen + */ +package org.simantics.utils.datastructures.hints; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.prioritystack.IPriorityStack; +import org.simantics.utils.datastructures.prioritystack.IPriorityStackListener; +import org.simantics.utils.datastructures.prioritystack.PriorityStack; +import org.simantics.utils.threads.Executable; +import org.simantics.utils.threads.IThreadWorkQueue; +import org.simantics.utils.threads.ThreadUtils; + + +public class HintStack extends AbstractHintObservable implements IHintStack { + + /** Stack of hint contexts */ + PriorityStack stack = + new PriorityStack(IHintContext.class); + + IPriorityStackListener stackListener = + new IPriorityStackListener() { + @Override + public void itemAdded(IPriorityStack sender, IHintContext item) { + item.addHintListener(ctxListener); + ArrayList executables = new ArrayList(); + synchronized(HintStack.this.stack) { + if (!hasListeners()) return; + Map hints = item.getHints(); + if (hints.size()==0) return; + + Set keys = new HashSet(hints.keySet()); + Map oldValues = new HashMap(); + // Check if there is a change to the stack + IHintContext list[] = stack.toArray(); + + int index = stack.indexOf(item); + + // Remove all keys that are overridden by higher priority keys + for (int i=index+1; i=0; i--) + { + Map lowerLevelHints = list[i].getHints(); + lowerLevelHints.keySet().retainAll(keys); + keys.removeAll(lowerLevelHints.keySet()); + oldValues.putAll(lowerLevelHints); + } + + // Send events for all new hints + for (Key key : keys) + { + Object newValue = hints.get(key); + addFireKeyChangedExecutables(executables, HintStack.this, key, null, newValue); + } + + // Send events for all hints that were overridden + for (Entry hint : oldValues.entrySet()) + { + Key key = hint.getKey(); + Object oldValue = hint.getValue(); + Object newValue = hints.get(key); + addFireKeyChangedExecutables(executables, HintStack.this, key, oldValue, newValue); + } + } + ThreadUtils.multiSyncExec(executables); + } + @Override + public void itemRemoved(IPriorityStack sender, IHintContext item) { + item.removeHintListener(ctxListener); + ArrayList executables = new ArrayList(); + synchronized(HintStack.this.stack) { + if (!hasListeners()) return; + Map hints = item.getHints(); + if (hints.size()==0) return; + + Set keys = new HashSet(hints.keySet()); + Map overriddenValues = new HashMap(); + // Check if there is a change to the stack + IHintContext list[] = stack.toArray(); + + int index = stack.indexOf(item); + + // Remove all keys that are overridden by higher priority keys + for (int i=index+1; i=0; i--) + { + Map lowerLevelHints = list[i].getHints(); + lowerLevelHints.keySet().retainAll(keys); + keys.removeAll(lowerLevelHints.keySet()); + overriddenValues.putAll(lowerLevelHints); + } + + // Send events for all values were removed and were never overridden + for (Key key : keys) + { + Object oldValue = hints.get(key); + addFireKeyRemovedExecutables(executables, HintStack.this, key, oldValue); + } + + // Send events. overridden hints have become effective + for (Entry hint : overriddenValues.entrySet()) + { + Key key = hint.getKey(); + Object newValue = hint.getValue(); + Object oldValue = hints.get(key); + addFireKeyChangedExecutables(executables, HintStack.this, key, oldValue, newValue); + } + } + ThreadUtils.multiSyncExec(executables); + } + }; + + IHintListener ctxListener = new IHintListener() { + @Override + public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { + Runnable notifications; + synchronized(HintStack.this.stack) { + IHintContext list[] = stack.toArray(); + + int index = stack.indexOf((IHintContext)sender); + if (index<0) return; + + // Check whether the key is overridden + for (int i=index+1; i=0; i--) + { + oldValue = list[i].getHint(key); + if (oldValue!=null) break; + } + } + notifications = createFireKeyChangedRunnable(HintStack.this, key, oldValue, newValue); + } + notifications.run(); + } + @Override + public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { + Runnable notification; + synchronized(HintStack.this.stack) { + IHintContext list[] = stack.toArray(); + + int index = stack.indexOf((IHintContext)sender); + if (index<0) return; + + // Check whether the key was overridden + for (int i=index+1; i=0; i--) + { + newValue = list[i].getHint(key); + if (newValue!=null) break; + } + if (newValue!=null) + notification = createFireKeyChangedRunnable(HintStack.this, key, oldValue, newValue); + else + notification = createFireKeyRemovedRunnable(HintStack.this, key, oldValue); + } + notification.run(); + } + }; + + public HintStack() { + stack.addStackListener(stackListener); + } + + @Override + public void addHintContext(IHintContext hints, int priority) { + stack.add(hints, priority); + } + + @SuppressWarnings("unchecked") + @Override + public E getHint(Key key) { + IHintContext list [] = stack.toArray(); + for (int i=list.length-1; i>=0; i--) + { + IHintContext ctx = list[i]; + Object value = ctx.getHint(key); + if (value!=null) return (E) value; + } + return null; + } + + @Override + public boolean containsHint(Key key) { + IHintContext list [] = stack.toArray(); + for (int i=list.length-1; i>=0; i--) + { + IHintContext ctx = list[i]; + if (ctx.containsHint(key)) + return true; + } + return false; + } + + @Override + public boolean removeHintContext(IHintContext hints) { + return stack.remove(hints); + } + + @Override + public synchronized Map getHints() { + Map result = new HashMap(); + for (IHintContext ctx : stack.toArray()) + result.putAll(ctx.getHints()); + return result; + } + + @Override + public synchronized Map getHintsUnsafe() { + return getHints(); + } + + @Override + public Map getHintsOfClass(Class clazz) { + Map result = new HashMap(); + for (IHintContext ctx : stack.toArray()) + result.putAll(ctx.getHintsOfClass(clazz)); + return result; + } + + /** + * Returns a hint context whose read operations originate from the stack, and + * write operations are performed on a local stack + * + * @param ctx the hint context to write into + * @return write-localized hint context based on this hint stack + */ + public IHintContext createStackRead(final IHintContext ctx) + { + return new IHintContext() { + @Override + public void clearWithoutNotification() { + ctx.clearWithoutNotification(); + } + @SuppressWarnings("unchecked") + @Override + public E removeHint(Key key) { + return (E) ctx.removeHint(key); + } + @Override + public void setHint(Key key, Object value) { + ctx.setHint(key, value); + } + @Override + public void addHintListener(IHintListener listener) { + HintStack.this.addHintListener(listener); + } + @Override + public void addHintListener(IThreadWorkQueue threadAccess, IHintListener listener) { + HintStack.this.addHintListener(threadAccess, listener); + } + @Override + public void addKeyHintListener(Key key, IHintListener listener) { + HintStack.this.addKeyHintListener(key, listener); + } + @Override + public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) { + HintStack.this.addKeyHintListener(threadAccess, key, listener); + } + @Override + public boolean containsHint(Key key) { + return HintStack.this.containsHint(key); + } + @SuppressWarnings("unchecked") + @Override + public E getHint(Key key) { + return (E) HintStack.this.getHint(key); + } + @Override + public Map getHints() { + return HintStack.this.getHints(); + } + @Override + public Map getHintsUnsafe() { + return HintStack.this.getHintsUnsafe(); + } + @Override + public void removeHintListener(IHintListener listener) { + HintStack.this.removeHintListener(listener); + } + @Override + public void removeHintListener(IThreadWorkQueue threadAccess, IHintListener listener) { + HintStack.this.removeHintListener(threadAccess, listener); + } + @Override + public void removeKeyHintListener(Key key, IHintListener listener) { + HintStack.this.removeKeyHintListener(key, listener); + } + @Override + public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) { + HintStack.this.removeKeyHintListener(threadAccess, key, listener); + } + @Override + public Map getHintsOfClass(Class clazz) { + return HintStack.this.getHintsOfClass(clazz); + } + @Override + public void setHints(Map hints) { + ctx.setHints(hints); + }}; + } + +}