1 package org.simantics.document.server.client;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Collection;
\r
5 import java.util.Collections;
\r
6 import java.util.Comparator;
\r
7 import java.util.HashMap;
\r
8 import java.util.HashSet;
\r
10 import org.simantics.db.common.procedure.adapter.ListenerAdapter;
\r
11 import org.simantics.db.common.procedure.adapter.ListenerSupport;
\r
12 import org.simantics.db.layer0.variable.ProxyChildVariable;
\r
13 import org.simantics.document.server.DocumentHistoryCollector;
\r
14 import org.simantics.document.server.JSONObject;
\r
15 import org.simantics.utils.datastructures.Pair;
\r
16 import org.simantics.utils.threads.IThreadWorkQueue;
\r
18 abstract public class DocumentClient implements Document {
\r
20 protected HashMap<String, WidgetData> widgetData = new HashMap<String, WidgetData>();
\r
21 private WidgetMapping mapping;
\r
22 private CommandMapping commandMapping;
\r
24 public DocumentClient(WidgetMapping mapping, CommandMapping commandMapping) {
\r
25 this.mapping = mapping;
\r
26 this.commandMapping = commandMapping;
\r
30 public WidgetManager<?, ?> getManager(JSONObject object) {
\r
31 return mapping.getWidget(object.getType());
\r
35 public WidgetData getWidget(String id) {
\r
36 return widgetData.get(id);
\r
39 abstract public IThreadWorkQueue thread();
\r
41 protected void updateDocument(Collection<JSONObject> objects) {
\r
43 ArrayList<WidgetData> updatedData = new ArrayList<WidgetData>();
\r
45 for (JSONObject object : objects) {
\r
46 WidgetData datum = widgetData.get(object.getId());
\r
48 datum = new WidgetData(this, null, object);
\r
49 widgetData.put(object.getId(), datum);
\r
51 // This could replace changed information instead of replacing the whole object
\r
52 datum.object = object;
\r
54 updatedData.add(datum);
\r
58 for(WidgetData datum : updatedData) {
\r
59 createElementIfNecessary(datum);
\r
62 HashSet<WidgetData> updatedParents = new HashSet<WidgetData>();
\r
64 // Update parent hierarchy
\r
65 for(WidgetData datum : updatedData) {
\r
66 updateChildmaps(datum, updatedParents);
\r
69 updateTree(updatedParents);
\r
72 for(WidgetData datum : updatedData) {
\r
73 datum.updateProperties();
\r
74 datum.updateCommands();
\r
79 private void createElementIfNecessary(WidgetData data) {
\r
80 if(data.widget == null) {
\r
81 data.widget = data.createElement();
\r
85 private void updateChildmaps(WidgetData data, HashSet<WidgetData> updates) {
\r
88 if(data.object == null) return;
\r
90 // System.err.println("p:" + data.object);
\r
91 // Object o = data.object.getParent();
\r
93 WidgetData parent = widgetData.get(data.object.getParent());
\r
95 // System.out.println("parent:" + parent);
\r
97 if(parent == null) return;
\r
99 String parentOrd = data.object.getParentOrd();
\r
101 WidgetData existing = parent.childmap.get(parentOrd);
\r
102 if(!data.equals(existing)) {
\r
103 updates.add(parent);
\r
104 parent.childmap.put(parentOrd, data);
\r
109 protected void updateTree(HashSet<WidgetData> updates) {
\r
111 if(updates.isEmpty()) return;
\r
113 ArrayList<WidgetData> updateList = new ArrayList<WidgetData>(updates);
\r
114 Collections.sort(updateList, new Comparator<WidgetData>() {
\r
116 private boolean isParent(WidgetData data, WidgetData possibleParent) {
\r
117 WidgetData parent = widgetData.get(data.object.getParent());
\r
118 if(parent == null) return false;
\r
119 else if(parent == possibleParent) return true;
\r
120 else return isParent(parent, possibleParent);
\r
124 public int compare(WidgetData arg0, WidgetData arg1) {
\r
125 if(arg0 == arg1) return 0;
\r
126 else if( isParent(arg0, arg1) ) return 1;
\r
127 else if( isParent(arg1, arg0) ) return -1;
\r
133 for(WidgetData d : updateList) d.updateChildren();
\r
137 public class DocumentListener extends ListenerAdapter<Integer> {
\r
141 final private ListenerSupport support;
\r
142 final private String document;
\r
143 final private String input;
\r
144 private boolean performing = false;
\r
146 public DocumentListener(ListenerSupport support, String document, String input) {
\r
147 this.support = support;
\r
148 this.document = document;
\r
149 this.input = input;
\r
152 public synchronized void perform() {
\r
153 if(performing) return;
\r
156 Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/" + ProxyChildVariable.CONTEXT_BEGIN + input + "/" + ProxyChildVariable.CONTEXT_END, revision);
\r
157 revision = content.first;
\r
158 updateDocument(content.second);
\r
160 performing = false;
\r
164 Runnable updater = new Runnable() {
\r
167 public void run() {
\r
169 // Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/???" + input + "/???", revision);
\r
170 // revision = content.first;
\r
171 // updateDocument(content.second);
\r
177 public void execute(Integer result) {
\r
178 IThreadWorkQueue thread = thread();
\r
179 if(thread.currentThreadAccess()) thread.syncExec(updater);
\r
180 else thread.asyncExec(updater);
\r
184 public boolean isDisposed() {
\r
185 return support.isDisposed();
\r
190 public void track(ListenerSupport support, String document, String input) {
\r
192 new DocumentListener(support, document, input).perform();
\r
194 // DocumentHistoryCollector.register(location, listener);
\r
195 // listener.execute(-1);
\r
199 WidgetData getRoot() {
\r
200 return widgetData.get("root");
\r
203 @SuppressWarnings("unchecked")
\r
204 <T> T getRootWidget() {
\r
205 return (T)getRoot().widget;
\r
209 public CommandManager<?, ?> getCommandManager(JSONObject object) {
\r
210 return commandMapping.getCommandManager(object.getType());
\r