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