1 | /* |
2 | * Copyright 2007, SDQ, IPD, University of Karlsruhe |
3 | */ |
4 | package de.uka.ipd.sdq.pcm.gmf.usage.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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin.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.usage.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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin |
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 | PalladioComponentModelUsageDiagramEditorPlugin |
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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin.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 | PalladioComponentModelUsageDiagramEditorPlugin.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(new Status(IStatus.ERROR, |
700 | PalladioComponentModelUsageDiagramEditorPlugin.ID, 0, e |
701 | .getLocalizedMessage(), null)); |
702 | } catch (IOException e) { |
703 | fireElementStateChangeFailed(element); |
704 | throw new CoreException(new Status(IStatus.ERROR, |
705 | PalladioComponentModelUsageDiagramEditorPlugin.ID, 0, e |
706 | .getLocalizedMessage(), null)); |
707 | } |
708 | newResource.unload(); |
709 | } |
710 | } |
711 | |
712 | /** |
713 | * @generated |
714 | */ |
715 | protected void handleElementChanged(ResourceSetInfo info, |
716 | Resource changedResource, IProgressMonitor monitor) { |
717 | IFile file = WorkspaceSynchronizer.getFile(changedResource); |
718 | if (file != null) { |
719 | try { |
720 | file.refreshLocal(IResource.DEPTH_INFINITE, monitor); |
721 | } catch (CoreException ex) { |
722 | PalladioComponentModelUsageDiagramEditorPlugin |
723 | .getInstance() |
724 | .logError( |
725 | Messages.PalladioComponentModelDocumentProvider_handleElementContentChanged, |
726 | ex); |
727 | // Error message to log was initially taken from org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.internal.l10n.EditorMessages.FileDocumentProvider_handleElementContentChanged |
728 | } |
729 | } |
730 | changedResource.unload(); |
731 | |
732 | fireElementContentAboutToBeReplaced(info.getEditorInput()); |
733 | removeUnchangedElementListeners(info.getEditorInput(), info); |
734 | info.fStatus = null; |
735 | try { |
736 | setDocumentContent(info.fDocument, info.getEditorInput()); |
737 | } catch (CoreException e) { |
738 | info.fStatus = e.getStatus(); |
739 | } |
740 | if (!info.fCanBeSaved) { |
741 | info.setModificationStamp(computeModificationStamp(info)); |
742 | } |
743 | addUnchangedElementListeners(info.getEditorInput(), info); |
744 | fireElementContentReplaced(info.getEditorInput()); |
745 | } |
746 | |
747 | /** |
748 | * @generated |
749 | */ |
750 | protected void handleElementMoved(IEditorInput input, URI uri) { |
751 | if (input instanceof FileEditorInput) { |
752 | IFile newFile = ResourcesPlugin.getWorkspace().getRoot().getFile( |
753 | new Path(URI.decode(uri.path())).removeFirstSegments(1)); |
754 | fireElementMoved(input, newFile == null ? null |
755 | : new FileEditorInput(newFile)); |
756 | return; |
757 | } |
758 | // TODO: append suffix to the URI! (use diagram as a parameter) |
759 | fireElementMoved(input, new URIEditorInput(uri)); |
760 | } |
761 | |
762 | /** |
763 | * @generated |
764 | */ |
765 | public IEditorInput createInputWithEditingDomain(IEditorInput editorInput, |
766 | TransactionalEditingDomain domain) { |
767 | return editorInput; |
768 | } |
769 | |
770 | /** |
771 | * @generated |
772 | */ |
773 | public IDiagramDocument getDiagramDocument(Object element) { |
774 | IDocument doc = getDocument(element); |
775 | if (doc instanceof IDiagramDocument) { |
776 | return (IDiagramDocument) doc; |
777 | } |
778 | return null; |
779 | } |
780 | |
781 | /** |
782 | * @generated |
783 | */ |
784 | protected IRunnableContext getOperationRunner(IProgressMonitor monitor) { |
785 | return null; |
786 | } |
787 | |
788 | /** |
789 | * @generated |
790 | */ |
791 | protected class ResourceSetInfo extends ElementInfo { |
792 | |
793 | /** |
794 | * @generated |
795 | */ |
796 | private long myModificationStamp = IResource.NULL_STAMP; |
797 | |
798 | /** |
799 | * @generated |
800 | */ |
801 | private WorkspaceSynchronizer mySynchronizer; |
802 | |
803 | /** |
804 | * @generated |
805 | */ |
806 | private Collection myUnSynchronizedResources = new ArrayList(); |
807 | |
808 | /** |
809 | * @generated |
810 | */ |
811 | private IDiagramDocument myDocument; |
812 | |
813 | /** |
814 | * @generated |
815 | */ |
816 | private IEditorInput myEditorInput; |
817 | |
818 | /** |
819 | * @generated |
820 | */ |
821 | private boolean myUpdateCache = true; |
822 | |
823 | /** |
824 | * @generated |
825 | */ |
826 | private boolean myModifiable = false; |
827 | |
828 | /** |
829 | * @generated |
830 | */ |
831 | private boolean myReadOnly = true; |
832 | |
833 | /** |
834 | * @generated |
835 | */ |
836 | private ResourceSetModificationListener myResourceSetListener; |
837 | |
838 | /** |
839 | * @generated |
840 | */ |
841 | public ResourceSetInfo(IDiagramDocument document, |
842 | IEditorInput editorInput) { |
843 | super(document); |
844 | myDocument = document; |
845 | myEditorInput = editorInput; |
846 | startResourceListening(); |
847 | myResourceSetListener = new ResourceSetModificationListener(this); |
848 | getResourceSet().eAdapters().add(myResourceSetListener); |
849 | } |
850 | |
851 | /** |
852 | * @generated |
853 | */ |
854 | public long getModificationStamp() { |
855 | return myModificationStamp; |
856 | } |
857 | |
858 | /** |
859 | * @generated |
860 | */ |
861 | public void setModificationStamp(long modificationStamp) { |
862 | myModificationStamp = modificationStamp; |
863 | } |
864 | |
865 | /** |
866 | * @generated |
867 | */ |
868 | public TransactionalEditingDomain getEditingDomain() { |
869 | return myDocument.getEditingDomain(); |
870 | } |
871 | |
872 | /** |
873 | * @generated |
874 | */ |
875 | public ResourceSet getResourceSet() { |
876 | return getEditingDomain().getResourceSet(); |
877 | } |
878 | |
879 | /** |
880 | * @generated |
881 | */ |
882 | public Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/getLoadedResourcesIterator() { |
883 | return new ArrayList/*<org.eclipse.emf.ecore.resource.Resource>*/( |
884 | getResourceSet().getResources()).iterator(); |
885 | } |
886 | |
887 | /** |
888 | * @generated |
889 | */ |
890 | public IEditorInput getEditorInput() { |
891 | return myEditorInput; |
892 | } |
893 | |
894 | /** |
895 | * @generated |
896 | */ |
897 | public void dispose() { |
898 | stopResourceListening(); |
899 | getResourceSet().eAdapters().remove(myResourceSetListener); |
900 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = getLoadedResourcesIterator(); it |
901 | .hasNext();) { |
902 | Resource resource = (Resource) it.next(); |
903 | resource.unload(); |
904 | } |
905 | getEditingDomain().dispose(); |
906 | } |
907 | |
908 | /** |
909 | * @generated |
910 | */ |
911 | public boolean isSynchronized() { |
912 | return myUnSynchronizedResources.size() == 0; |
913 | } |
914 | |
915 | /** |
916 | * @generated |
917 | */ |
918 | public void setUnSynchronized(Resource resource) { |
919 | myUnSynchronizedResources.add(resource); |
920 | } |
921 | |
922 | /** |
923 | * @generated |
924 | */ |
925 | public void setSynchronized(Resource resource) { |
926 | myUnSynchronizedResources.remove(resource); |
927 | } |
928 | |
929 | /** |
930 | * @generated |
931 | */ |
932 | public final void stopResourceListening() { |
933 | mySynchronizer.dispose(); |
934 | mySynchronizer = null; |
935 | } |
936 | |
937 | /** |
938 | * @generated |
939 | */ |
940 | public final void startResourceListening() { |
941 | mySynchronizer = new WorkspaceSynchronizer(getEditingDomain(), |
942 | new SynchronizerDelegate()); |
943 | } |
944 | |
945 | /** |
946 | * @generated |
947 | */ |
948 | public boolean isUpdateCache() { |
949 | return myUpdateCache; |
950 | } |
951 | |
952 | /** |
953 | * @generated |
954 | */ |
955 | public void setUpdateCache(boolean update) { |
956 | myUpdateCache = update; |
957 | } |
958 | |
959 | /** |
960 | * @generated |
961 | */ |
962 | public boolean isModifiable() { |
963 | return myModifiable; |
964 | } |
965 | |
966 | /** |
967 | * @generated |
968 | */ |
969 | public void setModifiable(boolean modifiable) { |
970 | myModifiable = modifiable; |
971 | } |
972 | |
973 | /** |
974 | * @generated |
975 | */ |
976 | public boolean isReadOnly() { |
977 | return myReadOnly; |
978 | } |
979 | |
980 | /** |
981 | * @generated |
982 | */ |
983 | public void setReadOnly(boolean readOnly) { |
984 | myReadOnly = readOnly; |
985 | } |
986 | |
987 | /** |
988 | * @generated |
989 | */ |
990 | private class SynchronizerDelegate implements |
991 | WorkspaceSynchronizer.Delegate { |
992 | |
993 | /** |
994 | * @generated |
995 | */ |
996 | public void dispose() { |
997 | } |
998 | |
999 | /** |
1000 | * @generated |
1001 | */ |
1002 | public boolean handleResourceChanged(final Resource resource) { |
1003 | synchronized (ResourceSetInfo.this) { |
1004 | if (ResourceSetInfo.this.fCanBeSaved) { |
1005 | ResourceSetInfo.this.setUnSynchronized(resource); |
1006 | return true; |
1007 | } |
1008 | } |
1009 | Display.getDefault().asyncExec(new Runnable() { |
1010 | public void run() { |
1011 | handleElementChanged(ResourceSetInfo.this, resource, |
1012 | null); |
1013 | } |
1014 | }); |
1015 | return true; |
1016 | } |
1017 | |
1018 | /** |
1019 | * @generated |
1020 | */ |
1021 | public boolean handleResourceDeleted(Resource resource) { |
1022 | synchronized (ResourceSetInfo.this) { |
1023 | if (ResourceSetInfo.this.fCanBeSaved) { |
1024 | ResourceSetInfo.this.setUnSynchronized(resource); |
1025 | return true; |
1026 | } |
1027 | } |
1028 | Display.getDefault().asyncExec(new Runnable() { |
1029 | public void run() { |
1030 | fireElementDeleted(ResourceSetInfo.this |
1031 | .getEditorInput()); |
1032 | } |
1033 | }); |
1034 | return true; |
1035 | } |
1036 | |
1037 | /** |
1038 | * @generated |
1039 | */ |
1040 | public boolean handleResourceMoved(Resource resource, |
1041 | final URI newURI) { |
1042 | synchronized (ResourceSetInfo.this) { |
1043 | if (ResourceSetInfo.this.fCanBeSaved) { |
1044 | ResourceSetInfo.this.setUnSynchronized(resource); |
1045 | return true; |
1046 | } |
1047 | } |
1048 | if (myDocument.getDiagram().eResource() == resource) { |
1049 | Display.getDefault().asyncExec(new Runnable() { |
1050 | public void run() { |
1051 | handleElementMoved(ResourceSetInfo.this |
1052 | .getEditorInput(), newURI); |
1053 | } |
1054 | }); |
1055 | } else { |
1056 | handleResourceDeleted(resource); |
1057 | } |
1058 | return true; |
1059 | } |
1060 | |
1061 | } |
1062 | |
1063 | } |
1064 | |
1065 | /** |
1066 | * @generated |
1067 | */ |
1068 | private class ResourceSetModificationListener extends EContentAdapter { |
1069 | |
1070 | /** |
1071 | * @generated |
1072 | */ |
1073 | private NotificationFilter myModifiedFilter; |
1074 | |
1075 | /** |
1076 | * @generated |
1077 | */ |
1078 | private ResourceSetInfo myInfo; |
1079 | |
1080 | /** |
1081 | * @generated |
1082 | */ |
1083 | public ResourceSetModificationListener(ResourceSetInfo info) { |
1084 | myInfo = info; |
1085 | myModifiedFilter = NotificationFilter.createEventTypeFilter( |
1086 | Notification.SET).or( |
1087 | NotificationFilter |
1088 | .createEventTypeFilter(Notification.UNSET)).and( |
1089 | NotificationFilter.createFeatureFilter(Resource.class, |
1090 | Resource.RESOURCE__IS_MODIFIED)); |
1091 | } |
1092 | |
1093 | /** |
1094 | * @generated |
1095 | */ |
1096 | public void notifyChanged(Notification notification) { |
1097 | if (notification.getNotifier() instanceof ResourceSet) { |
1098 | super.notifyChanged(notification); |
1099 | } |
1100 | if (!notification.isTouch() |
1101 | && myModifiedFilter.matches(notification)) { |
1102 | if (notification.getNotifier() instanceof Resource) { |
1103 | Resource resource = (Resource) notification.getNotifier(); |
1104 | if (resource.isLoaded()) { |
1105 | boolean modified = false; |
1106 | for (Iterator/*<org.eclipse.emf.ecore.resource.Resource>*/it = myInfo |
1107 | .getLoadedResourcesIterator(); it.hasNext() |
1108 | && !modified;) { |
1109 | Resource nextResource = (Resource) it.next(); |
1110 | if (nextResource.isLoaded()) { |
1111 | modified = nextResource.isModified(); |
1112 | } |
1113 | } |
1114 | boolean dirtyStateChanged = false; |
1115 | synchronized (myInfo) { |
1116 | if (modified != myInfo.fCanBeSaved) { |
1117 | myInfo.fCanBeSaved = modified; |
1118 | dirtyStateChanged = true; |
1119 | } |
1120 | if (!resource.isModified()) { |
1121 | myInfo.setSynchronized(resource); |
1122 | } |
1123 | } |
1124 | if (dirtyStateChanged) { |
1125 | fireElementDirtyStateChanged(myInfo |
1126 | .getEditorInput(), modified); |
1127 | |
1128 | if (!modified) { |
1129 | myInfo |
1130 | .setModificationStamp(computeModificationStamp(myInfo)); |
1131 | } |
1132 | } |
1133 | } |
1134 | } |
1135 | } |
1136 | } |
1137 | |
1138 | } |
1139 | |
1140 | } |