1 package org.simantics.modeling.adapters;
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.set.hash.THashSet;
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;
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;
42 * @author Tuukka Lehtonen
44 public class ExistingInstancesRemover extends AbstractRemover {
46 protected String typeDescription;
48 public ExistingInstancesRemover(Resource resource, String removedTypeDescription) {
50 this.typeDescription = removedTypeDescription;
54 public void remove(WriteGraph graph) throws DatabaseException {
55 remove(graph, resource, resource, resource);
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.");
65 Resource root = graph.syncRequest(new PossibleIndexRoot(resource));
68 // Not part of an index root? Just remove everything because
69 // we can't find instances anyway.
73 Layer0 L0 = Layer0.getInstance(graph);
74 final String componentTypeName = graph.getPossibleRelatedValue(typeNameResource, L0.HasName, Bindings.STRING);
75 if (componentTypeName == null) {
80 Set<Resource> instances = discoverInstances(graph, typeResource);
81 if (!instances.isEmpty()) {
82 confirmRemoval(graph, instances, typeDescription, componentTypeName);
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();
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()) {
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)) {
110 Set<Resource> result = new THashSet<Resource>();
111 Instances search = graph.adapt(type, Instances.class);
112 discoverInstances(graph, type, indexRoot, search, result);
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);
120 // for (Resource r : result)
121 // System.out.println("found instance: " + NameUtils.getURIOrSafeNameInternal(graph, r));
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);
131 for (Resource linkee : graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse)) {
132 discoverInstances(graph, typeResource, linkee, instances, result);
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()];
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;
150 Arrays.sort(content, new Comparator<RemoveInstancesDialog.Content>() {
152 public int compare(Content o1, Content o2) {
153 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.label, o2.label);
157 if (!unremovable.isEmpty()) {
158 if (PlatformUI.isWorkbenchRunning()) {
159 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
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 "
168 + " instances cannot be removed.\n\nSelect instances marked with errors from the table below to see why they cannot be removed.",
170 new String[] { IDialogConstants.OK_LABEL },
180 final Session session = graph.getSession();
182 if (PlatformUI.isWorkbenchRunning()) {
183 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
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?",
191 int result = dialog.open();
192 boolean doIt = result == IDialogConstants.OK_ID;
195 session.asyncRequest(new WriteRequest() {
197 public void perform(WriteGraph graph) throws DatabaseException {
198 justRemoveWithInstances(graph, instances);
204 // Just do it without confirmation when no user agent is available.
205 justRemoveWithInstances(graph, instances);
209 protected void justRemoveWithInstances(WriteGraph graph, Collection<Resource> instances) throws DatabaseException {
210 for (Resource instance : instances)
211 RemoverUtil.remove(graph, instance);
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));
227 Resource rootParent = graph.getPossibleObject(root, L0.PartOf);
228 if (rootParent == null)
231 String rootUri = graph.getPossibleURI(rootParent);
232 if (rootUri != null) {
233 String instanceRelativeUri = instanceUri.substring(rootUri.length());
234 result.put(instance, URIStringUtils.unescape( instanceRelativeUri ));
239 result.put(instance, URIStringUtils.unescape( instanceUri ));
244 result.put(instance, NameUtils.getSafeName(graph, instance, true));
249 protected void justRemove(WriteGraph graph) throws DatabaseException {
250 graph.deny(resource, Layer0.getInstance(graph).PartOf);
251 EntityRemover.remove(graph, resource);
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);
262 String problem = remover.canRemove(graph, aux);
263 if (problem != null) {
265 result = new THashMap<Resource, String>();
266 result.put(r, problem);
269 return result == null ? Collections.<Resource, String>emptyMap() : result;