1 | /* |
2 | * Copyright 2007, SDQ, IPD, Uni Karlsruhe (TH) |
3 | */ |
4 | package de.uka.ipd.sdq.pcm.gmf.composite.part; |
5 | |
6 | import java.io.IOException; |
7 | import java.util.ArrayList; |
8 | import java.util.Collection; |
9 | import java.util.Collections; |
10 | import java.util.HashMap; |
11 | import java.util.Iterator; |
12 | import java.util.List; |
13 | import java.util.Map; |
14 | |
15 | import org.eclipse.core.commands.ExecutionException; |
16 | import org.eclipse.core.resources.IFile; |
17 | import org.eclipse.core.resources.IResource; |
18 | import org.eclipse.core.resources.IResourceStatus; |
19 | import org.eclipse.core.resources.IStorage; |
20 | import org.eclipse.core.resources.ResourcesPlugin; |
21 | import org.eclipse.core.runtime.CoreException; |
22 | import org.eclipse.core.runtime.IAdaptable; |
23 | import org.eclipse.core.runtime.IProgressMonitor; |
24 | import org.eclipse.core.runtime.IStatus; |
25 | import org.eclipse.core.runtime.Path; |
26 | import org.eclipse.core.runtime.Status; |
27 | import org.eclipse.core.runtime.jobs.ISchedulingRule; |
28 | import org.eclipse.core.runtime.jobs.MultiRule; |
29 | import org.eclipse.emf.common.notify.Adapter; |
30 | import org.eclipse.emf.common.notify.Notification; |
31 | import org.eclipse.emf.common.notify.Notifier; |
32 | import org.eclipse.emf.common.ui.URIEditorInput; |
33 | import org.eclipse.emf.common.util.URI; |
34 | import org.eclipse.emf.ecore.EObject; |
35 | import org.eclipse.emf.ecore.resource.Resource; |
36 | import org.eclipse.emf.ecore.resource.ResourceSet; |
37 | import org.eclipse.emf.ecore.util.EContentAdapter; |
38 | import org.eclipse.emf.ecore.util.EcoreUtil; |
39 | import org.eclipse.emf.transaction.NotificationFilter; |
40 | import org.eclipse.emf.transaction.TransactionalEditingDomain; |
41 | import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; |
42 | import org.eclipse.gmf.runtime.common.core.command.CommandResult; |
43 | import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory; |
44 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.AbstractDocumentProvider; |
45 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.DiagramDocument; |
46 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument; |
47 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocumentProvider; |
48 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument; |
49 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.EditorStatusCodes; |
50 | import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.util.DiagramIOUtil; |
51 | import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; |
52 | import org.eclipse.gmf.runtime.emf.core.resources.GMFResourceFactory; |
53 | import org.eclipse.gmf.runtime.notation.Diagram; |
54 | import org.eclipse.jface.operation.IRunnableContext; |
55 | import org.eclipse.osgi.util.NLS; |
56 | import org.eclipse.swt.widgets.Display; |
57 | import org.eclipse.ui.IEditorInput; |
58 | import org.eclipse.ui.part.FileEditorInput; |
59 | |
60 | /** |
61 | * @generated |
62 | */ |
63 | public class PalladioComponentModelDocumentProvider extends |
64 | AbstractDocumentProvider implements IDiagramDocumentProvider { |
65 | |
66 | /** |
67 | * @generated |
68 | */ |
69 | protected ElementInfo createElementInfo(Object element) |
70 | throws CoreException { |
71 | if (false == element instanceof FileEditorInput |
72 | && false == element instanceof URIEditorInput) { |
73 | throw new CoreException( |
74 | new Status( |
75 | IStatus.ERROR, |
76 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
77 | 0, |
78 | NLS |
79 | .bind( |
80 | Messages.PalladioComponentModelDocumentProvider_IncorrectInputError, |
81 | new Object[] { |
82 | element, |
83 | "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$ |
84 | null)); |
85 | } |
86 | IEditorInput editorInput = (IEditorInput) element; |
87 | IDiagramDocument document = (IDiagramDocument) createDocument(editorInput); |
88 | |
89 | ResourceSetInfo info = new ResourceSetInfo(document, editorInput); |
90 | info.setModificationStamp(computeModificationStamp(info)); |
91 | info.fStatus = null; |
92 | return info; |
93 | } |
94 | |
95 | /** |
96 | * @generated |
97 | */ |
98 | protected IDocument createDocument(Object element) throws CoreException { |
99 | if (false == element instanceof FileEditorInput |
100 | && false == element instanceof URIEditorInput) { |
101 | throw new CoreException( |
102 | new Status( |
103 | IStatus.ERROR, |
104 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
105 | 0, |
106 | NLS |
107 | .bind( |
108 | Messages.PalladioComponentModelDocumentProvider_IncorrectInputError, |
109 | new Object[] { |
110 | element, |
111 | "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$ |
112 | null)); |
113 | } |
114 | IDocument document = createEmptyDocument(); |
115 | setDocumentContent(document, (IEditorInput) element); |
116 | setupDocument(element, document); |
117 | return document; |
118 | } |
119 | |
120 | /** |
121 | * Sets up the given document as it would be provided for the given element. The |
122 | * content of the document is not changed. This default implementation is empty. |
123 | * Subclasses may reimplement. |
124 | * |
125 | * @param element the blue-print element |
126 | * @param document the document to set up |
127 | * @generated |
128 | */ |
129 | protected void setupDocument(Object element, IDocument document) { |
130 | // for subclasses |
131 | } |
132 | |
133 | /** |
134 | * @generated |
135 | */ |
136 | private long computeModificationStamp(ResourceSetInfo info) { |
137 | int result = 0; |
138 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
139 | .getLoadedResourcesIterator(); it.hasNext();) { |
140 | Resource nextResource = (Resource) it.next(); |
141 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
142 | if (file != null) { |
143 | if (file.getLocation() != null) { |
144 | result += file.getLocation().toFile().lastModified(); |
145 | } else { |
146 | result += file.getModificationStamp(); |
147 | } |
148 | } |
149 | } |
150 | return result; |
151 | } |
152 | |
153 | /** |
154 | * @generated |
155 | */ |
156 | protected IDocument createEmptyDocument() { |
157 | DiagramDocument document = new DiagramDocument(); |
158 | document.setEditingDomain(createEditingDomain()); |
159 | return document; |
160 | } |
161 | |
162 | /** |
163 | * @generated |
164 | */ |
165 | private TransactionalEditingDomain createEditingDomain() { |
166 | TransactionalEditingDomain editingDomain = DiagramEditingDomainFactory |
167 | .getInstance().createEditingDomain(); |
168 | editingDomain.setID("de.uka.ipd.sdq.pcm.gmf.composite.EditingDomain"); //$NON-NLS-1$ |
169 | final NotificationFilter diagramResourceModifiedFilter = NotificationFilter |
170 | .createNotifierFilter(editingDomain.getResourceSet()).and( |
171 | NotificationFilter |
172 | .createEventTypeFilter(Notification.ADD)).and( |
173 | NotificationFilter.createFeatureFilter( |
174 | ResourceSet.class, |
175 | ResourceSet.RESOURCE_SET__RESOURCES)); |
176 | editingDomain.getResourceSet().eAdapters().add(new Adapter() { |
177 | |
178 | private Notifier myTarger; |
179 | |
180 | public Notifier getTarget() { |
181 | return myTarger; |
182 | } |
183 | |
184 | public boolean isAdapterForType(Object type) { |
185 | return false; |
186 | } |
187 | |
188 | public void notifyChanged(Notification notification) { |
189 | if (diagramResourceModifiedFilter.matches(notification)) { |
190 | Object value = notification.getNewValue(); |
191 | if (value instanceof Resource) { |
192 | ((Resource) value).setTrackingModification(true); |
193 | } |
194 | } |
195 | } |
196 | |
197 | public void setTarget(Notifier newTarget) { |
198 | myTarger = newTarget; |
199 | } |
200 | |
201 | }); |
202 | |
203 | return editingDomain; |
204 | } |
205 | |
206 | /** |
207 | * @generated |
208 | */ |
209 | protected void setDocumentContent(IDocument document, IEditorInput element) |
210 | throws CoreException { |
211 | IDiagramDocument diagramDocument = (IDiagramDocument) document; |
212 | TransactionalEditingDomain domain = diagramDocument.getEditingDomain(); |
213 | if (element instanceof FileEditorInput) { |
214 | IStorage storage = ((FileEditorInput) element).getStorage(); |
215 | Diagram diagram = DiagramIOUtil.load(domain, storage, true, |
216 | getProgressMonitor()); |
217 | document.setContent(diagram); |
218 | } else if (element instanceof URIEditorInput) { |
219 | URI uri = ((URIEditorInput) element).getURI(); |
220 | Resource resource = null; |
221 | try { |
222 | resource = domain.getResourceSet().getResource( |
223 | uri.trimFragment(), false); |
224 | if (resource == null) { |
225 | resource = domain.getResourceSet().createResource( |
226 | uri.trimFragment()); |
227 | } |
228 | if (!resource.isLoaded()) { |
229 | try { |
230 | Map options = new HashMap(GMFResourceFactory |
231 | .getDefaultLoadOptions()); |
232 | // @see 171060 |
233 | // options.put(org.eclipse.emf.ecore.xmi.XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE); |
234 | resource.load(options); |
235 | } catch (IOException e) { |
236 | resource.unload(); |
237 | throw e; |
238 | } |
239 | } |
240 | if (uri.fragment() != null) { |
241 | EObject rootElement = resource.getEObject(uri.fragment()); |
242 | if (rootElement instanceof Diagram) { |
243 | document.setContent((Diagram) rootElement); |
244 | return; |
245 | } |
246 | } else { |
247 | for (Iterator it = resource.getContents().iterator(); it |
248 | .hasNext();) { |
249 | Object rootElement = it.next(); |
250 | if (rootElement instanceof Diagram) { |
251 | document.setContent((Diagram) rootElement); |
252 | return; |
253 | } |
254 | } |
255 | } |
256 | throw new RuntimeException( |
257 | Messages.PalladioComponentModelDocumentProvider_NoDiagramInResourceError); |
258 | } catch (Exception e) { |
259 | CoreException thrownExcp = null; |
260 | if (e instanceof CoreException) { |
261 | thrownExcp = (CoreException) e; |
262 | } else { |
263 | String msg = e.getLocalizedMessage(); |
264 | thrownExcp = new CoreException( |
265 | new Status( |
266 | IStatus.ERROR, |
267 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
268 | 0, |
269 | msg != null ? msg |
270 | : Messages.PalladioComponentModelDocumentProvider_DiagramLoadingError, |
271 | e)); |
272 | } |
273 | throw thrownExcp; |
274 | } |
275 | } else { |
276 | throw new CoreException( |
277 | new Status( |
278 | IStatus.ERROR, |
279 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
280 | 0, |
281 | NLS |
282 | .bind( |
283 | Messages.PalladioComponentModelDocumentProvider_IncorrectInputError, |
284 | new Object[] { |
285 | element, |
286 | "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$ |
287 | null)); |
288 | } |
289 | } |
290 | |
291 | /** |
292 | * @generated |
293 | */ |
294 | public long getModificationStamp(Object element) { |
295 | ResourceSetInfo info = getResourceSetInfo(element); |
296 | if (info != null) { |
297 | return computeModificationStamp(info); |
298 | } |
299 | return super.getModificationStamp(element); |
300 | } |
301 | |
302 | /** |
303 | * @generated |
304 | */ |
305 | public boolean isDeleted(Object element) { |
306 | IDiagramDocument document = getDiagramDocument(element); |
307 | if (document != null) { |
308 | Resource diagramResource = document.getDiagram().eResource(); |
309 | if (diagramResource != null) { |
310 | IFile file = WorkspaceSynchronizer.getFile(diagramResource); |
311 | return file == null || file.getLocation() == null |
312 | || !file.getLocation().toFile().exists(); |
313 | } |
314 | } |
315 | return super.isDeleted(element); |
316 | } |
317 | |
318 | /** |
319 | * @generated |
320 | */ |
321 | public ResourceSetInfo getResourceSetInfo(Object editorInput) { |
322 | return (ResourceSetInfo) super.getElementInfo(editorInput); |
323 | } |
324 | |
325 | /** |
326 | * @generated |
327 | */ |
328 | protected void disposeElementInfo(Object element, ElementInfo info) { |
329 | if (info instanceof ResourceSetInfo) { |
330 | ResourceSetInfo resourceSetInfo = (ResourceSetInfo) info; |
331 | resourceSetInfo.dispose(); |
332 | } |
333 | super.disposeElementInfo(element, info); |
334 | } |
335 | |
336 | /** |
337 | * @generated |
338 | */ |
339 | protected void doValidateState(Object element, Object computationContext) |
340 | throws CoreException { |
341 | ResourceSetInfo info = getResourceSetInfo(element); |
342 | if (info != null) { |
343 | Collection/*<org.eclipse.core.resources.IFile>*/files2Validate = new ArrayList/*<org.eclipse.core.resources.IFile>*/(); |
344 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
345 | .getLoadedResourcesIterator(); it.hasNext();) { |
346 | Resource nextResource = (Resource) it.next(); |
347 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
348 | if (file != null && file.isReadOnly()) { |
349 | files2Validate.add(file); |
350 | } |
351 | } |
352 | ResourcesPlugin.getWorkspace().validateEdit( |
353 | (IFile[]) files2Validate.toArray(new IFile[files2Validate |
354 | .size()]), computationContext); |
355 | } |
356 | |
357 | super.doValidateState(element, computationContext); |
358 | } |
359 | |
360 | /** |
361 | * @generated |
362 | */ |
363 | public boolean isReadOnly(Object element) { |
364 | ResourceSetInfo info = getResourceSetInfo(element); |
365 | if (info != null) { |
366 | if (info.isUpdateCache()) { |
367 | try { |
368 | updateCache(element); |
369 | } catch (CoreException ex) { |
370 | PalladioComponentModelComposedStructureDiagramEditorPlugin |
371 | .getInstance() |
372 | .logError( |
373 | Messages.PalladioComponentModelDocumentProvider_isModifiable, |
374 | ex); |
375 | // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.StorageDocumentProvider_isModifiable |
376 | } |
377 | } |
378 | return info.isReadOnly(); |
379 | } |
380 | return super.isReadOnly(element); |
381 | } |
382 | |
383 | /** |
384 | * @generated |
385 | */ |
386 | public boolean isModifiable(Object element) { |
387 | if (!isStateValidated(element)) { |
388 | if (element instanceof FileEditorInput |
389 | || element instanceof URIEditorInput) { |
390 | return true; |
391 | } |
392 | } |
393 | ResourceSetInfo info = getResourceSetInfo(element); |
394 | if (info != null) { |
395 | if (info.isUpdateCache()) { |
396 | try { |
397 | updateCache(element); |
398 | } catch (CoreException ex) { |
399 | PalladioComponentModelComposedStructureDiagramEditorPlugin |
400 | .getInstance() |
401 | .logError( |
402 | Messages.PalladioComponentModelDocumentProvider_isModifiable, |
403 | ex); |
404 | // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.StorageDocumentProvider_isModifiable |
405 | } |
406 | } |
407 | return info.isModifiable(); |
408 | } |
409 | return super.isModifiable(element); |
410 | } |
411 | |
412 | /** |
413 | * @generated |
414 | */ |
415 | protected void updateCache(Object element) throws CoreException { |
416 | ResourceSetInfo info = getResourceSetInfo(element); |
417 | if (info != null) { |
418 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
419 | .getLoadedResourcesIterator(); it.hasNext();) { |
420 | Resource nextResource = (Resource) it.next(); |
421 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
422 | if (file != null && file.isReadOnly()) { |
423 | info.setReadOnly(true); |
424 | info.setModifiable(false); |
425 | return; |
426 | } |
427 | } |
428 | info.setReadOnly(false); |
429 | info.setModifiable(true); |
430 | return; |
431 | } |
432 | } |
433 | |
434 | /** |
435 | * @generated |
436 | */ |
437 | protected void doUpdateStateCache(Object element) throws CoreException { |
438 | ResourceSetInfo info = getResourceSetInfo(element); |
439 | if (info != null) { |
440 | info.setUpdateCache(true); |
441 | } |
442 | super.doUpdateStateCache(element); |
443 | } |
444 | |
445 | /** |
446 | * @generated |
447 | */ |
448 | public boolean isSynchronized(Object element) { |
449 | ResourceSetInfo info = getResourceSetInfo(element); |
450 | if (info != null) { |
451 | return info.isSynchronized(); |
452 | } |
453 | return super.isSynchronized(element); |
454 | } |
455 | |
456 | /** |
457 | * @generated |
458 | */ |
459 | protected ISchedulingRule getResetRule(Object element) { |
460 | ResourceSetInfo info = getResourceSetInfo(element); |
461 | if (info != null) { |
462 | Collection/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/rules = new ArrayList/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/(); |
463 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
464 | .getLoadedResourcesIterator(); it.hasNext();) { |
465 | Resource nextResource = (Resource) it.next(); |
466 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
467 | if (file != null) { |
468 | rules.add(ResourcesPlugin.getWorkspace().getRuleFactory() |
469 | .modifyRule(file)); |
470 | } |
471 | } |
472 | return new MultiRule((ISchedulingRule[]) rules |
473 | .toArray(new ISchedulingRule[rules.size()])); |
474 | } |
475 | return null; |
476 | } |
477 | |
478 | /** |
479 | * @generated |
480 | */ |
481 | protected ISchedulingRule getSaveRule(Object element) { |
482 | ResourceSetInfo info = getResourceSetInfo(element); |
483 | if (info != null) { |
484 | Collection/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/rules = new ArrayList/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/(); |
485 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
486 | .getLoadedResourcesIterator(); it.hasNext();) { |
487 | Resource nextResource = (Resource) it.next(); |
488 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
489 | if (file != null) { |
490 | rules.add(computeSchedulingRule(file)); |
491 | } |
492 | } |
493 | return new MultiRule((ISchedulingRule[]) rules |
494 | .toArray(new ISchedulingRule[rules.size()])); |
495 | } |
496 | return null; |
497 | } |
498 | |
499 | /** |
500 | * @generated |
501 | */ |
502 | protected ISchedulingRule getSynchronizeRule(Object element) { |
503 | ResourceSetInfo info = getResourceSetInfo(element); |
504 | if (info != null) { |
505 | Collection/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/rules = new ArrayList/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/(); |
506 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
507 | .getLoadedResourcesIterator(); it.hasNext();) { |
508 | Resource nextResource = (Resource) it.next(); |
509 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
510 | if (file != null) { |
511 | rules.add(ResourcesPlugin.getWorkspace().getRuleFactory() |
512 | .refreshRule(file)); |
513 | } |
514 | } |
515 | return new MultiRule((ISchedulingRule[]) rules |
516 | .toArray(new ISchedulingRule[rules.size()])); |
517 | } |
518 | return null; |
519 | } |
520 | |
521 | /** |
522 | * @generated |
523 | */ |
524 | protected ISchedulingRule getValidateStateRule(Object element) { |
525 | ResourceSetInfo info = getResourceSetInfo(element); |
526 | if (info != null) { |
527 | Collection/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/files = new ArrayList/*<org.eclipse.core.runtime.jobs.ISchedulingRule>*/(); |
528 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
529 | .getLoadedResourcesIterator(); it.hasNext();) { |
530 | Resource nextResource = (Resource) it.next(); |
531 | IFile file = WorkspaceSynchronizer.getFile(nextResource); |
532 | if (file != null) { |
533 | files.add(file); |
534 | } |
535 | } |
536 | return ResourcesPlugin.getWorkspace().getRuleFactory() |
537 | .validateEditRule( |
538 | (IFile[]) files.toArray(new IFile[files.size()])); |
539 | } |
540 | return null; |
541 | } |
542 | |
543 | /** |
544 | * @generated |
545 | */ |
546 | private ISchedulingRule computeSchedulingRule(IResource toCreateOrModify) { |
547 | if (toCreateOrModify.exists()) |
548 | return ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule( |
549 | toCreateOrModify); |
550 | |
551 | IResource parent = toCreateOrModify; |
552 | do { |
553 | /* |
554 | * XXX This is a workaround for |
555 | * https://bugs.eclipse.org/bugs/show_bug.cgi?id=67601 |
556 | * IResourceRuleFactory.createRule should iterate the hierarchy |
557 | * itself. |
558 | */ |
559 | toCreateOrModify = parent; |
560 | parent = toCreateOrModify.getParent(); |
561 | } while (parent != null && !parent.exists()); |
562 | |
563 | return ResourcesPlugin.getWorkspace().getRuleFactory().createRule( |
564 | toCreateOrModify); |
565 | } |
566 | |
567 | /** |
568 | * @generated |
569 | */ |
570 | protected void doSynchronize(Object element, IProgressMonitor monitor) |
571 | throws CoreException { |
572 | ResourceSetInfo info = getResourceSetInfo(element); |
573 | if (info != null) { |
574 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
575 | .getLoadedResourcesIterator(); it.hasNext();) { |
576 | Resource nextResource = (Resource) it.next(); |
577 | handleElementChanged(info, nextResource, monitor); |
578 | } |
579 | return; |
580 | } |
581 | super.doSynchronize(element, monitor); |
582 | } |
583 | |
584 | /** |
585 | * @generated |
586 | */ |
587 | protected void doSaveDocument(IProgressMonitor monitor, Object element, |
588 | IDocument document, boolean overwrite) throws CoreException { |
589 | ResourceSetInfo info = getResourceSetInfo(element); |
590 | if (info != null) { |
591 | if (!overwrite && !info.isSynchronized()) { |
592 | throw new CoreException( |
593 | new Status( |
594 | IStatus.ERROR, |
595 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
596 | IResourceStatus.OUT_OF_SYNC_LOCAL, |
597 | Messages.PalladioComponentModelDocumentProvider_UnsynchronizedFileSaveError, |
598 | null)); |
599 | } |
600 | info.stopResourceListening(); |
601 | fireElementStateChanging(element); |
602 | try { |
603 | monitor |
604 | .beginTask( |
605 | Messages.PalladioComponentModelDocumentProvider_SaveDiagramTask, |
606 | info.getResourceSet().getResources().size() + 1); //"Saving diagram" |
607 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = info |
608 | .getLoadedResourcesIterator(); it.hasNext();) { |
609 | Resource nextResource = (Resource) it.next(); |
610 | monitor |
611 | .setTaskName(NLS |
612 | .bind( |
613 | Messages.PalladioComponentModelDocumentProvider_SaveNextResourceTask, |
614 | nextResource.getURI())); |
615 | if (nextResource.isLoaded() |
616 | && !info.getEditingDomain() |
617 | .isReadOnly(nextResource)) { |
618 | try { |
619 | nextResource |
620 | .save(PalladioComponentModelDiagramEditorUtil |
621 | .getSaveOptions()); |
622 | } catch (IOException e) { |
623 | fireElementStateChangeFailed(element); |
624 | throw new CoreException( |
625 | new Status( |
626 | IStatus.ERROR, |
627 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
628 | EditorStatusCodes.RESOURCE_FAILURE, |
629 | e.getLocalizedMessage(), null)); |
630 | } |
631 | } |
632 | monitor.worked(1); |
633 | } |
634 | monitor.done(); |
635 | info.setModificationStamp(computeModificationStamp(info)); |
636 | } catch (RuntimeException x) { |
637 | fireElementStateChangeFailed(element); |
638 | throw x; |
639 | } finally { |
640 | info.startResourceListening(); |
641 | } |
642 | } else { |
643 | URI newResoruceURI; |
644 | List affectedFiles = null; |
645 | if (element instanceof FileEditorInput) { |
646 | IFile newFile = ((FileEditorInput) element).getFile(); |
647 | affectedFiles = Collections.singletonList(newFile); |
648 | newResoruceURI = URI.createPlatformResourceURI(newFile |
649 | .getFullPath().toString(), true); |
650 | } else if (element instanceof URIEditorInput) { |
651 | newResoruceURI = ((URIEditorInput) element).getURI(); |
652 | } else { |
653 | fireElementStateChangeFailed(element); |
654 | throw new CoreException( |
655 | new Status( |
656 | IStatus.ERROR, |
657 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
658 | 0, |
659 | NLS |
660 | .bind( |
661 | Messages.PalladioComponentModelDocumentProvider_IncorrectInputError, |
662 | new Object[] { |
663 | element, |
664 | "org.eclipse.ui.part.FileEditorInput", "org.eclipse.emf.common.ui.URIEditorInput" }), //$NON-NLS-1$ //$NON-NLS-2$ |
665 | null)); |
666 | } |
667 | if (false == document instanceof IDiagramDocument) { |
668 | fireElementStateChangeFailed(element); |
669 | throw new CoreException( |
670 | new Status( |
671 | IStatus.ERROR, |
672 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
673 | 0, |
674 | "Incorrect document used: " + document + " instead of org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument", null)); //$NON-NLS-1$ //$NON-NLS-2$ |
675 | } |
676 | IDiagramDocument diagramDocument = (IDiagramDocument) document; |
677 | final Resource newResource = diagramDocument.getEditingDomain() |
678 | .getResourceSet().createResource(newResoruceURI); |
679 | final Diagram diagramCopy = (Diagram) EcoreUtil |
680 | .copy(diagramDocument.getDiagram()); |
681 | try { |
682 | new AbstractTransactionalCommand( |
683 | diagramDocument.getEditingDomain(), |
684 | NLS |
685 | .bind( |
686 | Messages.PalladioComponentModelDocumentProvider_SaveAsOperation, |
687 | diagramCopy.getName()), affectedFiles) { |
688 | protected CommandResult doExecuteWithResult( |
689 | IProgressMonitor monitor, IAdaptable info) |
690 | throws ExecutionException { |
691 | newResource.getContents().add(diagramCopy); |
692 | return CommandResult.newOKCommandResult(); |
693 | } |
694 | }.execute(monitor, null); |
695 | newResource.save(PalladioComponentModelDiagramEditorUtil |
696 | .getSaveOptions()); |
697 | } catch (ExecutionException e) { |
698 | fireElementStateChangeFailed(element); |
699 | throw new CoreException( |
700 | new Status( |
701 | IStatus.ERROR, |
702 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
703 | 0, e.getLocalizedMessage(), null)); |
704 | } catch (IOException e) { |
705 | fireElementStateChangeFailed(element); |
706 | throw new CoreException( |
707 | new Status( |
708 | IStatus.ERROR, |
709 | PalladioComponentModelComposedStructureDiagramEditorPlugin.ID, |
710 | 0, e.getLocalizedMessage(), null)); |
711 | } |
712 | newResource.unload(); |
713 | } |
714 | } |
715 | |
716 | /** |
717 | * @generated |
718 | */ |
719 | protected void handleElementChanged(ResourceSetInfo info, |
720 | Resource changedResource, IProgressMonitor monitor) { |
721 | IFile file = WorkspaceSynchronizer.getFile(changedResource); |
722 | if (file != null) { |
723 | try { |
724 | file.refreshLocal(IResource.DEPTH_INFINITE, monitor); |
725 | } catch (CoreException ex) { |
726 | PalladioComponentModelComposedStructureDiagramEditorPlugin |
727 | .getInstance() |
728 | .logError( |
729 | Messages.PalladioComponentModelDocumentProvider_handleElementContentChanged, |
730 | ex); |
731 | // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.FileDocumentProvider_handleElementContentChanged |
732 | } |
733 | } |
734 | changedResource.unload(); |
735 | |
736 | fireElementContentAboutToBeReplaced(info.getEditorInput()); |
737 | removeUnchangedElementListeners(info.getEditorInput(), info); |
738 | info.fStatus = null; |
739 | try { |
740 | setDocumentContent(info.fDocument, info.getEditorInput()); |
741 | } catch (CoreException e) { |
742 | info.fStatus = e.getStatus(); |
743 | } |
744 | if (!info.fCanBeSaved) { |
745 | info.setModificationStamp(computeModificationStamp(info)); |
746 | } |
747 | addUnchangedElementListeners(info.getEditorInput(), info); |
748 | fireElementContentReplaced(info.getEditorInput()); |
749 | } |
750 | |
751 | /** |
752 | * @generated |
753 | */ |
754 | protected void handleElementMoved(IEditorInput input, URI uri) { |
755 | if (input instanceof FileEditorInput) { |
756 | IFile newFile = ResourcesPlugin.getWorkspace().getRoot().getFile( |
757 | new Path(URI.decode(uri.path())).removeFirstSegments(1)); |
758 | fireElementMoved(input, newFile == null ? null |
759 | : new FileEditorInput(newFile)); |
760 | return; |
761 | } |
762 | // TODO: append suffix to the URI! (use diagram as a parameter) |
763 | fireElementMoved(input, new URIEditorInput(uri)); |
764 | } |
765 | |
766 | /** |
767 | * @generated |
768 | */ |
769 | public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, |
770 | TransactionalEditingDomain domain) { |
771 | return editorInput; |
772 | } |
773 | |
774 | /** |
775 | * @generated |
776 | */ |
777 | public IDiagramDocument getDiagramDocument(Object element) { |
778 | IDocument doc = getDocument(element); |
779 | if (doc instanceof IDiagramDocument) { |
780 | return (IDiagramDocument) doc; |
781 | } |
782 | return null; |
783 | } |
784 | |
785 | /** |
786 | * @generated |
787 | */ |
788 | protected IRunnableContext getOperationRunner(IProgressMonitor monitor) { |
789 | return null; |
790 | } |
791 | |
792 | /** |
793 | * @generated |
794 | */ |
795 | protected class ResourceSetInfo extends ElementInfo { |
796 | |
797 | /** |
798 | * @generated |
799 | */ |
800 | private long myModificationStamp = IResource.NULL_STAMP; |
801 | |
802 | /** |
803 | * @generated |
804 | */ |
805 | private WorkspaceSynchronizer mySynchronizer; |
806 | |
807 | /** |
808 | * @generated |
809 | */ |
810 | private Collection myUnSynchronizedResources = new ArrayList(); |
811 | |
812 | /** |
813 | * @generated |
814 | */ |
815 | private IDiagramDocument myDocument; |
816 | |
817 | /** |
818 | * @generated |
819 | */ |
820 | private IEditorInput myEditorInput; |
821 | |
822 | /** |
823 | * @generated |
824 | */ |
825 | private boolean myUpdateCache = true; |
826 | |
827 | /** |
828 | * @generated |
829 | */ |
830 | private boolean myModifiable = false; |
831 | |
832 | /** |
833 | * @generated |
834 | */ |
835 | private boolean myReadOnly = true; |
836 | |
837 | /** |
838 | * @generated |
839 | */ |
840 | private ResourceSetModificationListener myResourceSetListener; |
841 | |
842 | /** |
843 | * @generated |
844 | */ |
845 | public ResourceSetInfo(IDiagramDocument document, |
846 | IEditorInput editorInput) { |
847 | super(document); |
848 | myDocument = document; |
849 | myEditorInput = editorInput; |
850 | startResourceListening(); |
851 | myResourceSetListener = new ResourceSetModificationListener(this); |
852 | getResourceSet().eAdapters().add(myResourceSetListener); |
853 | } |
854 | |
855 | /** |
856 | * @generated |
857 | */ |
858 | public long getModificationStamp() { |
859 | return myModificationStamp; |
860 | } |
861 | |
862 | /** |
863 | * @generated |
864 | */ |
865 | public void setModificationStamp(long modificationStamp) { |
866 | myModificationStamp = modificationStamp; |
867 | } |
868 | |
869 | /** |
870 | * @generated |
871 | */ |
872 | public TransactionalEditingDomain getEditingDomain() { |
873 | return myDocument.getEditingDomain(); |
874 | } |
875 | |
876 | /** |
877 | * @generated |
878 | */ |
879 | public ResourceSet getResourceSet() { |
880 | return getEditingDomain().getResourceSet(); |
881 | } |
882 | |
883 | /** |
884 | * @generated |
885 | */ |
886 | public Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/getLoadedResourcesIterator() { |
887 | return new ArrayList/*<org.eclipse.emf.ecore.resource.Resource>*/( |
888 | getResourceSet().getResources()).iterator(); |
889 | } |
890 | |
891 | /** |
892 | * @generated |
893 | */ |
894 | public IEditorInput getEditorInput() { |
895 | return myEditorInput; |
896 | } |
897 | |
898 | /** |
899 | * @generated |
900 | */ |
901 | public void dispose() { |
902 | stopResourceListening(); |
903 | getResourceSet().eAdapters().remove(myResourceSetListener); |
904 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = getLoadedResourcesIterator(); it |
905 | .hasNext();) { |
906 | Resource resource = (Resource) it.next(); |
907 | resource.unload(); |
908 | } |
909 | getEditingDomain().dispose(); |
910 | } |
911 | |
912 | /** |
913 | * @generated |
914 | */ |
915 | public boolean isSynchronized() { |
916 | return myUnSynchronizedResources.size() == 0; |
917 | } |
918 | |
919 | /** |
920 | * @generated |
921 | */ |
922 | public void setUnSynchronized(Resource resource) { |
923 | myUnSynchronizedResources.add(resource); |
924 | } |
925 | |
926 | /** |
927 | * @generated |
928 | */ |
929 | public void setSynchronized(Resource resource) { |
930 | myUnSynchronizedResources.remove(resource); |
931 | } |
932 | |
933 | /** |
934 | * @generated |
935 | */ |
936 | public final void stopResourceListening() { |
937 | mySynchronizer.dispose(); |
938 | mySynchronizer = null; |
939 | } |
940 | |
941 | /** |
942 | * @generated |
943 | */ |
944 | public final void startResourceListening() { |
945 | mySynchronizer = new WorkspaceSynchronizer(getEditingDomain(), |
946 | new SynchronizerDelegate()); |
947 | } |
948 | |
949 | /** |
950 | * @generated |
951 | */ |
952 | public boolean isUpdateCache() { |
953 | return myUpdateCache; |
954 | } |
955 | |
956 | /** |
957 | * @generated |
958 | */ |
959 | public void setUpdateCache(boolean update) { |
960 | myUpdateCache = update; |
961 | } |
962 | |
963 | /** |
964 | * @generated |
965 | */ |
966 | public boolean isModifiable() { |
967 | return myModifiable; |
968 | } |
969 | |
970 | /** |
971 | * @generated |
972 | */ |
973 | public void setModifiable(boolean modifiable) { |
974 | myModifiable = modifiable; |
975 | } |
976 | |
977 | /** |
978 | * @generated |
979 | */ |
980 | public boolean isReadOnly() { |
981 | return myReadOnly; |
982 | } |
983 | |
984 | /** |
985 | * @generated |
986 | */ |
987 | public void setReadOnly(boolean readOnly) { |
988 | myReadOnly = readOnly; |
989 | } |
990 | |
991 | /** |
992 | * @generated |
993 | */ |
994 | private class SynchronizerDelegate implements |
995 | WorkspaceSynchronizer.Delegate { |
996 | |
997 | /** |
998 | * @generated |
999 | */ |
1000 | public void dispose() { |
1001 | } |
1002 | |
1003 | /** |
1004 | * @generated |
1005 | */ |
1006 | public boolean handleResourceChanged(final Resource resource) { |
1007 | synchronized (ResourceSetInfo.this) { |
1008 | if (ResourceSetInfo.this.fCanBeSaved) { |
1009 | ResourceSetInfo.this.setUnSynchronized(resource); |
1010 | return true; |
1011 | } |
1012 | } |
1013 | Display.getDefault().asyncExec(new Runnable() { |
1014 | public void run() { |
1015 | handleElementChanged(ResourceSetInfo.this, resource, |
1016 | null); |
1017 | } |
1018 | }); |
1019 | return true; |
1020 | } |
1021 | |
1022 | /** |
1023 | * @generated |
1024 | */ |
1025 | public boolean handleResourceDeleted(Resource resource) { |
1026 | synchronized (ResourceSetInfo.this) { |
1027 | if (ResourceSetInfo.this.fCanBeSaved) { |
1028 | ResourceSetInfo.this.setUnSynchronized(resource); |
1029 | return true; |
1030 | } |
1031 | } |
1032 | Display.getDefault().asyncExec(new Runnable() { |
1033 | public void run() { |
1034 | fireElementDeleted(ResourceSetInfo.this |
1035 | .getEditorInput()); |
1036 | } |
1037 | }); |
1038 | return true; |
1039 | } |
1040 | |
1041 | /** |
1042 | * @generated |
1043 | */ |
1044 | public boolean handleResourceMoved(Resource resource, |
1045 | final URI newURI) { |
1046 | synchronized (ResourceSetInfo.this) { |
1047 | if (ResourceSetInfo.this.fCanBeSaved) { |
1048 | ResourceSetInfo.this.setUnSynchronized(resource); |
1049 | return true; |
1050 | } |
1051 | } |
1052 | if (myDocument.getDiagram().eResource() == resource) { |
1053 | Display.getDefault().asyncExec(new Runnable() { |
1054 | public void run() { |
1055 | handleElementMoved(ResourceSetInfo.this |
1056 | .getEditorInput(), newURI); |
1057 | } |
1058 | }); |
1059 | } else { |
1060 | handleResourceDeleted(resource); |
1061 | } |
1062 | return true; |
1063 | } |
1064 | |
1065 | } |
1066 | |
1067 | } |
1068 | |
1069 | /** |
1070 | * @generated |
1071 | */ |
1072 | private class ResourceSetModificationListener extends EContentAdapter { |
1073 | |
1074 | /** |
1075 | * @generated |
1076 | */ |
1077 | private NotificationFilter myModifiedFilter; |
1078 | |
1079 | /** |
1080 | * @generated |
1081 | */ |
1082 | private ResourceSetInfo myInfo; |
1083 | |
1084 | /** |
1085 | * @generated |
1086 | */ |
1087 | public ResourceSetModificationListener(ResourceSetInfo info) { |
1088 | myInfo = info; |
1089 | myModifiedFilter = NotificationFilter.createEventTypeFilter( |
1090 | Notification.SET).or( |
1091 | NotificationFilter |
1092 | .createEventTypeFilter(Notification.UNSET)).and( |
1093 | NotificationFilter.createFeatureFilter(Resource.class, |
1094 | Resource.RESOURCE__IS_MODIFIED)); |
1095 | } |
1096 | |
1097 | /** |
1098 | * @generated |
1099 | */ |
1100 | public void notifyChanged(Notification notification) { |
1101 | if (notification.getNotifier() instanceof ResourceSet) { |
1102 | super.notifyChanged(notification); |
1103 | } |
1104 | if (!notification.isTouch() |
1105 | && myModifiedFilter.matches(notification)) { |
1106 | if (notification.getNotifier() instanceof Resource) { |
1107 | Resource resource = (Resource) notification.getNotifier(); |
1108 | if (resource.isLoaded()) { |
1109 | boolean modified = false; |
1110 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = myInfo |
1111 | .getLoadedResourcesIterator(); it.hasNext() |
1112 | && !modified;) { |
1113 | Resource nextResource = (Resource) it.next(); |
1114 | if (nextResource.isLoaded()) { |
1115 | modified = nextResource.isModified(); |
1116 | } |
1117 | } |
1118 | boolean dirtyStateChanged = false; |
1119 | synchronized (myInfo) { |
1120 | if (modified != myInfo.fCanBeSaved) { |
1121 | myInfo.fCanBeSaved = modified; |
1122 | dirtyStateChanged = true; |
1123 | } |
1124 | if (!resource.isModified()) { |
1125 | myInfo.setSynchronized(resource); |
1126 | } |
1127 | } |
1128 | if (dirtyStateChanged) { |
1129 | fireElementDirtyStateChanged(myInfo |
1130 | .getEditorInput(), modified); |
1131 | |
1132 | if (!modified) { |
1133 | myInfo |
1134 | .setModificationStamp(computeModificationStamp(myInfo)); |
1135 | } |
1136 | } |
1137 | } |
1138 | } |
1139 | } |
1140 | } |
1141 | |
1142 | } |
1143 | |
1144 | } |