]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/ExistingInstancesRemover.java
Added new field TypeId to dependency index for exact type searching
[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                 Set<Resource> result = new THashSet<Resource>();
94                 Instances search = graph.adapt(type, Instances.class);
95                 discoverInstances(graph, type, indexRoot, search, result);
96
97                 // It is possible that resource is an instance of the specified type
98                 // also. However we assume that the specified resource is removed last
99                 // only after all the instances have been removed. That's why we remove
100                 // resource from the calculated set of instances at this point.
101                 result.remove(resource);
102
103 //              for (Resource r : result)
104 //                      System.out.println("found instance: " + NameUtils.getURIOrSafeNameInternal(graph, r));
105
106                 return result;
107         }
108
109         private void discoverInstances(WriteGraph graph, Resource typeResource, Resource indexRoot, Instances instances, Set<Resource> result) throws DatabaseException {
110                 Layer0 L0 = Layer0.getInstance(graph);
111                 Collection<Resource> rs = instances.find(graph, indexRoot);
112                 result.addAll(rs);
113
114                 for (Resource linkee : graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse)) {
115                         discoverInstances(graph, typeResource, linkee, instances, result);
116                 }
117         }
118
119         protected void confirmRemoval(WriteGraph graph, final Set<Resource> instances, final String typeDescription, final String typeName) throws DatabaseException {
120                 Map<Resource, String> instanceAddresses = resolveInstanceAddresses(graph, instances);
121                 Map<Resource, String> unremovable = findUnremovable(graph, instances);
122                 final RemoveInstancesDialog.Content[] content = new RemoveInstancesDialog.Content[instanceAddresses.size()];
123                 int i = 0;
124                 ImageDescriptor problemImage = BundleUtils.getImageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png");
125                 for (Map.Entry<Resource, String> entry : instanceAddresses.entrySet()) {
126                         content[i] = new RemoveInstancesDialog.Content(entry.getValue());
127                         content[i].details = unremovable.get(entry.getKey());
128                         if (content[i].details != null) {
129                                 content[i].image = problemImage;
130                         }
131                         ++i;
132                 }
133                 Arrays.sort(content, new Comparator<RemoveInstancesDialog.Content>() {
134                         @Override
135                         public int compare(Content o1, Content o2) {
136                                 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.label, o2.label);
137                         }
138                 });
139
140                 if (!unremovable.isEmpty()) {
141                         if (PlatformUI.isWorkbenchRunning()) {
142                                 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
143                                         @Override
144                                         public void run() {
145                                                 RemoveInstancesDialog dialog = new RemoveInstancesDialog(
146                                                                 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
147                                                                 "Cannot Remove  " + typeDescription,
148                                                                 typeDescription + " '" + typeName
149                                                                 + "' is still in use and all of its "
150                                                                 + instances.size()
151                                                                 + " instances cannot be removed.\n\nSelect instances marked with errors from the table below to see why they cannot be removed.",
152                                                                 MessageDialog.ERROR,
153                                                                 new String[] { IDialogConstants.OK_LABEL },
154                                                                 0,
155                                                                 content);
156                                                 dialog.open();
157                                         }
158                                 });
159                         }
160                         return;
161                 }
162
163                 final Session session = graph.getSession();
164
165                 if (PlatformUI.isWorkbenchRunning()) {
166                         PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
167                                 @Override
168                                 public void run() {
169                                         RemoveInstancesDialog dialog = new RemoveInstancesDialog(
170                                                         PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
171                                                         "Remove " + typeDescription + "?",
172                                                         typeDescription + " '" + typeName + "' is still in use. Are you sure you want to remove it and all its " + instances.size() + " instances?",
173                                                         content);
174                                         int result = dialog.open();
175                                         boolean doIt = result == IDialogConstants.OK_ID;
176                                         if (!doIt)
177                                                 return;
178                                         session.asyncRequest(new WriteRequest() {
179                                                 @Override
180                                                 public void perform(WriteGraph graph) throws DatabaseException {
181                                                         justRemoveWithInstances(graph, instances);
182                                                 }
183                                         });
184                                 }
185                         });
186                 } else {
187                         // Just do it without confirmation when no user agent is available.
188                         justRemoveWithInstances(graph, instances);
189                 }
190         }
191
192         protected void justRemoveWithInstances(WriteGraph graph, Collection<Resource> instances) throws DatabaseException {
193                 for (Resource instance : instances)
194                         RemoverUtil.remove(graph, instance);
195                 justRemove(graph);
196         }
197
198         protected Map<Resource, String> resolveInstanceAddresses(ReadGraph graph, Set<Resource> instances) throws DatabaseException {
199                 Layer0 L0 = Layer0.getInstance(graph);
200                 ModelingResources MOD = ModelingResources.getInstance(graph);
201                 Map<Resource, String> result = new THashMap<Resource, String>();
202                 for (Resource instance : instances) {
203                         Resource component = graph.getPossibleObject(instance, MOD.ElementToComponent);
204                         if (component != null)
205                                 instance = component;
206                         String instanceUri = graph.getPossibleURI(instance);
207                         if (instanceUri != null) {
208                                 Resource root = graph.syncRequest(new PossibleIndexRoot(instance));
209                                 if (root != null) {
210                                         Resource rootParent = graph.getPossibleObject(root, L0.PartOf);
211                                         if (rootParent == null)
212                                                 rootParent = root;
213
214                                         String rootUri = graph.getPossibleURI(rootParent);
215                                         if (rootUri != null) {
216                                                 String instanceRelativeUri = instanceUri.substring(rootUri.length());
217                                                 result.put(instance, URIStringUtils.unescape( instanceRelativeUri ));
218                                                 continue;
219                                         }
220                                 }
221
222                                 result.put(instance, URIStringUtils.unescape( instanceUri ));
223                                 continue;
224                         }
225
226                         // Fallback logic
227                         result.put(instance, NameUtils.getSafeName(graph, instance, true));
228                 }
229                 return result;
230         }
231
232         protected void justRemove(WriteGraph graph) throws DatabaseException {
233                 graph.deny(resource, Layer0.getInstance(graph).PartOf);
234                 EntityRemover.remove(graph, resource);
235         }
236
237         private Map<Resource, String> findUnremovable(ReadGraph graph, Collection<Resource> instances) throws DatabaseException {
238                 Map<Resource, String> result = null;
239                 Map<Object, Object> aux = new HashMap<Object, Object>();
240                 for (Resource r : instances) {
241                         Remover remover = graph.getPossibleAdapter(r, Remover.class);
242                         if (remover == null)
243                                 continue;
244                         aux.clear();
245                         String problem = remover.canRemove(graph, aux);
246                         if (problem != null) {
247                                 if (result == null)
248                                         result = new THashMap<Resource, String>();
249                                 result.put(r, problem);
250                         }
251                 }
252                 return result == null ? Collections.<Resource, String>emptyMap() : result;
253         }
254
255 }