]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.document.server/src/org/simantics/document/server/client/DocumentClient.java
Work in progress
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / client / DocumentClient.java
1 package org.simantics.document.server.client;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9
10 import org.simantics.db.common.procedure.adapter.ListenerAdapter;
11 import org.simantics.db.common.procedure.adapter.ListenerSupport;
12 import org.simantics.db.layer0.variable.ProxyChildVariable;
13 import org.simantics.document.server.DocumentHistoryCollector;
14 import org.simantics.document.server.JSONObject;
15 import org.simantics.utils.datastructures.Pair;
16 import org.simantics.utils.threads.IThreadWorkQueue;
17
18 abstract public class DocumentClient implements Document {
19
20         protected HashMap<String, WidgetData> widgetData = new HashMap<String, WidgetData>();
21         private WidgetMapping mapping;
22     private CommandMapping commandMapping;
23         
24         public DocumentClient(WidgetMapping mapping, CommandMapping commandMapping) {
25                 this.mapping = mapping;
26                 this.commandMapping = commandMapping;
27         }
28
29         @Override
30         public WidgetManager<?, ?> getManager(JSONObject object) {
31                 WidgetManager<?, ?>  result = mapping.getWidget(object.getType());
32                 if(result == null)
33                         throw new RuntimeException("No manager for type " + object.getType());
34                 return result;
35         }
36         
37         @Override
38         public WidgetData getWidget(String id) {
39                 return widgetData.get(id);
40         }
41         
42         abstract public IThreadWorkQueue thread();
43         
44         protected void updateDocument(Collection<JSONObject> objects) {
45
46                 ArrayList<WidgetData> updatedData = new ArrayList<WidgetData>();
47                 // Cache data
48                 for (JSONObject object : objects) {
49                         WidgetData datum = widgetData.get(object.getId());
50                         if(datum == null) {
51                                 datum = new WidgetData(this, null, object);
52                                 widgetData.put(object.getId(), datum);
53                         } else {
54                                 // This could replace changed information instead of replacing the whole object
55                                 datum.object = object;
56                         }
57                         updatedData.add(datum);
58                 }
59
60                 // Create widgets
61                 for(WidgetData datum : updatedData) {
62                         createElementIfNecessary(datum);
63                 }
64                 
65                 HashSet<WidgetData> updatedParents = new HashSet<WidgetData>(); 
66                 
67                 // Update parent hierarchy
68                 for(WidgetData datum : updatedData) {
69                         updateChildmaps(datum, updatedParents);
70                 }
71                 
72                 updateTree(updatedParents);
73                 
74                 // Set values
75                 for(WidgetData datum : updatedData) {
76                         datum.updateProperties();
77                         datum.updateCommands();
78                 }
79
80         }
81         
82         private void createElementIfNecessary(WidgetData data) {
83                 if(data.widget == null) { 
84                         data.widget = data.createElement();
85                 }
86         }
87
88         private void updateChildmaps(WidgetData data, HashSet<WidgetData> updates) {
89
90                 // Root
91                 if(data.object == null) return;
92                 
93 //              System.err.println("p:" + data.object);
94 //              Object o = data.object.getParent();
95                 
96                 WidgetData parent = widgetData.get(data.object.getParent()); 
97
98 //              System.out.println("parent:" + parent);
99
100                 if(parent == null) return;
101                 
102                 String parentOrd = data.object.getParentOrd();
103                 
104                 WidgetData existing = parent.childmap.get(parentOrd);
105                 if(!data.equals(existing)) {
106                         updates.add(parent);
107                         parent.childmap.put(parentOrd, data);
108                 }
109                 
110         }
111
112         protected void updateTree(HashSet<WidgetData> updates) {
113                 
114                 if(updates.isEmpty()) return;
115                 
116                 ArrayList<WidgetData> updateList = new ArrayList<WidgetData>(updates);
117                 Collections.sort(updateList, new Comparator<WidgetData>() {
118
119                         private boolean isParent(WidgetData data, WidgetData possibleParent) {
120                                 WidgetData parent = widgetData.get(data.object.getParent());
121                                 if(parent == null) return false;
122                                 else if(parent == possibleParent) return true;
123                                 else return isParent(parent, possibleParent);
124                         }
125                         
126                         @Override
127                         public int compare(WidgetData arg0, WidgetData arg1) {
128                                 if(arg0 == arg1) return 0;
129                                 else if( isParent(arg0, arg1) ) return 1;
130                                 else if( isParent(arg1, arg0) ) return -1;
131                                 else return 0;
132                         }
133                         
134                 });
135                         
136                 for(WidgetData d : updateList) d.updateChildren();
137                 
138         }
139         
140         public class DocumentListener extends ListenerAdapter<Integer> {
141
142                 int revision = -1;
143                 
144                 final private ListenerSupport support;
145                 final private String document;
146                 final private String input;
147                 private boolean performing = false;
148                 
149                 public DocumentListener(ListenerSupport support, String document, String input) {
150                         this.support = support;
151                         this.document = document;
152                         this.input = input;
153                 }
154                 
155                 public synchronized void perform() {
156                     if(performing) return;
157                     performing = true;
158                     try {
159                         Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/" + ProxyChildVariable.CONTEXT_BEGIN  + input + "/" + ProxyChildVariable.CONTEXT_END, revision);
160                         revision = content.first;
161                         updateDocument(content.second);
162                     } finally {
163                         performing = false;
164                     }
165                 }
166                 
167                 Runnable updater = new Runnable() {
168
169                         @Override
170                         public void run() {
171                                 perform();
172 //                              Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/???" + input + "/???", revision);
173 //                              revision = content.first;
174 //                              updateDocument(content.second);
175                         }
176                         
177                 };
178                 
179                 @Override
180                 public void execute(Integer result) {
181                         IThreadWorkQueue thread = thread();
182                         if(thread.currentThreadAccess()) thread.syncExec(updater);
183                         else thread.asyncExec(updater);
184                 }
185                 
186                 @Override
187                 public boolean isDisposed() {
188                         return support.isDisposed();
189                 }
190
191         };
192         
193         public void track(ListenerSupport support, String document, String input) {
194                 
195                 new DocumentListener(support, document, input).perform();
196                 
197 //              DocumentHistoryCollector.register(location, listener);
198 //              listener.execute(-1);
199                 
200         }
201         
202         WidgetData getRoot() {
203                 return widgetData.get("root");
204         }
205         
206         @SuppressWarnings("unchecked")
207         <T> T getRootWidget() {
208                 return (T)getRoot().widget;
209         }
210         
211         @Override
212         public CommandManager<?, ?> getCommandManager(JSONObject object) {
213             return commandMapping.getCommandManager(object.getType());
214         }
215         
216 }