-package org.simantics.document.server.client;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-\r
-import org.simantics.db.common.procedure.adapter.ListenerAdapter;\r
-import org.simantics.db.common.procedure.adapter.ListenerSupport;\r
-import org.simantics.db.layer0.variable.ProxyChildVariable;\r
-import org.simantics.document.server.DocumentHistoryCollector;\r
-import org.simantics.document.server.JSONObject;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.threads.IThreadWorkQueue;\r
-\r
-abstract public class DocumentClient implements Document {\r
-\r
- protected HashMap<String, WidgetData> widgetData = new HashMap<String, WidgetData>();\r
- private WidgetMapping mapping;\r
- private CommandMapping commandMapping;\r
- \r
- public DocumentClient(WidgetMapping mapping, CommandMapping commandMapping) {\r
- this.mapping = mapping;\r
- this.commandMapping = commandMapping;\r
- }\r
-\r
- @Override\r
- public WidgetManager<?, ?> getManager(JSONObject object) {\r
- return mapping.getWidget(object.getType());\r
- }\r
- \r
- @Override\r
- public WidgetData getWidget(String id) {\r
- return widgetData.get(id);\r
- }\r
- \r
- abstract public IThreadWorkQueue thread();\r
- \r
- protected void updateDocument(Collection<JSONObject> objects) {\r
-\r
- ArrayList<WidgetData> updatedData = new ArrayList<WidgetData>();\r
- // Cache data\r
- for (JSONObject object : objects) {\r
- WidgetData datum = widgetData.get(object.getId());\r
- if(datum == null) {\r
- datum = new WidgetData(this, null, object);\r
- widgetData.put(object.getId(), datum);\r
- } else {\r
- // This could replace changed information instead of replacing the whole object\r
- datum.object = object;\r
- }\r
- updatedData.add(datum);\r
- }\r
-\r
- // Create widgets\r
- for(WidgetData datum : updatedData) {\r
- createElementIfNecessary(datum);\r
- }\r
- \r
- HashSet<WidgetData> updatedParents = new HashSet<WidgetData>(); \r
- \r
- // Update parent hierarchy\r
- for(WidgetData datum : updatedData) {\r
- updateChildmaps(datum, updatedParents);\r
- }\r
- \r
- updateTree(updatedParents);\r
- \r
- // Set values\r
- for(WidgetData datum : updatedData) {\r
- datum.updateProperties();\r
- datum.updateCommands();\r
- }\r
-\r
- }\r
- \r
- private void createElementIfNecessary(WidgetData data) {\r
- if(data.widget == null) { \r
- data.widget = data.createElement();\r
- }\r
- }\r
-\r
- private void updateChildmaps(WidgetData data, HashSet<WidgetData> updates) {\r
-\r
- // Root\r
- if(data.object == null) return;\r
- \r
-// System.err.println("p:" + data.object);\r
-// Object o = data.object.getParent();\r
- \r
- WidgetData parent = widgetData.get(data.object.getParent()); \r
-\r
-// System.out.println("parent:" + parent);\r
-\r
- if(parent == null) return;\r
- \r
- String parentOrd = data.object.getParentOrd();\r
- \r
- WidgetData existing = parent.childmap.get(parentOrd);\r
- if(!data.equals(existing)) {\r
- updates.add(parent);\r
- parent.childmap.put(parentOrd, data);\r
- }\r
- \r
- }\r
-\r
- protected void updateTree(HashSet<WidgetData> updates) {\r
- \r
- if(updates.isEmpty()) return;\r
- \r
- ArrayList<WidgetData> updateList = new ArrayList<WidgetData>(updates);\r
- Collections.sort(updateList, new Comparator<WidgetData>() {\r
-\r
- private boolean isParent(WidgetData data, WidgetData possibleParent) {\r
- WidgetData parent = widgetData.get(data.object.getParent());\r
- if(parent == null) return false;\r
- else if(parent == possibleParent) return true;\r
- else return isParent(parent, possibleParent);\r
- }\r
- \r
- @Override\r
- public int compare(WidgetData arg0, WidgetData arg1) {\r
- if(arg0 == arg1) return 0;\r
- else if( isParent(arg0, arg1) ) return 1;\r
- else if( isParent(arg1, arg0) ) return -1;\r
- else return 0;\r
- }\r
- \r
- });\r
- \r
- for(WidgetData d : updateList) d.updateChildren();\r
- \r
- }\r
- \r
- public class DocumentListener extends ListenerAdapter<Integer> {\r
-\r
- int revision = -1;\r
- \r
- final private ListenerSupport support;\r
- final private String document;\r
- final private String input;\r
- private boolean performing = false;\r
- \r
- public DocumentListener(ListenerSupport support, String document, String input) {\r
- this.support = support;\r
- this.document = document;\r
- this.input = input;\r
- }\r
- \r
- public synchronized void perform() {\r
- if(performing) return;\r
- performing = true;\r
- try {\r
- Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/" + ProxyChildVariable.CONTEXT_BEGIN + input + "/" + ProxyChildVariable.CONTEXT_END, revision);\r
- revision = content.first;\r
- updateDocument(content.second);\r
- } finally {\r
- performing = false;\r
- }\r
- }\r
- \r
- Runnable updater = new Runnable() {\r
-\r
- @Override\r
- public void run() {\r
- perform();\r
-// Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/???" + input + "/???", revision);\r
-// revision = content.first;\r
-// updateDocument(content.second);\r
- }\r
- \r
- };\r
- \r
- @Override\r
- public void execute(Integer result) {\r
- IThreadWorkQueue thread = thread();\r
- if(thread.currentThreadAccess()) thread.syncExec(updater);\r
- else thread.asyncExec(updater);\r
- }\r
- \r
- @Override\r
- public boolean isDisposed() {\r
- return support.isDisposed();\r
- }\r
-\r
- };\r
- \r
- public void track(ListenerSupport support, String document, String input) {\r
- \r
- new DocumentListener(support, document, input).perform();\r
- \r
-// DocumentHistoryCollector.register(location, listener);\r
-// listener.execute(-1);\r
- \r
- }\r
- \r
- WidgetData getRoot() {\r
- return widgetData.get("root");\r
- }\r
- \r
- @SuppressWarnings("unchecked")\r
- <T> T getRootWidget() {\r
- return (T)getRoot().widget;\r
- }\r
- \r
- @Override\r
- public CommandManager<?, ?> getCommandManager(JSONObject object) {\r
- return commandMapping.getCommandManager(object.getType());\r
- }\r
- \r
-}\r
+package org.simantics.document.server.client;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.simantics.db.common.procedure.adapter.ListenerAdapter;
+import org.simantics.db.common.procedure.adapter.ListenerSupport;
+import org.simantics.db.layer0.variable.ProxyChildVariable;
+import org.simantics.document.server.DocumentHistoryCollector;
+import org.simantics.document.server.JSONObject;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.threads.IThreadWorkQueue;
+
+abstract public class DocumentClient implements Document {
+
+ protected HashMap<String, WidgetData> widgetData = new HashMap<String, WidgetData>();
+ private WidgetMapping mapping;
+ private CommandMapping commandMapping;
+
+ public DocumentClient(WidgetMapping mapping, CommandMapping commandMapping) {
+ this.mapping = mapping;
+ this.commandMapping = commandMapping;
+ }
+
+ @Override
+ public WidgetManager<?, ?> getManager(JSONObject object) {
+ return mapping.getWidget(object.getType());
+ }
+
+ @Override
+ public WidgetData getWidget(String id) {
+ return widgetData.get(id);
+ }
+
+ abstract public IThreadWorkQueue thread();
+
+ protected void updateDocument(Collection<JSONObject> objects) {
+
+ ArrayList<WidgetData> updatedData = new ArrayList<WidgetData>();
+ // Cache data
+ for (JSONObject object : objects) {
+ WidgetData datum = widgetData.get(object.getId());
+ if(datum == null) {
+ datum = new WidgetData(this, null, object);
+ widgetData.put(object.getId(), datum);
+ } else {
+ // This could replace changed information instead of replacing the whole object
+ datum.object = object;
+ }
+ updatedData.add(datum);
+ }
+
+ // Create widgets
+ for(WidgetData datum : updatedData) {
+ createElementIfNecessary(datum);
+ }
+
+ HashSet<WidgetData> updatedParents = new HashSet<WidgetData>();
+
+ // Update parent hierarchy
+ for(WidgetData datum : updatedData) {
+ updateChildmaps(datum, updatedParents);
+ }
+
+ updateTree(updatedParents);
+
+ // Set values
+ for(WidgetData datum : updatedData) {
+ datum.updateProperties();
+ datum.updateCommands();
+ }
+
+ }
+
+ private void createElementIfNecessary(WidgetData data) {
+ if(data.widget == null) {
+ data.widget = data.createElement();
+ }
+ }
+
+ private void updateChildmaps(WidgetData data, HashSet<WidgetData> updates) {
+
+ // Root
+ if(data.object == null) return;
+
+// System.err.println("p:" + data.object);
+// Object o = data.object.getParent();
+
+ WidgetData parent = widgetData.get(data.object.getParent());
+
+// System.out.println("parent:" + parent);
+
+ if(parent == null) return;
+
+ String parentOrd = data.object.getParentOrd();
+
+ WidgetData existing = parent.childmap.get(parentOrd);
+ if(!data.equals(existing)) {
+ updates.add(parent);
+ parent.childmap.put(parentOrd, data);
+ }
+
+ }
+
+ protected void updateTree(HashSet<WidgetData> updates) {
+
+ if(updates.isEmpty()) return;
+
+ ArrayList<WidgetData> updateList = new ArrayList<WidgetData>(updates);
+ Collections.sort(updateList, new Comparator<WidgetData>() {
+
+ private boolean isParent(WidgetData data, WidgetData possibleParent) {
+ WidgetData parent = widgetData.get(data.object.getParent());
+ if(parent == null) return false;
+ else if(parent == possibleParent) return true;
+ else return isParent(parent, possibleParent);
+ }
+
+ @Override
+ public int compare(WidgetData arg0, WidgetData arg1) {
+ if(arg0 == arg1) return 0;
+ else if( isParent(arg0, arg1) ) return 1;
+ else if( isParent(arg1, arg0) ) return -1;
+ else return 0;
+ }
+
+ });
+
+ for(WidgetData d : updateList) d.updateChildren();
+
+ }
+
+ public class DocumentListener extends ListenerAdapter<Integer> {
+
+ int revision = -1;
+
+ final private ListenerSupport support;
+ final private String document;
+ final private String input;
+ private boolean performing = false;
+
+ public DocumentListener(ListenerSupport support, String document, String input) {
+ this.support = support;
+ this.document = document;
+ this.input = input;
+ }
+
+ public synchronized void perform() {
+ if(performing) return;
+ performing = true;
+ try {
+ Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/" + ProxyChildVariable.CONTEXT_BEGIN + input + "/" + ProxyChildVariable.CONTEXT_END, revision);
+ revision = content.first;
+ updateDocument(content.second);
+ } finally {
+ performing = false;
+ }
+ }
+
+ Runnable updater = new Runnable() {
+
+ @Override
+ public void run() {
+ perform();
+// Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/???" + input + "/???", revision);
+// revision = content.first;
+// updateDocument(content.second);
+ }
+
+ };
+
+ @Override
+ public void execute(Integer result) {
+ IThreadWorkQueue thread = thread();
+ if(thread.currentThreadAccess()) thread.syncExec(updater);
+ else thread.asyncExec(updater);
+ }
+
+ @Override
+ public boolean isDisposed() {
+ return support.isDisposed();
+ }
+
+ };
+
+ public void track(ListenerSupport support, String document, String input) {
+
+ new DocumentListener(support, document, input).perform();
+
+// DocumentHistoryCollector.register(location, listener);
+// listener.execute(-1);
+
+ }
+
+ WidgetData getRoot() {
+ return widgetData.get("root");
+ }
+
+ @SuppressWarnings("unchecked")
+ <T> T getRootWidget() {
+ return (T)getRoot().widget;
+ }
+
+ @Override
+ public CommandManager<?, ?> getCommandManager(JSONObject object) {
+ return commandMapping.getCommandManager(object.getType());
+ }
+
+}