-package org.simantics.structural.synchronization.base;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-import gnu.trove.procedure.TObjectObjectProcedure;\r
-import gnu.trove.procedure.TObjectProcedure;\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-import java.io.PrintWriter;\r
-\r
-/**\r
- * The entry point to the mapping structure between Simantics database and a\r
- * designated solver. It is used to synchronize changes from Simantics to the\r
- * solver.\r
- * \r
- * @author Hannu Niemistö\r
- */\r
-abstract public class MappingBase<T extends ComponentBase<T>> {\r
-\r
- abstract public T getConfiguration();\r
- \r
- /**\r
- * Set of all components indexed by their UID.\r
- */\r
- transient protected THashMap<String, T> configurationByUid;\r
- \r
- /** \r
- * Set of components whose removal is delayed because they might\r
- * have been moved somewhere else.\r
- */\r
- transient THashSet<T> pendingRemoval = new THashSet<T>();\r
- \r
- /**\r
- * This is a structure that is used to return the state of the removed modules\r
- * when the removal is undone.\r
- */\r
- public transient StateUndoContextBase undoContext;\r
- \r
- public transient ComponentFactory<T> componentFactory;\r
- \r
- /**\r
- * The synchronization has processed all change sets before this change set \r
- * (excluding this change set).\r
- * It means that next synchronization operation should start examining changes\r
- * made in this revision and revisions after this.\r
- */\r
- public long currentRevision;\r
- \r
- /**\r
- * Tells whether the uids in the components can be used\r
- * in the synchronization. This is normally true, but\r
- * may be set temporarily false when export/import:in \r
- * the model.\r
- */\r
- private boolean trustUids;\r
-\r
- public MappingBase() {\r
- this(null, -1L, false);\r
- }\r
-\r
- public MappingBase(T configuration, boolean trustUids) {\r
- this(configuration, -1L, trustUids);\r
- }\r
-\r
- public MappingBase(T configuration, long currentRevision, boolean trustUids) {\r
- undoContext = createUndoContext();\r
- componentFactory = createComponentFactory();\r
- if(trustUids)\r
- createConfigurationById(configuration);\r
- this.currentRevision = currentRevision;\r
- this.trustUids = trustUids;\r
- }\r
- \r
- abstract public StateUndoContextBase createUndoContext();\r
- abstract public ComponentFactory<T> createComponentFactory();\r
-\r
- protected void createConfigurationById(T configuration) {\r
- THashMap<String, T> configurationByUid = new THashMap<String, T>();\r
- browseConfiguration(configurationByUid, configuration);\r
- this.configurationByUid = configurationByUid;\r
- }\r
-\r
- private void browseConfiguration(\r
- THashMap<String, T> configurationByUid,\r
- T configuration) {\r
- configurationByUid.put(configuration.uid, configuration);\r
- for(T child : configuration.getChildren()) {\r
- browseConfiguration(configurationByUid, child);\r
- child.parent = configuration;\r
- }\r
- }\r
-\r
- public T detachOrCreateComponent(String uid) {\r
- T result = configurationByUid.get(uid);\r
- if(result == null) {\r
- result = componentFactory.create(uid);\r
- configurationByUid.put(uid, result);\r
- }\r
- else {\r
- if(result.getParent() == null)\r
- pendingRemoval.remove(result);\r
- else\r
- result.getParent().detachByUid(uid);\r
- }\r
- return result;\r
- }\r
-\r
- /**\r
- * Marks that the component should be removed. The actual removal\r
- * is delayed until the call of {@link #removePending} so that if the\r
- * component is not actually removed but moved or renamed, we don't lose\r
- * its state.\r
- */\r
- public void addPendingRemoval(T component) {\r
- pendingRemoval.add(component);\r
- }\r
-\r
- public void printUidMap() {\r
- printUidMap(new PrintWriter(System.out));\r
- }\r
-\r
- public void printUidMap(final PrintWriter out) {\r
- out.println("Component tree");\r
- out.print(" ");\r
- getConfiguration().printConfiguration(out, 1);\r
- if(configurationByUid != null) {\r
- out.println("UIDs");\r
- configurationByUid.forEachEntry(new TObjectObjectProcedure<String, T>() {\r
- @Override\r
- public boolean execute(String a, T b) {\r
- out.println(" " + a + " (" + b.solverComponentName + ", " + b.componentId + ", " + b.uid + ")");\r
- return true;\r
- }\r
- });\r
- }\r
- }\r
-\r
- /**\r
- * Removes the component recursively.\r
- */\r
- public void remove(final Solver solver, T component) {\r
- if(configurationByUid != null)\r
- configurationByUid.remove(component.uid);\r
- if(component.getChildMap() != null)\r
- component.getChildMap().forEachValue(new TObjectProcedure<T>() {\r
- @Override\r
- public boolean execute(T child) {\r
- remove(solver, child);\r
- return true;\r
- }\r
- });\r
- if(component.componentId > 0 && !component.attached)\r
- solver.remove(component.componentId);\r
- }\r
- \r
- /**\r
- * Saves undo state recursively\r
- */\r
- public void saveUndoState(final Solver solver, T component) {\r
- if(component.getChildMap() != null)\r
- component.getChildMap().forEachValue(new TObjectProcedure<T>() {\r
- @Override\r
- public boolean execute(T child) {\r
- saveUndoState(solver, child);\r
- return true;\r
- }\r
- });\r
- else if(component.componentId > 0 && !component.attached)\r
- undoContext.saveState(solver, component.componentId, component.uid);\r
- }\r
-\r
- /**\r
- * Removes components that are marked pending with {@link #addPendingRemoval} method.\r
- */\r
- public void removePending(final Solver solver) {\r
- pendingRemoval.forEach(new TObjectProcedure<T>() {\r
- @Override\r
- public boolean execute(T component) {\r
- saveUndoState(solver, component);\r
- return true;\r
- }\r
- });\r
- pendingRemoval.forEach(new TObjectProcedure<T>() {\r
- @Override\r
- public boolean execute(T component) {\r
- remove(solver, component);\r
- return true;\r
- }\r
- });\r
- pendingRemoval.clear();\r
- }\r
- \r
- /**\r
- * Changes the {@link #trustUids} flag.\r
- */\r
- public void setTrustUids(boolean trustUids) {\r
- if(trustUids != this.trustUids) {\r
- this.trustUids = trustUids;\r
- if(trustUids) {\r
- T configuration = getConfiguration();\r
- if(configuration != null)\r
- createConfigurationById(configuration);\r
- }\r
- }\r
- if(!trustUids)\r
- configurationByUid = null;\r
- }\r
- \r
- public boolean getTrustUids() {\r
- return trustUids;\r
- }\r
-\r
- public void dispose() {\r
- if (configurationByUid != null)\r
- configurationByUid.clear();\r
- pendingRemoval.clear();\r
- }\r
-\r
-}\r
+package org.simantics.structural.synchronization.base;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectObjectProcedure;
+import gnu.trove.procedure.TObjectProcedure;
+import gnu.trove.set.hash.THashSet;
+
+import java.io.PrintWriter;
+
+/**
+ * The entry point to the mapping structure between Simantics database and a
+ * designated solver. It is used to synchronize changes from Simantics to the
+ * solver.
+ *
+ * @author Hannu Niemistö
+ */
+abstract public class MappingBase<T extends ComponentBase<T>> {
+
+ abstract public T getConfiguration();
+
+ /**
+ * Set of all components indexed by their UID.
+ */
+ transient protected THashMap<String, T> configurationByUid;
+
+ /**
+ * Set of components whose removal is delayed because they might
+ * have been moved somewhere else.
+ */
+ transient THashSet<T> pendingRemoval = new THashSet<T>();
+
+ /**
+ * This is a structure that is used to return the state of the removed modules
+ * when the removal is undone.
+ */
+ public transient StateUndoContextBase undoContext;
+
+ public transient ComponentFactory<T> componentFactory;
+
+ /**
+ * The synchronization has processed all change sets before this change set
+ * (excluding this change set).
+ * It means that next synchronization operation should start examining changes
+ * made in this revision and revisions after this.
+ */
+ public long currentRevision;
+
+ /**
+ * Tells whether the uids in the components can be used
+ * in the synchronization. This is normally true, but
+ * may be set temporarily false when export/import:in
+ * the model.
+ */
+ private boolean trustUids;
+
+ public MappingBase() {
+ this(null, -1L, false);
+ }
+
+ public MappingBase(T configuration, boolean trustUids) {
+ this(configuration, -1L, trustUids);
+ }
+
+ public MappingBase(T configuration, long currentRevision, boolean trustUids) {
+ undoContext = createUndoContext();
+ componentFactory = createComponentFactory();
+ if(trustUids)
+ createConfigurationById(configuration);
+ this.currentRevision = currentRevision;
+ this.trustUids = trustUids;
+ }
+
+ abstract public StateUndoContextBase createUndoContext();
+ abstract public ComponentFactory<T> createComponentFactory();
+
+ protected void createConfigurationById(T configuration) {
+ THashMap<String, T> configurationByUid = new THashMap<String, T>();
+ browseConfiguration(configurationByUid, configuration);
+ this.configurationByUid = configurationByUid;
+ }
+
+ private void browseConfiguration(
+ THashMap<String, T> configurationByUid,
+ T configuration) {
+ configurationByUid.put(configuration.uid, configuration);
+ for(T child : configuration.getChildren()) {
+ browseConfiguration(configurationByUid, child);
+ child.parent = configuration;
+ }
+ }
+
+ public T detachOrCreateComponent(String uid) {
+ T result = configurationByUid.get(uid);
+ if(result == null) {
+ result = componentFactory.create(uid);
+ configurationByUid.put(uid, result);
+ }
+ else {
+ if(result.getParent() == null)
+ pendingRemoval.remove(result);
+ else
+ result.getParent().detachByUid(uid);
+ }
+ return result;
+ }
+
+ /**
+ * Marks that the component should be removed. The actual removal
+ * is delayed until the call of {@link #removePending} so that if the
+ * component is not actually removed but moved or renamed, we don't lose
+ * its state.
+ */
+ public void addPendingRemoval(T component) {
+ pendingRemoval.add(component);
+ }
+
+ public void printUidMap() {
+ printUidMap(new PrintWriter(System.out));
+ }
+
+ public void printUidMap(final PrintWriter out) {
+ out.println("Component tree");
+ out.print(" ");
+ getConfiguration().printConfiguration(out, 1);
+ if(configurationByUid != null) {
+ out.println("UIDs");
+ configurationByUid.forEachEntry(new TObjectObjectProcedure<String, T>() {
+ @Override
+ public boolean execute(String a, T b) {
+ out.println(" " + a + " (" + b.solverComponentName + ", " + b.componentId + ", " + b.uid + ")");
+ return true;
+ }
+ });
+ }
+ }
+
+ /**
+ * Removes the component recursively.
+ */
+ public void remove(final Solver solver, T component) {
+ if(configurationByUid != null)
+ configurationByUid.remove(component.uid);
+ if(component.getChildMap() != null)
+ component.getChildMap().forEachValue(new TObjectProcedure<T>() {
+ @Override
+ public boolean execute(T child) {
+ remove(solver, child);
+ return true;
+ }
+ });
+ if(component.componentId > 0 && !component.attached)
+ solver.remove(component.componentId);
+ }
+
+ /**
+ * Saves undo state recursively
+ */
+ public void saveUndoState(final Solver solver, T component) {
+ if(component.getChildMap() != null)
+ component.getChildMap().forEachValue(new TObjectProcedure<T>() {
+ @Override
+ public boolean execute(T child) {
+ saveUndoState(solver, child);
+ return true;
+ }
+ });
+ else if(component.componentId > 0 && !component.attached)
+ undoContext.saveState(solver, component.componentId, component.uid);
+ }
+
+ /**
+ * Removes components that are marked pending with {@link #addPendingRemoval} method.
+ */
+ public void removePending(final Solver solver) {
+ pendingRemoval.forEach(new TObjectProcedure<T>() {
+ @Override
+ public boolean execute(T component) {
+ saveUndoState(solver, component);
+ return true;
+ }
+ });
+ pendingRemoval.forEach(new TObjectProcedure<T>() {
+ @Override
+ public boolean execute(T component) {
+ remove(solver, component);
+ return true;
+ }
+ });
+ pendingRemoval.clear();
+ }
+
+ /**
+ * Changes the {@link #trustUids} flag.
+ */
+ public void setTrustUids(boolean trustUids) {
+ if(trustUids != this.trustUids) {
+ this.trustUids = trustUids;
+ if(trustUids) {
+ T configuration = getConfiguration();
+ if(configuration != null)
+ createConfigurationById(configuration);
+ }
+ }
+ if(!trustUids)
+ configurationByUid = null;
+ }
+
+ public boolean getTrustUids() {
+ return trustUids;
+ }
+
+ public void dispose() {
+ if (configurationByUid != null)
+ configurationByUid.clear();
+ pendingRemoval.clear();
+ }
+
+ public boolean hasPendingRemovals() {
+ return !pendingRemoval.isEmpty();
+ }
+
+}