]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/ExistingInstancesRemover.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / adapters / ExistingInstancesRemover.java
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/ExistingInstancesRemover.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/ExistingInstancesRemover.java
new file mode 100644 (file)
index 0000000..a2b4fc3
--- /dev/null
@@ -0,0 +1,272 @@
+package org.simantics.modeling.adapters;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.util.URIStringUtils;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Instances;\r
+import org.simantics.db.layer0.adapter.Remover;\r
+import org.simantics.db.layer0.adapter.impl.AbstractRemover;\r
+import org.simantics.db.layer0.adapter.impl.EntityRemover;\r
+import org.simantics.db.layer0.exception.CannotRemoveException;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.db.layer0.util.RemoverUtil;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.adapters.RemoveInstancesDialog.Content;\r
+import org.simantics.utils.strings.AlphanumComparator;\r
+import org.simantics.utils.ui.BundleUtils;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class ExistingInstancesRemover extends AbstractRemover {\r
+\r
+       protected String typeDescription;\r
+\r
+       public ExistingInstancesRemover(Resource resource, String removedTypeDescription) {\r
+               super(resource);\r
+               this.typeDescription = removedTypeDescription;\r
+       }\r
+\r
+       @Override\r
+       public void remove(WriteGraph graph) throws DatabaseException {\r
+               remove(graph, resource, resource, resource);\r
+       }\r
+\r
+       protected void remove(WriteGraph graph, Resource resource, Resource typeResource, Resource typeNameResource) throws DatabaseException {\r
+//             System.out.println("resource: " + NameUtils.getURIOrSafeNameInternal(graph, resource));\r
+//             System.out.println("type resource: " + NameUtils.getURIOrSafeNameInternal(graph, typeResource));\r
+//             System.out.println("type name resource: " + NameUtils.getURIOrSafeNameInternal(graph, typeNameResource));\r
+               if (Layer0Utils.isContainerPublished(graph, resource))\r
+                       throw new CannotRemoveException("Items in published libraries cannot be removed. Please create a new version to perform modifications.");\r
+\r
+               Resource root = graph.syncRequest(new PossibleIndexRoot(resource));\r
+               if (root == null) {\r
+                       justRemove(graph);\r
+                       // Not part of an index root? Just remove everything because\r
+                       // we can't find instances anyway.\r
+                       return;\r
+               }\r
+\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               final String componentTypeName = graph.getPossibleRelatedValue(typeNameResource, L0.HasName, Bindings.STRING);\r
+               if (componentTypeName == null) {\r
+                       justRemove(graph);\r
+                       return;\r
+               }\r
+\r
+               Set<Resource> instances = discoverInstances(graph, typeResource);\r
+               if (!instances.isEmpty()) {\r
+                       confirmRemoval(graph, instances, typeDescription, componentTypeName);\r
+               } else {\r
+                       justRemove(graph);\r
+               }\r
+       }\r
+\r
+       protected Set<Resource> discoverInstances(WriteGraph graph, Resource type) throws DatabaseException {\r
+               Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(type));\r
+               if (indexRoot == null)\r
+                       return Collections.emptySet();\r
+\r
+//             @SuppressWarnings("rawtypes")\r
+//             Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);\r
+//             @SuppressWarnings("unchecked")\r
+//             List<Map<String, Object>> result = (List<Map<String, Object>>) modules.apply(graph, root, "Types:\"" + IndexQueries.escape(componentTypeName) + "\"");\r
+//             if (result.isEmpty()) {\r
+//                     justRemove(graph);\r
+//                     return;\r
+//             }\r
+//\r
+//             final Set<Resource> instances = new HashSet<Resource>();\r
+//             for (Map<String, Object> entry : result) {\r
+//                     Resource c = (Resource) entry.get(Dependencies.FIELD_RESOURCE);\r
+//                     if (c != null && graph.hasStatement(c, L0.InstanceOf, resource)) {\r
+//                             instances.add(c);\r
+//                     }\r
+//             }\r
+\r
+               Set<Resource> result = new THashSet<Resource>();\r
+               Instances search = graph.adapt(type, Instances.class);\r
+               discoverInstances(graph, type, indexRoot, search, result);\r
+\r
+               // It is possible that resource is an instance of the specified type\r
+               // also. However we assume that the specified resource is removed last\r
+               // only after all the instances have been removed. That's why we remove\r
+               // resource from the calculated set of instances at this point.\r
+               result.remove(resource);\r
+\r
+//             for (Resource r : result)\r
+//                     System.out.println("found instance: " + NameUtils.getURIOrSafeNameInternal(graph, r));\r
+\r
+               return result;\r
+       }\r
+\r
+       private void discoverInstances(WriteGraph graph, Resource typeResource, Resource indexRoot, Instances instances, Set<Resource> result) throws DatabaseException {\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               Collection<Resource> rs = instances.find(graph, indexRoot);\r
+               result.addAll(rs);\r
+\r
+               for (Resource linkee : graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse)) {\r
+                       discoverInstances(graph, typeResource, linkee, instances, result);\r
+               }\r
+       }\r
+\r
+       protected void confirmRemoval(WriteGraph graph, final Set<Resource> instances, final String typeDescription, final String typeName) throws DatabaseException {\r
+               Map<Resource, String> instanceAddresses = resolveInstanceAddresses(graph, instances);\r
+               Map<Resource, String> unremovable = findUnremovable(graph, instances);\r
+               final RemoveInstancesDialog.Content[] content = new RemoveInstancesDialog.Content[instanceAddresses.size()];\r
+               int i = 0;\r
+               ImageDescriptor problemImage = BundleUtils.getImageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png");\r
+               for (Map.Entry<Resource, String> entry : instanceAddresses.entrySet()) {\r
+                       content[i] = new RemoveInstancesDialog.Content(entry.getValue());\r
+                       content[i].details = unremovable.get(entry.getKey());\r
+                       if (content[i].details != null) {\r
+                               content[i].image = problemImage;\r
+                       }\r
+                       ++i;\r
+               }\r
+               Arrays.sort(content, new Comparator<RemoveInstancesDialog.Content>() {\r
+                       @Override\r
+                       public int compare(Content o1, Content o2) {\r
+                               return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.label, o2.label);\r
+                       }\r
+               });\r
+\r
+               if (!unremovable.isEmpty()) {\r
+                       if (PlatformUI.isWorkbenchRunning()) {\r
+                               PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
+                                       @Override\r
+                                       public void run() {\r
+                                               RemoveInstancesDialog dialog = new RemoveInstancesDialog(\r
+                                                               PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
+                                                               "Cannot Remove  " + typeDescription,\r
+                                                               typeDescription + " '" + typeName\r
+                                                               + "' is still in use and all of its "\r
+                                                               + instances.size()\r
+                                                               + " instances cannot be removed.\n\nSelect instances marked with errors from the table below to see why they cannot be removed.",\r
+                                                               MessageDialog.ERROR,\r
+                                                               new String[] { IDialogConstants.OK_LABEL },\r
+                                                               0,\r
+                                                               content);\r
+                                               dialog.open();\r
+                                       }\r
+                               });\r
+                       }\r
+                       return;\r
+               }\r
+\r
+               final Session session = graph.getSession();\r
+\r
+               if (PlatformUI.isWorkbenchRunning()) {\r
+                       PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       RemoveInstancesDialog dialog = new RemoveInstancesDialog(\r
+                                                       PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
+                                                       "Remove " + typeDescription + "?",\r
+                                                       typeDescription + " '" + typeName + "' is still in use. Are you sure you want to remove it and all its " + instances.size() + " instances?",\r
+                                                       content);\r
+                                       int result = dialog.open();\r
+                                       boolean doIt = result == IDialogConstants.OK_ID;\r
+                                       if (!doIt)\r
+                                               return;\r
+                                       session.asyncRequest(new WriteRequest() {\r
+                                               @Override\r
+                                               public void perform(WriteGraph graph) throws DatabaseException {\r
+                                                       justRemoveWithInstances(graph, instances);\r
+                                               }\r
+                                       });\r
+                               }\r
+                       });\r
+               } else {\r
+                       // Just do it without confirmation when no user agent is available.\r
+                       justRemoveWithInstances(graph, instances);\r
+               }\r
+       }\r
+\r
+       protected void justRemoveWithInstances(WriteGraph graph, Collection<Resource> instances) throws DatabaseException {\r
+               for (Resource instance : instances)\r
+                       RemoverUtil.remove(graph, instance);\r
+               justRemove(graph);\r
+       }\r
+\r
+       protected Map<Resource, String> resolveInstanceAddresses(ReadGraph graph, Set<Resource> instances) throws DatabaseException {\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               ModelingResources MOD = ModelingResources.getInstance(graph);\r
+               Map<Resource, String> result = new THashMap<Resource, String>();\r
+               for (Resource instance : instances) {\r
+                       Resource component = graph.getPossibleObject(instance, MOD.ElementToComponent);\r
+                       if (component != null)\r
+                               instance = component;\r
+                       String instanceUri = graph.getPossibleURI(instance);\r
+                       if (instanceUri != null) {\r
+                               Resource root = graph.syncRequest(new PossibleIndexRoot(instance));\r
+                               if (root != null) {\r
+                                       Resource rootParent = graph.getPossibleObject(root, L0.PartOf);\r
+                                       if (rootParent == null)\r
+                                               rootParent = root;\r
+\r
+                                       String rootUri = graph.getPossibleURI(rootParent);\r
+                                       if (rootUri != null) {\r
+                                               String instanceRelativeUri = instanceUri.substring(rootUri.length());\r
+                                               result.put(instance, URIStringUtils.unescape( instanceRelativeUri ));\r
+                                               continue;\r
+                                       }\r
+                               }\r
+\r
+                               result.put(instance, URIStringUtils.unescape( instanceUri ));\r
+                               continue;\r
+                       }\r
+\r
+                       // Fallback logic\r
+                       result.put(instance, NameUtils.getSafeName(graph, instance, true));\r
+               }\r
+               return result;\r
+       }\r
+\r
+       protected void justRemove(WriteGraph graph) throws DatabaseException {\r
+               graph.deny(resource, Layer0.getInstance(graph).PartOf);\r
+               EntityRemover.remove(graph, resource);\r
+       }\r
+\r
+       private Map<Resource, String> findUnremovable(ReadGraph graph, Collection<Resource> instances) throws DatabaseException {\r
+               Map<Resource, String> result = null;\r
+               Map<Object, Object> aux = new HashMap<Object, Object>();\r
+               for (Resource r : instances) {\r
+                       Remover remover = graph.getPossibleAdapter(r, Remover.class);\r
+                       if (remover == null)\r
+                               continue;\r
+                       aux.clear();\r
+                       String problem = remover.canRemove(graph, aux);\r
+                       if (problem != null) {\r
+                               if (result == null)\r
+                                       result = new THashMap<Resource, String>();\r
+                               result.put(r, problem);\r
+                       }\r
+               }\r
+               return result == null ? Collections.<Resource, String>emptyMap() : result;\r
+       }\r
+\r
+}
\ No newline at end of file