Support diagram profile activity store/restore in model export/import
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / profile / Profiles.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.profile;
13
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.simantics.databoard.Bindings;
21 import org.simantics.databoard.binding.mutable.Variant;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.RequestProcessor;
24 import org.simantics.db.Resource;
25 import org.simantics.db.VirtualGraph;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.WriteOnlyGraph;
28 import org.simantics.db.common.request.WriteRequest;
29 import org.simantics.db.common.utils.ListUtils;
30 import org.simantics.db.exception.DatabaseException;
31 import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler;
32 import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor;
33 import org.simantics.db.layer0.util.ClipboardUtils;
34 import org.simantics.db.layer0.util.SimanticsClipboard;
35 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
36 import org.simantics.db.layer0.util.SimanticsKeys;
37 import org.simantics.db.layer0.variable.Variable;
38 import org.simantics.db.service.VirtualGraphSupport;
39 import org.simantics.diagram.profile.ProfileActivityBean.Profile;
40 import org.simantics.diagram.stubs.DiagramResource;
41 import org.simantics.graph.db.TransferableGraphs;
42 import org.simantics.graph.representation.Root;
43 import org.simantics.graph.representation.TransferableGraph1;
44 import org.simantics.layer0.Layer0;
45 import org.simantics.modeling.ModelingResources;
46 import org.simantics.simulation.ontology.SimulationResource;
47 import org.simantics.utils.datastructures.Arrays;
48
49 /**
50  * @author Tuukka Lehtonen
51  */
52 public class Profiles {
53
54     public static Resource createProfile(WriteGraph graph, String profileName, Resource... entries)
55             throws DatabaseException {
56         Layer0 L0 = Layer0.getInstance(graph);
57         DiagramResource DIA = DiagramResource.getInstance(graph);
58
59         ArrayList<Resource> ee = new ArrayList<Resource>();
60         Arrays.addAll(ee, entries);
61         Resource list = ListUtils.create(graph, DIA.Profile, ee);
62
63         // TODO : DIA.Profile is a list, but why it is used in the container?
64         //Resource profile = graph.newResource();
65         //graph.claim(profile, L0.InstanceOf, null, DIA.Profile);
66         
67         Resource profile = ListUtils.create(graph, DIA.Profile);
68         
69         graph.claimLiteral(profile, L0.HasName, profileName);
70         graph.claim(profile, DIA.HasEntries, null, list);
71
72         return profile;
73     }
74
75     public static Resource createEntry(WriteGraph graph, String name, Resource style, Resource group)
76             throws DatabaseException {
77         Layer0 L0 = Layer0.getInstance(graph);
78         DiagramResource DIA = DiagramResource.getInstance(graph);
79
80         Resource entry = graph.newResource();
81         graph.claim(entry, L0.InstanceOf, null, DIA.GroupStyleProfileEntry);
82         graph.claimLiteral(entry, L0.HasName, name);
83         graph.claimLiteral(entry, L0.HasLabel, name);
84         graph.claim(entry, DIA.ProfileEntry_HasStyle, style);
85         graph.claim(entry, DIA.ProfileEntry_HasGroup, group);
86
87         return entry;
88     }
89
90     public static Resource createContainerProfile(WriteGraph graph, String name, Resource... children)
91             throws DatabaseException {
92         Layer0 L0 = Layer0.getInstance(graph);
93         DiagramResource DIA = DiagramResource.getInstance(graph);
94
95         Resource profile = graph.newResource();
96         graph.claim(profile, L0.InstanceOf, null, DIA.Profile);
97         graph.claim(profile, L0.Abstract, profile);
98         graph.claimLiteral(profile, L0.HasName, name);
99         graph.claimLiteral(profile, L0.HasLabel, name);
100         ArrayList<Resource> cd = new ArrayList<Resource>();
101         Arrays.addAll(cd, children);
102         graph.claim(profile, DIA.HasEntries, null, ListUtils.create(graph, DIA.Profile, cd));
103
104         return profile;
105     }
106     
107     public static Variable getMappedVariable(ReadGraph graph, Resource runtimeDiagram, Resource element) throws DatabaseException {
108         
109                 DiagramResource DIA = DiagramResource.getInstance(graph);
110                 ModelingResources MOD = ModelingResources.getInstance(graph);
111
112                 String variableURI = graph.getPossibleRelatedValue(runtimeDiagram, DIA.RuntimeDiagram_HasVariable, Bindings.STRING);
113                 Variable activeVariable = org.simantics.db.layer0.variable.Variables.getVariable(graph, variableURI);
114                 
115                 Resource module = graph.getPossibleObject(element, MOD.ElementToComponent);
116                 if (module == null)
117                         return null;
118
119                 return activeVariable.browse(graph, module);
120         
121     }
122     
123     public static Resource[] getProfileEntries(ReadGraph graph, Resource profile) throws DatabaseException {
124                 DiagramResource DIA = DiagramResource.getInstance(graph);
125
126                 Resource list = graph.getSingleObject(profile, DIA.HasEntries);
127                 List<Resource> entries = ListUtils.toList(graph, list);
128                 return entries.toArray(new Resource[entries.size()]);
129         }
130         
131         /**
132          * Copies profiles from an ontology definition to a model.
133          * 
134          * @param graph
135          * @param model
136          * @param sourceProfile
137          * @throws DatabaseException
138          */
139         public static void addProfiles(WriteGraph graph, Resource model, Resource sourceProfile) throws DatabaseException {
140                 Layer0 L0 = Layer0.getInstance(graph);
141                 DiagramResource DIA = DiagramResource.getInstance(graph);
142                 Resource profile = null;
143
144                 if (graph.isInstanceOf(sourceProfile, DIA.ConfigurableProfile))
145                         profile = copyProfiles(graph, model, sourceProfile);
146                 else
147                         profile = initProfiles(graph, model, sourceProfile);
148
149                 // connect profile to model
150                 graph.claim(model, DIA.HasProfile, profile);
151                 graph.claim(model, L0.ConsistsOf, profile);
152                 graph.claim(model, DIA.HasActiveProfile, profile);
153
154         }
155         
156         public static void addProfiles(WriteGraph graph, Resource model, String name, Resource... profileEntries) throws DatabaseException {
157                 Layer0 L0 = Layer0.getInstance(graph);
158                 DiagramResource DIA = DiagramResource.getInstance(graph);
159                 Resource profile = null;
160
161                 profile = initProfiles(graph, model, name, profileEntries);
162
163                 // connect profile to model
164                 graph.claim(model, DIA.HasProfile, profile);
165                 graph.claim(model, L0.ConsistsOf, profile);
166                 graph.claim(model, DIA.HasActiveProfile, profile);
167
168         }
169
170         private static Resource initProfiles(WriteGraph graph, Resource model, Resource profile) throws DatabaseException {
171                 Layer0 L0 = Layer0.getInstance(graph);
172
173                 Resource entries[] = getProfileEntries(graph, profile);
174
175                 String name = "Profile";
176                 String label = graph.getPossibleRelatedValue(profile, L0.HasLabel, Bindings.STRING);
177                 if (label != null && label.length() > 0)
178                         name = label;
179
180                 return initProfiles(graph, model, name, entries);
181         }
182
183         private static Resource initProfiles(WriteGraph graph, Resource model, String name, Resource entries[])
184                         throws DatabaseException {
185                 DiagramResource DIA = DiagramResource.getInstance(graph);
186                 for (int i = 0; i < entries.length; i++) {
187                         Resource entry = entries[i];
188                         if (graph.isInstanceOf(entry, DIA.ConfigurableProfile)) {
189                                 entries[i] = copyProfiles(graph, model, entry);
190                         }
191                 }
192
193                 return createProfile2(graph, name, entries);
194         }
195
196         private static Resource createProfile2(WriteGraph graph, String name, Resource[] entries) throws DatabaseException {
197                 DiagramResource DIA = DiagramResource.getInstance(graph);
198
199                 Resource profile = Profiles.createProfile(graph, name, entries);
200
201                 final List<Resource> enabled = new ArrayList<Resource>();
202                 for (Resource r : entries) {
203                         if (graph.hasStatement(r, DIA.Profile_defaultEnabled)) {
204                                 enabled.add(r);
205                         }
206                 }
207
208                 if (enabled.size() > 0) {
209                         final Resource p = profile;
210                         VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class);
211                         graph.syncRequest(new WriteRequest(support.getWorkspacePersistent("profiles")) {
212
213                                 @Override
214                                 public void perform(WriteGraph graph) throws DatabaseException {
215                                         SimulationResource SIM = SimulationResource.getInstance(graph);
216                                         for (Resource r : enabled) {
217                                                 graph.claim(p, SIM.IsActive, r);
218                                         }
219                                 }
220                         });
221                 }
222
223                 return profile;
224         }
225
226         private static Resource copyProfiles(WriteGraph graph, Resource model, Resource profile) throws DatabaseException {
227                 Layer0 L0 = Layer0.getInstance(graph);
228                 DiagramResource DIA = DiagramResource.getInstance(graph);
229
230                 Resource entries[] = getProfileEntries(graph, profile);
231
232                 Map<Resource, Resource> groupMap = new HashMap<Resource, Resource>();
233                 for (int i = 0; i < entries.length; i++) {
234                         Resource entry = entries[i];
235                         if (graph.isInstanceOf(entry, DIA.Profile)) {
236                                 entries[i] = initProfiles(graph, model, entry);
237                         } else if (graph.isInstanceOf(entry, DIA.ConfigurableProfile)) {
238                                 entries[i] = copyProfiles(graph, model, entry);
239                         } else if (graph.isInstanceOf(entry, DIA.ProfileEntry)) {
240                                 entries[i] = copyProfileEntry(graph, entry, groupMap);
241                         }
242                 }
243                 String name = "Profile";
244                 String label = graph.getPossibleRelatedValue(profile, L0.HasLabel, Bindings.STRING);
245                 if (label != null && label.length() > 0)
246                         name = label;
247
248                 return createProfile2(graph, name, entries);
249         }
250
251         private static Resource copyProfileEntry(WriteGraph graph, Resource entry, Map<Resource, Resource> groupMap)
252                         throws DatabaseException {
253                 Layer0 L0 = Layer0.getInstance(graph);
254                 DiagramResource DIA = DiagramResource.getInstance(graph);
255
256                 String name = graph.getPossibleRelatedValue(entry, L0.HasLabel, Bindings.STRING);
257                 Resource group = graph.getSingleObject(entry, DIA.ProfileEntry_HasGroup);
258                 Resource copyGroup = groupMap.get(group);
259                 if (copyGroup == null) {
260                         copyGroup = copyProfileGroup(graph, group);
261                         groupMap.put(group, copyGroup);
262                 }
263                 Resource style = graph.getSingleObject(entry, DIA.ProfileEntry_HasStyle);
264                 if (!graph.isInstanceOf(style, DIA.Style)) {
265                         style = createProfileStyle(graph, style);
266                 }
267                 Resource instance = Profiles.createEntry(graph, name, style, copyGroup);
268                 graph.claim(instance, L0.InstanceOf, entry);
269                 Double priority = graph.getPossibleRelatedValue(entry, DIA.ProfileEntry_HasPriority, Bindings.DOUBLE);
270                 if (priority != null) {
271                         graph.claimLiteral(instance, DIA.ProfileEntry_HasPriority, priority, Bindings.DOUBLE);
272                 }
273                 for (Resource template : graph.getObjects(entry, DIA.HasTemplate)) {
274                         SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
275                         DefaultCopyHandler handler = new DefaultCopyHandler(template);
276                         DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(instance) {
277                                 @Override
278                                 public Resource createRoot(WriteOnlyGraph graph, Root root, Resource resource)
279                                                 throws DatabaseException {
280                                         Layer0 l0 = graph.getService(Layer0.class);
281                                         DiagramResource DIA = graph.getService(DiagramResource.class);  
282                                         
283                                         if(resource == null) resource = graph.newResource();
284                                         
285                                         graph.claim(library, DIA.HasTemplate, DIA.HasTemplate_Inverse, resource);
286                                         
287                                         String newName = getName(root);
288                                         graph.addLiteral(resource, l0.HasName, l0.NameOf, l0.String, newName, Bindings.STRING);
289                                         
290                                         addRootInfo(root, newName, resource);
291                                         
292                                         return resource;
293                                 }
294                         };
295                         handler.copyToClipboard(graph, builder);
296                         for(Set<SimanticsClipboard.Representation> object : builder.getContents()) {
297                     TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
298                     TransferableGraphs.importGraph1(graph, tg, advisor);
299                 }
300                          
301                 }
302                 return instance;
303         }
304
305         private static Resource copyProfileGroup(WriteGraph graph, Resource group) throws DatabaseException {
306                 Layer0 L0 = Layer0.getInstance(graph);
307                 DiagramResource DIA = DiagramResource.getInstance(graph);
308
309                 Resource instance = graph.newResource();
310                 for (Resource type : graph.getObjects(group, L0.InstanceOf)) {
311                         graph.claim(instance, L0.InstanceOf, type);
312                 }
313                 Resource referredType = graph.getPossibleObject(group, DIA.TypeGroup_HasType);
314                 if (referredType != null)
315                         graph.claim(instance, DIA.TypeGroup_HasType, referredType);
316
317                 return instance;
318         }
319
320         private static Resource createProfileStyle(WriteGraph graph, Resource style) throws DatabaseException {
321                 Layer0 L0 = Layer0.getInstance(graph);
322
323                 Resource instance = graph.newResource();
324                 graph.claim(instance, L0.InstanceOf, style);
325                 return instance;
326         }
327
328         public static ProfileActivityBean readProfileActivity(
329                         RequestProcessor processor,
330                         Resource root)
331                                         throws DatabaseException
332         {
333                 return processor.syncRequest(new ProfileActivityBeanRequest(root));
334         }
335
336         public static ProfileActivityBean readProfileActivity(
337                         RequestProcessor processor,
338                         Resource root,
339                         Map<String, Variant> writeToMap)
340                                         throws DatabaseException
341         {
342                 ProfileActivityBean pab = readProfileActivity(processor, root);
343                 if (pab != null && writeToMap != null)
344                         writeToMap.put(ProfileActivityBean.EXTENSION_KEY, new Variant(ProfileActivityBean.BINDING, pab));
345                 return pab;
346         }
347
348         public static void writeProfileActivity(
349                         RequestProcessor processor,
350                         Resource root,
351                         ProfileActivityBean bean)
352                                         throws DatabaseException
353         {
354                 VirtualGraph vg = processor.getService(VirtualGraphSupport.class).getWorkspacePersistent("profiles");
355                 processor.syncRequest(new WriteRequest(vg) {
356                         @Override
357                         public void perform(WriteGraph graph) throws DatabaseException {
358                                 writeProfileActivity(graph, root, bean);
359                         }
360                 });
361         }
362
363         private static void writeProfileActivity(
364                         WriteGraph graph,
365                         Resource root,
366                         ProfileActivityBean bean)
367                                         throws DatabaseException
368         {
369                 String rootUri = graph.getPossibleURI(root);
370                 if (rootUri == null)
371                         return;
372
373                 SimulationResource SIMU = SimulationResource.getInstance(graph);
374                 for (Profile p : bean.topLevelProfiles.values()) {
375                         Resource pr = resolveRelativeUri(graph, rootUri, p.relativeUri);
376                         if (pr == null)
377                                 continue;
378                         for (String active : p.activeEntries) {
379                                 Resource ar = resolveRelativeUri(graph, rootUri, active);
380                                 if (ar != null)
381                                         graph.claim(pr, SIMU.IsActive, ar);
382                         }
383                 }
384
385                 Resource activeProfile = resolveRelativeUri(graph, rootUri, bean.activeProfile);
386                 if (activeProfile != null) {
387                         DiagramResource DIA = DiagramResource.getInstance(graph);
388                         graph.claim(root, DIA.HasActiveProfile, DIA.HasActiveProfile_Inverse, activeProfile);
389                 }
390         }
391
392         static String possiblyRelativeUri(ReadGraph graph, String rootUri, Resource r) throws DatabaseException {
393                 if (r == null)
394                         return null;
395                 String uri = graph.getPossibleURI(r);
396                 if (rootUri != null && uri != null && uri.startsWith(rootUri))
397                         return uri.substring(rootUri.length());
398                 return uri;
399         }
400
401         static Resource resolveRelativeUri(ReadGraph graph, String rootUri, String possiblyRelativeUri) throws DatabaseException {
402                 return possiblyRelativeUri != null
403                                 ? graph.getPossibleResource( resolveRelativeUri(rootUri, possiblyRelativeUri) )
404                                 : null;
405         }
406
407         private static String resolveRelativeUri(String rootUri, String possiblyRelativeUri) {
408                 return possiblyRelativeUri.startsWith("http:/")
409                                 ? possiblyRelativeUri
410                                 : rootUri + possiblyRelativeUri;
411         }
412
413 }