Last modified by msp on 2025/01/30 12:03

From version 12.1
edited by msp
on 2012/11/07 11:29
Change comment: There is no comment for this version
To version 14.1
edited by msp
on 2012/11/07 11:42
Change comment: Migrated to Confluence 5.3

Summary

Details

Page properties
Parent
... ... @@ -1,0 +1,1 @@
1 +Tutorials
Content
... ... @@ -391,4 +391,4 @@
391 391  1. Create a new class {{code language="none"}}StateUpdateFeature{{/code}} extending {{code language="none"}}AbstractUpdateFeature{{/code}} and register it by overriding {{code language="none"}}getUpdateFeature{{/code}} in the {{code language="none"}}TuringFeatureProvider{{/code}}. This new feature is responsible for updating the displayed text when the corresponding attribute in the domain model is changed outside the Graphiti editor. For example you could open the Turing Machine model with the //Sample Reflective Ecore Model Editor //in order to modify attributes. You can activate automatic updates of the diagram by extending {{code language="none"}}isAutoUpdateAtRuntime{{/code}} (resp. {{code language="none"}}Startup{{/code}} / {{code language="none"}}Reset{{/code}}) in the {{code language="none"}}TuringDiagramTypeProvider{{/code}} and returning {{code language="none"}}true{{/code}}. The update feature can be invoked explicitly in other features by calling the superclass method {{code language="none"}}updatePictogramElement{{/code}}.
392 392  1. Create a new class {{code language="none"}}StateLayoutFeature{{/code}} extending {{code language="none"}}AbstractLayoutFeature{{/code}} and register it by overriding {{code language="none"}}getLayoutFeature{{/code}} in the {{code language="none"}}TuringFeatureProvider{{/code}}. This new feature is responsible for updating the position and size of graphics algorithms of a state when the state is resized in the graphical editor or when the displayed text for the state name is updated. The layout feature can be invoked explicitly in other features by calling the superclass method {{code language="none"}}layoutPictogramElement{{/code}}.
393 393  
394 -
394 +Implement all created feature classes such that the editor behaves correctly when state names are modified or states are resized. You should aim for a good look-and-feel of your Turing Machine editor. If you like, you may also implement transition labels for displaying triggers and actions of transitions (not required for finishing the tutorial).
CreationWizardPage.java
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.XWikiGuest
Size
... ... @@ -1,0 +1,1 @@
1 +5.6 KB
Content
... ... @@ -1,0 +1,177 @@
1 +/*
2 + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
3 + *
4 + * http://www.informatik.uni-kiel.de/rtsys/kieler/
5 + *
6 + * Copyright 2010 by
7 + * + Christian-Albrechts-University of Kiel
8 + * + Department of Computer Science
9 + * + Real-Time and Embedded Systems Group
10 + *
11 + * This code is provided under the terms of the Eclipse Public License (EPL).
12 + * See the file epl-v10.html for the license text.
13 + */
14 +package de.cau.cs.rtprak.turing.graphiti;
15 +
16 +import org.eclipse.core.resources.IWorkspaceRoot;
17 +import org.eclipse.core.resources.ResourcesPlugin;
18 +import org.eclipse.core.runtime.IPath;
19 +import org.eclipse.core.runtime.Path;
20 +import org.eclipse.emf.common.util.URI;
21 +import org.eclipse.jface.viewers.IStructuredSelection;
22 +import org.eclipse.jface.wizard.IWizardPage;
23 +import org.eclipse.swt.widgets.Composite;
24 +import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
25 +
26 +/**
27 + * Wizard page to create diagram or model files.
28 + *
29 + * @author msp
30 + */
31 +public class CreationWizardPage extends WizardNewFileCreationPage {
32 +
33 + /** the file extension to use for this wizard page. */
34 + private String extension;
35 +
36 + /**
37 + * Creates a page with given settings.
38 + *
39 + * @param pageName the name of the page
40 + * @param selection the current resource selection
41 + * @param theextension the file extension
42 + */
43 + public CreationWizardPage(final String pageName, final IStructuredSelection selection,
44 + final String theextension) {
45 + super(pageName, selection);
46 + this.extension = theextension;
47 + }
48 +
49 + /**
50 + * {@inheritDoc}
51 + */
52 + @Override
53 + public void createControl(final Composite parent) {
54 + super.createControl(parent);
55 + setPageComplete(true);
56 + }
57 +
58 + /**
59 + * Creates a URI for the selected file path.
60 + *
61 + * @return a URI for the file
62 + */
63 + public URI getURI() {
64 + IPath path = getContainerFullPath();
65 + if (path == null) {
66 + path = new Path("");
67 + }
68 + String fileName = getFileName();
69 + if (fileName == null || fileName.length() == 0) {
70 + fileName = copyFileName();
71 + }
72 + path = path.append(getUniqueFileName(path, fileName, extension));
73 + return URI.createPlatformResourceURI(path.toString(), false);
74 + }
75 +
76 + /**
77 + * {@inheritDoc}
78 + */
79 + @Override
80 + public void setVisible(final boolean visible) {
81 + if (visible && (getFileName() == null || getFileName().length() == 0)) {
82 + setFileName(getUniqueFileName(getContainerFullPath(), copyFileName(), extension));
83 + }
84 + super.setVisible(visible);
85 + }
86 +
87 + private String copyFileName() {
88 + String fileName = null;
89 + IWizardPage previousPage = getPreviousPage();
90 + if (previousPage instanceof CreationWizardPage) {
91 + CreationWizardPage copyPage = (CreationWizardPage) previousPage;
92 + fileName = copyPage.getFileName();
93 + if (fileName.endsWith(copyPage.extension)) {
94 + fileName = fileName.substring(0, fileName.length()
95 + - (copyPage.extension.length() + 1));
96 + }
97 + }
98 + return fileName;
99 + }
100 +
101 + /**
102 + * Creates a unique file name.
103 + *
104 + * @param containerFullPath the container full path, or {@code null}
105 + * @param fileName the initial file name, or {@code null}
106 + * @param extension the required file extension
107 + * @return a unique file name
108 + */
109 + private static String getUniqueFileName(final IPath containerFullPath, final String fileName,
110 + final String extension) {
111 + IPath contPath = containerFullPath == null ? new Path("") : containerFullPath;
112 + String name = (fileName == null || fileName.trim().length() == 0) ? "default" : fileName;
113 + IPath filePath = contPath.append(name);
114 + if (extension.equals(filePath.getFileExtension())) {
115 + name = name.substring(0, name.length() - (extension.length() + 1));
116 + } else {
117 + filePath = filePath.addFileExtension(extension);
118 + }
119 + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
120 + if (workspaceRoot.exists(filePath)) {
121 + int x = getNumber(name);
122 + if (x >= 0) {
123 + name = name.substring(0, name.length() - digits(x));
124 + } else {
125 + x = 0;
126 + }
127 + do {
128 + x++;
129 + String newName = name + x + "." + extension;
130 + filePath = filePath.append(newName);
131 + } while (workspaceRoot.exists(filePath));
132 + }
133 + return filePath.lastSegment();
134 + }
135 +
136 + /**
137 + * Returns the greatest number that is a suffix of the given string.
138 + *
139 + * @param string a string
140 + * @return a suffix number, of -1 if the string has no such suffix
141 + */
142 + private static int getNumber(final String string) {
143 + int index = string.length();
144 + while (index > 0 && Character.isDigit(string.charAt(index - 1))) {
145 + index--;
146 + }
147 + if (index < string.length()) {
148 + try {
149 + return Integer.parseInt(string.substring(index));
150 + } catch (NumberFormatException exception) {
151 + // ignore exception and return 0
152 + }
153 + }
154 + return -1;
155 + }
156 +
157 + /** the base for integer numbers. */
158 + private static final int BASE = 10;
159 +
160 + /**
161 + * Returns the number of digits of a number.
162 + *
163 + * @param x an integer number
164 + * @return the number of digits of x
165 + */
166 + private static int digits(final int x) {
167 + int digits = 1;
168 + int a = x;
169 + while (a >= BASE) {
170 + a /= BASE;
171 + digits++;
172 + }
173 + return digits;
174 + }
175 +
176 +}
177 +
GraphitiNewWizard.java
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.XWikiGuest
Size
... ... @@ -1,0 +1,1 @@
1 +13.8 KB
Content
... ... @@ -1,0 +1,362 @@
1 +/*
2 + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
3 + *
4 + * http://www.informatik.uni-kiel.de/rtsys/kieler/
5 + *
6 + * Copyright 2010 by
7 + * + Christian-Albrechts-University of Kiel
8 + * + Department of Computer Science
9 + * + Real-Time and Embedded Systems Group
10 + *
11 + * This code is provided under the terms of the Eclipse Public License (EPL).
12 + * See the file epl-v10.html for the license text.
13 + */
14 +package de.cau.cs.rtprak.turing.graphiti;
15 +
16 +import java.io.IOException;
17 +import java.lang.reflect.InvocationTargetException;
18 +import java.util.HashMap;
19 +import java.util.Map;
20 +
21 +import org.eclipse.core.resources.IFile;
22 +import org.eclipse.core.resources.IResource;
23 +import org.eclipse.core.resources.ResourcesPlugin;
24 +import org.eclipse.core.runtime.CoreException;
25 +import org.eclipse.core.runtime.IProgressMonitor;
26 +import org.eclipse.core.runtime.IStatus;
27 +import org.eclipse.core.runtime.NullProgressMonitor;
28 +import org.eclipse.core.runtime.Path;
29 +import org.eclipse.core.runtime.Status;
30 +import org.eclipse.emf.common.command.CommandStack;
31 +import org.eclipse.emf.common.util.URI;
32 +import org.eclipse.emf.ecore.EObject;
33 +import org.eclipse.emf.ecore.resource.Resource;
34 +import org.eclipse.emf.ecore.resource.ResourceSet;
35 +import org.eclipse.emf.ecore.xmi.XMLResource;
36 +import org.eclipse.emf.transaction.RecordingCommand;
37 +import org.eclipse.emf.transaction.TransactionalEditingDomain;
38 +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
39 +import org.eclipse.graphiti.mm.pictograms.Diagram;
40 +import org.eclipse.graphiti.mm.pictograms.PictogramLink;
41 +import org.eclipse.graphiti.mm.pictograms.PictogramsFactory;
42 +import org.eclipse.graphiti.services.Graphiti;
43 +import org.eclipse.graphiti.ui.services.GraphitiUi;
44 +import org.eclipse.jface.operation.IRunnableWithProgress;
45 +import org.eclipse.jface.viewers.IStructuredSelection;
46 +import org.eclipse.jface.wizard.Wizard;
47 +import org.eclipse.ui.INewWizard;
48 +import org.eclipse.ui.IWorkbench;
49 +import org.eclipse.ui.IWorkbenchPage;
50 +import org.eclipse.ui.PartInitException;
51 +import org.eclipse.ui.actions.WorkspaceModifyOperation;
52 +import org.eclipse.ui.part.FileEditorInput;
53 +import org.eclipse.ui.statushandlers.StatusManager;
54 +
55 +/**
56 + * A generic wizard for creation of new Graphiti diagrams.
57 + *
58 + * @author msp
59 + */
60 +public abstract class GraphitiNewWizard extends Wizard implements INewWizard {
61 +
62 + /** the workbench. */
63 + private IWorkbench workbench;
64 + /** the current selection. */
65 + private IStructuredSelection selection;
66 + /** the diagram model wizard page. */
67 + private CreationWizardPage diagramModelFilePage;
68 + /** the domain model wizard page. */
69 + private CreationWizardPage domainModelFilePage;
70 + /** the name of the wizard. */
71 + private String wizardName;
72 + /** the diagram file extension. */
73 + private String diagramFileExtension;
74 + /** the domain model file extension. */
75 + private String domainFileExtension;
76 + /** the diagram type name of the graphiti diagram. */
77 + private String diagramTypeName;
78 + /** the identifier of the diagram editor. */
79 + private String editorId;
80 + /** the grid size (0 means no grid). */
81 + private int gridSize = 0;
82 + /** the setting for snapping to grid. */
83 + private boolean snapToGrid = false;
84 +
85 + /**
86 + * Creates a new-wizard for Graphiti, with no grid.
87 + *
88 + * @param name
89 + * the name of the wizard
90 + * @param diagExt
91 + * the diagram file extension
92 + * @param domainExt
93 + * the domain model file extension
94 + * @param thediagramTypeName
95 + * the diagram type name of the graphiti diagram
96 + */
97 + public GraphitiNewWizard(final String name, final String diagExt, final String domainExt,
98 + final String thediagramTypeName) {
99 + this.wizardName = name;
100 + this.diagramFileExtension = diagExt;
101 + this.domainFileExtension = domainExt;
102 + this.diagramTypeName = thediagramTypeName;
103 + }
104 +
105 + /**
106 + * Creates a new-wizard for Graphiti, with no grid.
107 + *
108 + * @param name
109 + * the name of the wizard
110 + * @param diagExt
111 + * the diagram file extension
112 + * @param domainExt
113 + * the domain model file extension
114 + * @param thediagramTypeName
115 + * the diagram type of the graphiti diagram
116 + * @param theeditorId
117 + * identifier of the diagram editor, or {@code null} if no editor shall be opened
118 + * after model creation
119 + */
120 + public GraphitiNewWizard(final String name, final String diagExt, final String domainExt,
121 + final String thediagramTypeName, final String theeditorId) {
122 + this(name, diagExt, domainExt, thediagramTypeName);
123 + this.editorId = theeditorId;
124 + }
125 +
126 + /**
127 + * Creates a new-wizard for Graphiti, with customizable grid.
128 + *
129 + * @param name
130 + * the name of the wizard
131 + * @param diagExt
132 + * the diagram file extension
133 + * @param domainExt
134 + * the domain model file extension
135 + * @param thediagramTypeName
136 + * the diagram type name of the graphiti diagram
137 + * @param theeditorId
138 + * identifier of the diagram editor, or {@code null} if no editor shall be opened
139 + * after model creation
140 + * @param thegridSize
141 + * the grid size (0 means no grid)
142 + * @param thesnapToGrid
143 + * the setting for snapping to grid
144 + */
145 + public GraphitiNewWizard(final String name, final String diagExt, final String domainExt,
146 + final String thediagramTypeName, final String theeditorId, final int thegridSize,
147 + final boolean thesnapToGrid) {
148 + this(name, diagExt, domainExt, thediagramTypeName, theeditorId);
149 + this.gridSize = thegridSize;
150 + this.snapToGrid = thesnapToGrid;
151 + }
152 +
153 + /**
154 + * {@inheritDoc}
155 + */
156 + public final void init(final IWorkbench theworkbench, final IStructuredSelection theselection) {
157 + this.workbench = theworkbench;
158 + this.selection = theselection;
159 + setWindowTitle("New " + wizardName + " Diagram");
160 + setNeedsProgressMonitor(true);
161 + }
162 +
163 + /**
164 + * {@inheritDoc}
165 + */
166 + @Override
167 + public final void addPages() {
168 + diagramModelFilePage = new CreationWizardPage("DiagramModelFile", selection,
169 + diagramFileExtension);
170 + diagramModelFilePage.setTitle("Create " + wizardName + " Diagram");
171 + diagramModelFilePage.setDescription("Select file that will contain diagram model.");
172 + addPage(diagramModelFilePage);
173 +
174 + domainModelFilePage = new CreationWizardPage("DomainModelFile", selection,
175 + domainFileExtension);
176 + domainModelFilePage.setTitle("Create " + wizardName + " Domain Model");
177 + domainModelFilePage.setDescription("Select file that will contain domain model.");
178 + addPage(domainModelFilePage);
179 + }
180 +
181 + /**
182 + * {@inheritDoc}
183 + */
184 + @Override
185 + public final boolean performFinish() {
186 + IRunnableWithProgress op = new WorkspaceModifyOperation(null) {
187 + @Override
188 + protected void execute(final IProgressMonitor monitor) throws CoreException,
189 + InterruptedException {
190 + Resource diagramResource = createDiagram(diagramModelFilePage.getURI(),
191 + domainModelFilePage.getURI(), monitor);
192 + if (diagramResource != null && editorId != null) {
193 + try {
194 + openDiagram(diagramResource);
195 + } catch (PartInitException exception) {
196 + throw new CoreException(new Status(IStatus.ERROR,
197 + "de.cau.cs.rtprak.turing.graphiti",
198 + "Error opening diagram", exception));
199 + }
200 + }
201 + }
202 + };
203 + try {
204 + getContainer().run(false, true, op);
205 + } catch (InterruptedException exception) {
206 + return false;
207 + } catch (InvocationTargetException exception) {
208 + if (exception.getTargetException() instanceof CoreException) {
209 + StatusManager.getManager().handle(((CoreException) exception.getTargetException()),
210 + "de.cau.cs.rtprak.turing.graphiti");
211 + } else {
212 + IStatus status = new Status(IStatus.ERROR, "de.cau.cs.rtprak.turing.graphiti",
213 + "Error creating diagram", exception.getTargetException());
214 + StatusManager.getManager().handle(status, StatusManager.LOG);
215 + }
216 + return false;
217 + }
218 + return true;
219 + }
220 +
221 + /**
222 + * Create a diagram with given URIs.
223 + *
224 + * @param diagramURI
225 + * URI for the diagram file
226 + * @param modelURI
227 + * URI for the model file
228 + * @param progressMonitor
229 + * progress monitor
230 + * @return a resource for the new diagram file
231 + */
232 + private Resource createDiagram(final URI diagramURI, final URI modelURI,
233 + final IProgressMonitor progressMonitor) {
234 + progressMonitor.beginTask("Creating diagram and model files", 2);
235 + // create a resource set and editing domain
236 + TransactionalEditingDomain editingDomain = GraphitiUi.getEmfService()
237 + .createResourceSetAndEditingDomain();
238 + ResourceSet resourceSet = editingDomain.getResourceSet();
239 + CommandStack commandStack = editingDomain.getCommandStack();
240 + // create resources for the diagram and domain model files
241 + final Resource diagramResource = resourceSet.createResource(diagramURI);
242 + final Resource modelResource = resourceSet.createResource(modelURI);
243 + if (diagramResource != null && modelResource != null) {
244 + commandStack.execute(new RecordingCommand(editingDomain) {
245 + @Override
246 + protected void doExecute() {
247 + createModel(diagramResource, diagramURI.lastSegment(), modelResource,
248 + modelURI.lastSegment());
249 + }
250 + });
251 + progressMonitor.worked(1);
252 +
253 + try {
254 + modelResource.save(createSaveOptions());
255 + diagramResource.save(createSaveOptions());
256 + } catch (IOException exception) {
257 + IStatus status = new Status(IStatus.ERROR, "de.cau.cs.rtprak.turing.graphiti",
258 + "Unable to store model and diagram resources", exception);
259 + StatusManager.getManager().handle(status);
260 + }
261 + setCharset(WorkspaceSynchronizer.getFile(modelResource));
262 + setCharset(WorkspaceSynchronizer.getFile(diagramResource));
263 + }
264 + progressMonitor.done();
265 + return diagramResource;
266 + }
267 +
268 + /**
269 + * Creates save options for the resources.
270 + *
271 + * @return new save options
272 + */
273 + public static Map<?, ?> createSaveOptions() {
274 + HashMap<String, Object> saveOptions = new HashMap<String, Object>();
275 + saveOptions.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
276 + saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED,
277 + Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER);
278 + return saveOptions;
279 + }
280 +
281 + /**
282 + * Set the character set for the given file to UTF-8.
283 + *
284 + * @param file
285 + * a file
286 + */
287 + public static void setCharset(final IFile file) {
288 + try {
289 + if (file != null) {
290 + file.setCharset("UTF-8", new NullProgressMonitor());
291 + }
292 + } catch (CoreException e) {
293 + StatusManager.getManager().handle(e, "de.cau.cs.rtprak.turing.graphiti");
294 + }
295 + }
296 +
297 + /**
298 + * Open the diagram from the given resource.
299 + *
300 + * @param diagramResource
301 + * a resource for a diagram file
302 + * @throws PartInitException
303 + * if the diagram could not be opened
304 + */
305 + private void openDiagram(final Resource diagramResource) throws PartInitException {
306 + String path = diagramResource.getURI().toPlatformString(true);
307 + IResource workspaceResource = ResourcesPlugin.getWorkspace().getRoot()
308 + .findMember(new Path(path));
309 + if (workspaceResource instanceof IFile) {
310 + IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
311 + page.openEditor(new FileEditorInput((IFile) workspaceResource), editorId);
312 + }
313 + }
314 +
315 + /**
316 + * Create a model in the given resources.
317 + *
318 + * @param diagramResource
319 + * resource for the diagram model
320 + * @param diagramName
321 + * name of the diagram model
322 + * @param modelResource
323 + * resource for the domain model
324 + * @param modelName
325 + * name of the domain model
326 + */
327 + private void createModel(final Resource diagramResource, final String diagramName,
328 + final Resource modelResource, final String modelName) {
329 + modelResource.setTrackingModification(true);
330 + EObject domainModel = createModel(modelName);
331 + modelResource.getContents().add(domainModel);
332 + diagramResource.setTrackingModification(true);
333 + Diagram diagram = Graphiti.getPeCreateService().createDiagram(diagramTypeName, diagramName,
334 + gridSize, snapToGrid);
335 + PictogramLink link = PictogramsFactory.eINSTANCE.createPictogramLink();
336 + link.setPictogramElement(diagram);
337 + link.getBusinessObjects().add(domainModel);
338 + configureDiagram(diagram);
339 + diagramResource.getContents().add(diagram);
340 + }
341 +
342 + /**
343 + * Configure the diagram. May be overridden by subclasses.
344 + *
345 + * @param diagram
346 + * the top-level element of the pictogram model
347 + */
348 + protected void configureDiagram(final Diagram diagram) {
349 + // the default implementation does nothing
350 + }
351 +
352 + /**
353 + * Create an instance of the top-level object for the domain model.
354 + *
355 + * @param name
356 + * name of the model
357 + * @return an instance of the domain model object
358 + */
359 + protected abstract EObject createModel(final String name);
360 +
361 +}
362 +
Confluence.Code.ConfluencePageClass[0]
Id
... ... @@ -1,1 +1,1 @@
1 -3604595
1 +3604565
URL
... ... @@ -1,1 +1,1 @@
1 -https://rtsys.informatik.uni-kiel.de/confluence//wiki/spaces/WS12EclPract/pages/3604595/Graphical Modeling with Graphiti
1 +https://rtsys.informatik.uni-kiel.de/confluence//wiki/spaces/WS12EclPract/pages/3604565/Graphical Modeling with Graphiti