1 package org.simantics.modeling.adapters;
\r
3 import gnu.trove.map.hash.THashMap;
\r
4 import gnu.trove.set.hash.THashSet;
\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
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
42 * @author Tuukka Lehtonen
\r
44 public class ExistingInstancesRemover extends AbstractRemover {
\r
46 protected String typeDescription;
\r
48 public ExistingInstancesRemover(Resource resource, String removedTypeDescription) {
\r
50 this.typeDescription = removedTypeDescription;
\r
54 public void remove(WriteGraph graph) throws DatabaseException {
\r
55 remove(graph, resource, resource, resource);
\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
65 Resource root = graph.syncRequest(new PossibleIndexRoot(resource));
\r
68 // Not part of an index root? Just remove everything because
\r
69 // we can't find instances anyway.
\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
80 Set<Resource> instances = discoverInstances(graph, typeResource);
\r
81 if (!instances.isEmpty()) {
\r
82 confirmRemoval(graph, instances, typeDescription, componentTypeName);
\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
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
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
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
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
120 // for (Resource r : result)
\r
121 // System.out.println("found instance: " + NameUtils.getURIOrSafeNameInternal(graph, r));
\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
131 for (Resource linkee : graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse)) {
\r
132 discoverInstances(graph, typeResource, linkee, instances, result);
\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
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
150 Arrays.sort(content, new Comparator<RemoveInstancesDialog.Content>() {
\r
152 public int compare(Content o1, Content o2) {
\r
153 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.label, o2.label);
\r
157 if (!unremovable.isEmpty()) {
\r
158 if (PlatformUI.isWorkbenchRunning()) {
\r
159 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
\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
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
180 final Session session = graph.getSession();
\r
182 if (PlatformUI.isWorkbenchRunning()) {
\r
183 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
\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
191 int result = dialog.open();
\r
192 boolean doIt = result == IDialogConstants.OK_ID;
\r
195 session.asyncRequest(new WriteRequest() {
\r
197 public void perform(WriteGraph graph) throws DatabaseException {
\r
198 justRemoveWithInstances(graph, instances);
\r
204 // Just do it without confirmation when no user agent is available.
\r
205 justRemoveWithInstances(graph, instances);
\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
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
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
239 result.put(instance, URIStringUtils.unescape( instanceUri ));
\r
244 result.put(instance, NameUtils.getSafeName(graph, instance, true));
\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
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
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
269 return result == null ? Collections.<Resource, String>emptyMap() : result;
\r