]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/base/MappingBase.java
Sync git svn branch with SVN repository r33366.
[simantics/platform.git] / bundles / org.simantics.structural.synchronization.client / src / org / simantics / structural / synchronization / base / MappingBase.java
1 package org.simantics.structural.synchronization.base;\r
2 \r
3 import gnu.trove.map.hash.THashMap;\r
4 import gnu.trove.procedure.TObjectObjectProcedure;\r
5 import gnu.trove.procedure.TObjectProcedure;\r
6 import gnu.trove.set.hash.THashSet;\r
7 \r
8 import java.io.PrintWriter;\r
9 \r
10 /**\r
11  * The entry point to the mapping structure between Simantics database and a\r
12  * designated solver. It is used to synchronize changes from Simantics to the\r
13  * solver.\r
14  * \r
15  * @author Hannu Niemistö\r
16  */\r
17 abstract public class MappingBase<T extends ComponentBase<T>> {\r
18 \r
19         abstract public T getConfiguration();\r
20     \r
21     /**\r
22      * Set of all components indexed by their UID.\r
23      */\r
24     transient protected THashMap<String, T> configurationByUid;\r
25     \r
26     /** \r
27      * Set of components whose removal is delayed because they might\r
28      * have been moved somewhere else.\r
29      */\r
30     transient THashSet<T> pendingRemoval = new THashSet<T>();\r
31     \r
32     /**\r
33      * This is a structure that is used to return the state of the removed modules\r
34      * when the removal is undone.\r
35      */\r
36     public transient StateUndoContextBase undoContext;\r
37     \r
38     public transient ComponentFactory<T> componentFactory;\r
39     \r
40     /**\r
41      * The synchronization has processed all change sets before this change set \r
42      * (excluding this change set).\r
43      * It means that next synchronization operation should start examining changes\r
44      * made in this revision and revisions after this.\r
45      */\r
46     public long currentRevision;\r
47     \r
48     /**\r
49      * Tells whether the uids in the components can be used\r
50      * in the synchronization. This is normally true, but\r
51      * may be set temporarily false when export/import:in \r
52      * the model.\r
53      */\r
54     private boolean trustUids;\r
55 \r
56     public MappingBase() {\r
57         this(null, -1L, false);\r
58     }\r
59 \r
60     public MappingBase(T configuration, boolean trustUids) {\r
61         this(configuration, -1L, trustUids);\r
62     }\r
63 \r
64     public MappingBase(T configuration, long currentRevision, boolean trustUids) {\r
65         undoContext = createUndoContext();\r
66         componentFactory = createComponentFactory();\r
67         if(trustUids)\r
68             createConfigurationById(configuration);\r
69         this.currentRevision = currentRevision;\r
70         this.trustUids = trustUids;\r
71     }\r
72     \r
73     abstract public StateUndoContextBase createUndoContext();\r
74     abstract public ComponentFactory<T> createComponentFactory();\r
75 \r
76     protected void createConfigurationById(T configuration) {\r
77         THashMap<String, T> configurationByUid = new THashMap<String, T>();\r
78         browseConfiguration(configurationByUid, configuration);\r
79         this.configurationByUid = configurationByUid;\r
80     }\r
81 \r
82     private void browseConfiguration(\r
83             THashMap<String, T> configurationByUid,\r
84             T configuration) {\r
85         configurationByUid.put(configuration.uid, configuration);\r
86         for(T child : configuration.getChildren()) {\r
87             browseConfiguration(configurationByUid, child);\r
88             child.parent = configuration;\r
89         }\r
90     }\r
91 \r
92     public T detachOrCreateComponent(String uid) {\r
93         T result = configurationByUid.get(uid);\r
94         if(result == null) {\r
95             result = componentFactory.create(uid);\r
96             configurationByUid.put(uid, result);\r
97         }\r
98         else {\r
99             if(result.getParent() == null)\r
100                 pendingRemoval.remove(result);\r
101             else\r
102                 result.getParent().detachByUid(uid);\r
103         }\r
104         return result;\r
105     }\r
106 \r
107     /**\r
108      * Marks that the component should be removed. The actual removal\r
109      * is delayed until the call of {@link #removePending} so that if the\r
110      * component is not actually removed but moved or renamed, we don't lose\r
111      * its state.\r
112      */\r
113     public void addPendingRemoval(T component) {\r
114         pendingRemoval.add(component);\r
115     }\r
116 \r
117     public void printUidMap() {\r
118         printUidMap(new PrintWriter(System.out));\r
119     }\r
120 \r
121     public void printUidMap(final PrintWriter out) {\r
122         out.println("Component tree");\r
123         out.print("    ");\r
124         getConfiguration().printConfiguration(out, 1);\r
125         if(configurationByUid != null) {\r
126             out.println("UIDs");\r
127             configurationByUid.forEachEntry(new TObjectObjectProcedure<String, T>() {\r
128                 @Override\r
129                 public boolean execute(String a, T b) {\r
130                     out.println("    " + a + " (" + b.solverComponentName + ", " + b.componentId + ", " + b.uid + ")");\r
131                     return true;\r
132                 }\r
133             });\r
134         }\r
135     }\r
136 \r
137     /**\r
138      * Removes the component recursively.\r
139      */\r
140     public void remove(final Solver solver, T component) {\r
141         if(configurationByUid != null)\r
142             configurationByUid.remove(component.uid);\r
143         if(component.getChildMap() != null)\r
144             component.getChildMap().forEachValue(new TObjectProcedure<T>() {\r
145                 @Override\r
146                 public boolean execute(T child) {\r
147                     remove(solver, child);\r
148                     return true;\r
149                 }\r
150             });\r
151         if(component.componentId > 0 && !component.attached)\r
152             solver.remove(component.componentId);\r
153     }\r
154     \r
155     /**\r
156      * Saves undo state recursively\r
157      */\r
158     public void saveUndoState(final Solver solver, T component) {\r
159         if(component.getChildMap() != null)\r
160             component.getChildMap().forEachValue(new TObjectProcedure<T>() {\r
161                 @Override\r
162                 public boolean execute(T child) {\r
163                     saveUndoState(solver, child);\r
164                     return true;\r
165                 }\r
166             });\r
167         else if(component.componentId > 0 && !component.attached)\r
168             undoContext.saveState(solver, component.componentId, component.uid);\r
169     }\r
170 \r
171     /**\r
172      * Removes components that are marked pending with {@link #addPendingRemoval} method.\r
173      */\r
174     public void removePending(final Solver solver) {\r
175         pendingRemoval.forEach(new TObjectProcedure<T>() {\r
176             @Override\r
177             public boolean execute(T component) {\r
178                 saveUndoState(solver, component);\r
179                 return true;\r
180             }\r
181         });\r
182         pendingRemoval.forEach(new TObjectProcedure<T>() {\r
183             @Override\r
184             public boolean execute(T component) {\r
185                 remove(solver, component);\r
186                 return true;\r
187             }\r
188         });\r
189         pendingRemoval.clear();\r
190     }\r
191     \r
192     /**\r
193      * Changes the {@link #trustUids} flag.\r
194      */\r
195     public void setTrustUids(boolean trustUids) {\r
196         if(trustUids != this.trustUids) {\r
197             this.trustUids = trustUids;\r
198             if(trustUids) {\r
199                 T configuration = getConfiguration();\r
200                 if(configuration != null)\r
201                     createConfigurationById(configuration);\r
202             }\r
203         }\r
204         if(!trustUids)\r
205             configurationByUid = null;\r
206     }\r
207     \r
208     public boolean getTrustUids() {\r
209         return trustUids;\r
210     }\r
211 \r
212     public void dispose() {\r
213         if (configurationByUid != null)\r
214             configurationByUid.clear();\r
215         pendingRemoval.clear();\r
216     }\r
217 \r
218 }\r