]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 package org.simantics.modeling.adapters;\r
2 \r
3 import gnu.trove.map.hash.THashMap;\r
4 import gnu.trove.set.hash.THashSet;\r
5 \r
6 import java.util.Arrays;\r
7 import java.util.Collection;\r
8 import java.util.Collections;\r
9 import java.util.Comparator;\r
10 import java.util.HashMap;\r
11 import java.util.Map;\r
12 import java.util.Set;\r
13 \r
14 import org.eclipse.jface.dialogs.IDialogConstants;\r
15 import org.eclipse.jface.dialogs.MessageDialog;\r
16 import org.eclipse.jface.resource.ImageDescriptor;\r
17 import org.eclipse.ui.PlatformUI;\r
18 import org.simantics.databoard.Bindings;\r
19 import org.simantics.databoard.util.URIStringUtils;\r
20 import org.simantics.db.ReadGraph;\r
21 import org.simantics.db.Resource;\r
22 import org.simantics.db.Session;\r
23 import org.simantics.db.WriteGraph;\r
24 import org.simantics.db.common.request.PossibleIndexRoot;\r
25 import org.simantics.db.common.request.WriteRequest;\r
26 import org.simantics.db.common.utils.NameUtils;\r
27 import org.simantics.db.exception.DatabaseException;\r
28 import org.simantics.db.layer0.adapter.Instances;\r
29 import org.simantics.db.layer0.adapter.Remover;\r
30 import org.simantics.db.layer0.adapter.impl.AbstractRemover;\r
31 import org.simantics.db.layer0.adapter.impl.EntityRemover;\r
32 import org.simantics.db.layer0.exception.CannotRemoveException;\r
33 import org.simantics.db.layer0.util.Layer0Utils;\r
34 import org.simantics.db.layer0.util.RemoverUtil;\r
35 import org.simantics.layer0.Layer0;\r
36 import org.simantics.modeling.ModelingResources;\r
37 import org.simantics.modeling.adapters.RemoveInstancesDialog.Content;\r
38 import org.simantics.utils.strings.AlphanumComparator;\r
39 import org.simantics.utils.ui.BundleUtils;\r
40 \r
41 /**\r
42  * @author Tuukka Lehtonen\r
43  */\r
44 public class ExistingInstancesRemover extends AbstractRemover {\r
45 \r
46         protected String typeDescription;\r
47 \r
48         public ExistingInstancesRemover(Resource resource, String removedTypeDescription) {\r
49                 super(resource);\r
50                 this.typeDescription = removedTypeDescription;\r
51         }\r
52 \r
53         @Override\r
54         public void remove(WriteGraph graph) throws DatabaseException {\r
55                 remove(graph, resource, resource, resource);\r
56         }\r
57 \r
58         protected void remove(WriteGraph graph, Resource resource, Resource typeResource, Resource typeNameResource) throws DatabaseException {\r
59 //              System.out.println("resource: " + NameUtils.getURIOrSafeNameInternal(graph, resource));\r
60 //              System.out.println("type resource: " + NameUtils.getURIOrSafeNameInternal(graph, typeResource));\r
61 //              System.out.println("type name resource: " + NameUtils.getURIOrSafeNameInternal(graph, typeNameResource));\r
62                 if (Layer0Utils.isContainerPublished(graph, resource))\r
63                         throw new CannotRemoveException("Items in published libraries cannot be removed. Please create a new version to perform modifications.");\r
64 \r
65                 Resource root = graph.syncRequest(new PossibleIndexRoot(resource));\r
66                 if (root == null) {\r
67                         justRemove(graph);\r
68                         // Not part of an index root? Just remove everything because\r
69                         // we can't find instances anyway.\r
70                         return;\r
71                 }\r
72 \r
73                 Layer0 L0 = Layer0.getInstance(graph);\r
74                 final String componentTypeName = graph.getPossibleRelatedValue(typeNameResource, L0.HasName, Bindings.STRING);\r
75                 if (componentTypeName == null) {\r
76                         justRemove(graph);\r
77                         return;\r
78                 }\r
79 \r
80                 Set<Resource> instances = discoverInstances(graph, typeResource);\r
81                 if (!instances.isEmpty()) {\r
82                         confirmRemoval(graph, instances, typeDescription, componentTypeName);\r
83                 } else {\r
84                         justRemove(graph);\r
85                 }\r
86         }\r
87 \r
88         protected Set<Resource> discoverInstances(WriteGraph graph, Resource type) throws DatabaseException {\r
89                 Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(type));\r
90                 if (indexRoot == null)\r
91                         return Collections.emptySet();\r
92 \r
93 //              @SuppressWarnings("rawtypes")\r
94 //              Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);\r
95 //              @SuppressWarnings("unchecked")\r
96 //              List<Map<String, Object>> result = (List<Map<String, Object>>) modules.apply(graph, root, "Types:\"" + IndexQueries.escape(componentTypeName) + "\"");\r
97 //              if (result.isEmpty()) {\r
98 //                      justRemove(graph);\r
99 //                      return;\r
100 //              }\r
101 //\r
102 //              final Set<Resource> instances = new HashSet<Resource>();\r
103 //              for (Map<String, Object> entry : result) {\r
104 //                      Resource c = (Resource) entry.get(Dependencies.FIELD_RESOURCE);\r
105 //                      if (c != null && graph.hasStatement(c, L0.InstanceOf, resource)) {\r
106 //                              instances.add(c);\r
107 //                      }\r
108 //              }\r
109 \r
110                 Set<Resource> result = new THashSet<Resource>();\r
111                 Instances search = graph.adapt(type, Instances.class);\r
112                 discoverInstances(graph, type, indexRoot, search, result);\r
113 \r
114                 // It is possible that resource is an instance of the specified type\r
115                 // also. However we assume that the specified resource is removed last\r
116                 // only after all the instances have been removed. That's why we remove\r
117                 // resource from the calculated set of instances at this point.\r
118                 result.remove(resource);\r
119 \r
120 //              for (Resource r : result)\r
121 //                      System.out.println("found instance: " + NameUtils.getURIOrSafeNameInternal(graph, r));\r
122 \r
123                 return result;\r
124         }\r
125 \r
126         private void discoverInstances(WriteGraph graph, Resource typeResource, Resource indexRoot, Instances instances, Set<Resource> result) throws DatabaseException {\r
127                 Layer0 L0 = Layer0.getInstance(graph);\r
128                 Collection<Resource> rs = instances.find(graph, indexRoot);\r
129                 result.addAll(rs);\r
130 \r
131                 for (Resource linkee : graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse)) {\r
132                         discoverInstances(graph, typeResource, linkee, instances, result);\r
133                 }\r
134         }\r
135 \r
136         protected void confirmRemoval(WriteGraph graph, final Set<Resource> instances, final String typeDescription, final String typeName) throws DatabaseException {\r
137                 Map<Resource, String> instanceAddresses = resolveInstanceAddresses(graph, instances);\r
138                 Map<Resource, String> unremovable = findUnremovable(graph, instances);\r
139                 final RemoveInstancesDialog.Content[] content = new RemoveInstancesDialog.Content[instanceAddresses.size()];\r
140                 int i = 0;\r
141                 ImageDescriptor problemImage = BundleUtils.getImageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png");\r
142                 for (Map.Entry<Resource, String> entry : instanceAddresses.entrySet()) {\r
143                         content[i] = new RemoveInstancesDialog.Content(entry.getValue());\r
144                         content[i].details = unremovable.get(entry.getKey());\r
145                         if (content[i].details != null) {\r
146                                 content[i].image = problemImage;\r
147                         }\r
148                         ++i;\r
149                 }\r
150                 Arrays.sort(content, new Comparator<RemoveInstancesDialog.Content>() {\r
151                         @Override\r
152                         public int compare(Content o1, Content o2) {\r
153                                 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.label, o2.label);\r
154                         }\r
155                 });\r
156 \r
157                 if (!unremovable.isEmpty()) {\r
158                         if (PlatformUI.isWorkbenchRunning()) {\r
159                                 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
160                                         @Override\r
161                                         public void run() {\r
162                                                 RemoveInstancesDialog dialog = new RemoveInstancesDialog(\r
163                                                                 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
164                                                                 "Cannot Remove  " + typeDescription,\r
165                                                                 typeDescription + " '" + typeName\r
166                                                                 + "' is still in use and all of its "\r
167                                                                 + instances.size()\r
168                                                                 + " instances cannot be removed.\n\nSelect instances marked with errors from the table below to see why they cannot be removed.",\r
169                                                                 MessageDialog.ERROR,\r
170                                                                 new String[] { IDialogConstants.OK_LABEL },\r
171                                                                 0,\r
172                                                                 content);\r
173                                                 dialog.open();\r
174                                         }\r
175                                 });\r
176                         }\r
177                         return;\r
178                 }\r
179 \r
180                 final Session session = graph.getSession();\r
181 \r
182                 if (PlatformUI.isWorkbenchRunning()) {\r
183                         PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
184                                 @Override\r
185                                 public void run() {\r
186                                         RemoveInstancesDialog dialog = new RemoveInstancesDialog(\r
187                                                         PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
188                                                         "Remove " + typeDescription + "?",\r
189                                                         typeDescription + " '" + typeName + "' is still in use. Are you sure you want to remove it and all its " + instances.size() + " instances?",\r
190                                                         content);\r
191                                         int result = dialog.open();\r
192                                         boolean doIt = result == IDialogConstants.OK_ID;\r
193                                         if (!doIt)\r
194                                                 return;\r
195                                         session.asyncRequest(new WriteRequest() {\r
196                                                 @Override\r
197                                                 public void perform(WriteGraph graph) throws DatabaseException {\r
198                                                         justRemoveWithInstances(graph, instances);\r
199                                                 }\r
200                                         });\r
201                                 }\r
202                         });\r
203                 } else {\r
204                         // Just do it without confirmation when no user agent is available.\r
205                         justRemoveWithInstances(graph, instances);\r
206                 }\r
207         }\r
208 \r
209         protected void justRemoveWithInstances(WriteGraph graph, Collection<Resource> instances) throws DatabaseException {\r
210                 for (Resource instance : instances)\r
211                         RemoverUtil.remove(graph, instance);\r
212                 justRemove(graph);\r
213         }\r
214 \r
215         protected Map<Resource, String> resolveInstanceAddresses(ReadGraph graph, Set<Resource> instances) throws DatabaseException {\r
216                 Layer0 L0 = Layer0.getInstance(graph);\r
217                 ModelingResources MOD = ModelingResources.getInstance(graph);\r
218                 Map<Resource, String> result = new THashMap<Resource, String>();\r
219                 for (Resource instance : instances) {\r
220                         Resource component = graph.getPossibleObject(instance, MOD.ElementToComponent);\r
221                         if (component != null)\r
222                                 instance = component;\r
223                         String instanceUri = graph.getPossibleURI(instance);\r
224                         if (instanceUri != null) {\r
225                                 Resource root = graph.syncRequest(new PossibleIndexRoot(instance));\r
226                                 if (root != null) {\r
227                                         Resource rootParent = graph.getPossibleObject(root, L0.PartOf);\r
228                                         if (rootParent == null)\r
229                                                 rootParent = root;\r
230 \r
231                                         String rootUri = graph.getPossibleURI(rootParent);\r
232                                         if (rootUri != null) {\r
233                                                 String instanceRelativeUri = instanceUri.substring(rootUri.length());\r
234                                                 result.put(instance, URIStringUtils.unescape( instanceRelativeUri ));\r
235                                                 continue;\r
236                                         }\r
237                                 }\r
238 \r
239                                 result.put(instance, URIStringUtils.unescape( instanceUri ));\r
240                                 continue;\r
241                         }\r
242 \r
243                         // Fallback logic\r
244                         result.put(instance, NameUtils.getSafeName(graph, instance, true));\r
245                 }\r
246                 return result;\r
247         }\r
248 \r
249         protected void justRemove(WriteGraph graph) throws DatabaseException {\r
250                 graph.deny(resource, Layer0.getInstance(graph).PartOf);\r
251                 EntityRemover.remove(graph, resource);\r
252         }\r
253 \r
254         private Map<Resource, String> findUnremovable(ReadGraph graph, Collection<Resource> instances) throws DatabaseException {\r
255                 Map<Resource, String> result = null;\r
256                 Map<Object, Object> aux = new HashMap<Object, Object>();\r
257                 for (Resource r : instances) {\r
258                         Remover remover = graph.getPossibleAdapter(r, Remover.class);\r
259                         if (remover == null)\r
260                                 continue;\r
261                         aux.clear();\r
262                         String problem = remover.canRemove(graph, aux);\r
263                         if (problem != null) {\r
264                                 if (result == null)\r
265                                         result = new THashMap<Resource, String>();\r
266                                 result.put(r, problem);\r
267                         }\r
268                 }\r
269                 return result == null ? Collections.<Resource, String>emptyMap() : result;\r
270         }\r
271 \r
272 }