Skip to content

Package: ViewEditorPart$ViewPartListener$1

ViewEditorPart$ViewPartListener$1

nameinstructionbranchcomplexitylinemethod
run()
M: 63 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
{...}
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Eugen Neufeld - initial API and implementation
13: * Christian W. Damus - bugs 543376, 548592
14: ******************************************************************************/
15: package org.eclipse.emf.ecp.ide.editor.view;
16:
17: import static org.eclipse.emf.ecp.view.spi.context.ViewModelContextFactory.provide;
18:
19: import java.io.File;
20: import java.io.IOException;
21: import java.io.InputStream;
22: import java.lang.reflect.InvocationTargetException;
23: import java.nio.file.Files;
24: import java.text.MessageFormat;
25: import java.util.ArrayList;
26: import java.util.Collections;
27: import java.util.EventObject;
28: import java.util.HashMap;
29: import java.util.HashSet;
30: import java.util.LinkedList;
31: import java.util.List;
32: import java.util.Map;
33: import java.util.Optional;
34: import java.util.Set;
35:
36: import org.eclipse.core.resources.IFile;
37: import org.eclipse.core.resources.IResource;
38: import org.eclipse.core.resources.IResourceChangeEvent;
39: import org.eclipse.core.resources.IResourceChangeListener;
40: import org.eclipse.core.resources.IResourceDelta;
41: import org.eclipse.core.resources.IResourceDeltaVisitor;
42: import org.eclipse.core.resources.IStorage;
43: import org.eclipse.core.resources.ResourcesPlugin;
44: import org.eclipse.core.runtime.CoreException;
45: import org.eclipse.core.runtime.IProgressMonitor;
46: import org.eclipse.core.runtime.IStatus;
47: import org.eclipse.core.runtime.Status;
48: import org.eclipse.e4.core.contexts.IEclipseContext;
49: import org.eclipse.emf.common.command.BasicCommandStack;
50: import org.eclipse.emf.common.command.CommandStackListener;
51: import org.eclipse.emf.common.notify.AdapterFactory;
52: import org.eclipse.emf.common.util.URI;
53: import org.eclipse.emf.ecore.EClass;
54: import org.eclipse.emf.ecore.EObject;
55: import org.eclipse.emf.ecore.EPackage;
56: import org.eclipse.emf.ecore.resource.Resource;
57: import org.eclipse.emf.ecore.resource.ResourceSet;
58: import org.eclipse.emf.ecore.util.EcoreUtil;
59: import org.eclipse.emf.ecore.xmi.XMLResource;
60: import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
61: import org.eclipse.emf.ecp.ide.editor.view.messages.Messages;
62: import org.eclipse.emf.ecp.ide.spi.util.EcoreHelper;
63: import org.eclipse.emf.ecp.ide.spi.util.ViewModelHelper;
64: import org.eclipse.emf.ecp.ide.view.service.ViewModelEditorCallback;
65: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelMigrationException;
66: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelMigratorUtil;
67: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelWorkspaceMigrator;
68: import org.eclipse.emf.ecp.ui.view.ECPRendererException;
69: import org.eclipse.emf.ecp.ui.view.swt.DefaultReferenceService;
70: import org.eclipse.emf.ecp.ui.view.swt.ECPSWTView;
71: import org.eclipse.emf.ecp.ui.view.swt.ECPSWTViewRenderer;
72: import org.eclipse.emf.ecp.view.migrator.ViewModelMigrationException;
73: import org.eclipse.emf.ecp.view.migrator.ViewModelMigrator;
74: import org.eclipse.emf.ecp.view.migrator.ViewModelMigratorUtil;
75: import org.eclipse.emf.ecp.view.migrator.ViewModelWorkspaceMigrator;
76: import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory;
77: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
78: import org.eclipse.emf.ecp.view.spi.context.ViewModelContextFactory;
79: import org.eclipse.emf.ecp.view.spi.model.VView;
80: import org.eclipse.emf.ecp.view.spi.model.reporting.StatusReport;
81: import org.eclipse.emf.ecp.view.spi.provider.ViewProviderHelper;
82: import org.eclipse.emf.ecp.view.spi.swt.services.ECPSelectionProviderService;
83: import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
84: import org.eclipse.emf.edit.domain.EditingDomain;
85: import org.eclipse.emf.edit.domain.IEditingDomainProvider;
86: import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
87: import org.eclipse.emf.edit.ui.util.EditUIUtil;
88: import org.eclipse.emfforms.spi.common.report.AbstractReport;
89: import org.eclipse.emfforms.spi.editor.GotoMarkerAdapter;
90: import org.eclipse.emfforms.spi.editor.helpers.ResourceSetHelpers;
91: import org.eclipse.emfforms.spi.ide.view.segments.DmrToSegmentsMigrationException;
92: import org.eclipse.emfforms.spi.ide.view.segments.DmrToSegmentsMigrator;
93: import org.eclipse.emfforms.spi.ide.view.segments.ToolingModeUtil;
94: import org.eclipse.jface.dialogs.MessageDialog;
95: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
96: import org.eclipse.jface.operation.IRunnableWithProgress;
97: import org.eclipse.jface.window.Window;
98: import org.eclipse.swt.SWT;
99: import org.eclipse.swt.widgets.Composite;
100: import org.eclipse.swt.widgets.Display;
101: import org.eclipse.swt.widgets.Shell;
102: import org.eclipse.ui.IEditorInput;
103: import org.eclipse.ui.IEditorPart;
104: import org.eclipse.ui.IEditorSite;
105: import org.eclipse.ui.IPartListener2;
106: import org.eclipse.ui.IPathEditorInput;
107: import org.eclipse.ui.IStorageEditorInput;
108: import org.eclipse.ui.IWorkbenchPage;
109: import org.eclipse.ui.IWorkbenchPartReference;
110: import org.eclipse.ui.PartInitException;
111: import org.eclipse.ui.PlatformUI;
112: import org.eclipse.ui.actions.WorkspaceModifyOperation;
113: import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
114: import org.eclipse.ui.dialogs.ISelectionStatusValidator;
115: import org.eclipse.ui.dialogs.ListSelectionDialog;
116: import org.eclipse.ui.ide.IGotoMarker;
117: import org.eclipse.ui.model.BaseWorkbenchContentProvider;
118: import org.eclipse.ui.model.WorkbenchLabelProvider;
119: import org.eclipse.ui.part.EditorPart;
120: import org.eclipse.ui.part.FileEditorInput;
121:
122: /**
123: * The IDE ViewModel EditorPart.
124: *
125: * @author Eugen Neufeld
126: *
127: */
128: public class ViewEditorPart extends EditorPart implements
129:         ViewModelEditorCallback, IEditingDomainProvider {
130:
131:         private URI inputUri;
132:         private Resource resource;
133:         private BasicCommandStack basicCommandStack;
134:         private Composite parent;
135:         private ECPSWTView render;
136:
137:         private boolean ecoreOutOfSync;
138:         private IPartListener2 partListener;
139:         private final ViewEditorPart instance;
140:         private AdapterFactoryEditingDomain editingDomain;
141:
142:         /** Default constructor for {@link ViewEditorPart}. */
143:         public ViewEditorPart() {
144:                 super();
145:                 instance = this;
146:         }
147:
148:         @Override
149:         public void doSave(IProgressMonitor monitor) {
150:                 // Do the work within an operation because this is a long running activity that modifies the workbench.
151:                 final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
152:                         @Override
153:                         public void execute(IProgressMonitor monitor) {
154:                                 try {
155:                                         resource.save(getSaveOptions());
156:                                 } catch (final IOException e) {
157:                                         Activator.getDefault().getLog()
158:                                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
159:                                 }
160:                         }
161:                 };
162:                 try {
163:                         new ProgressMonitorDialog(getSite().getShell()).run(true, false, operation);
164:                         basicCommandStack.saveIsDone();
165:                         firePropertyChange(IEditorPart.PROP_DIRTY);
166:                 } catch (final InvocationTargetException e) {
167:                         Activator.getDefault().getLog()
168:                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
169:                 } catch (final InterruptedException e) {
170:                         Activator.getDefault().getLog()
171:                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
172:                 }
173:
174:         }
175:
176:         /**
177:          * Get the save options used when saving the view model.
178:          *
179:          * @return The save options
180:          */
181:         protected Map<Object, Object> getSaveOptions() {
182:                 final Map<Object, Object> options = new HashMap<>();
183:                 options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
184:                 return options;
185:         }
186:
187:         @Override
188:         public void doSaveAs() {
189:                 // unsupported
190:         }
191:
192:         @Override
193:         public void init(IEditorSite site, IEditorInput input)
194:                 throws PartInitException {
195:                 super.setSite(site);
196:                 super.setInput(input);
197:                 super.setPartName(input.getName());
198:
199:                 try {
200:                         basicCommandStack = new BasicCommandStack();
201:                         editingDomain = new AdapterFactoryEditingDomain(
202:                                 new ComposedAdapterFactory(new AdapterFactory[] {
203:                                         new CustomReflectiveItemProviderAdapterFactory(),
204:                                         new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) }),
205:                                 basicCommandStack);
206:                         editingDomain.getResourceSet().getLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE,
207:                                 Boolean.TRUE);
208:                         loadView(false, false);
209:                 } // BEGIN SUPRESS CATCH EXCEPTION
210:                 catch (final Exception e) {// END SUPRESS CATCH EXCEPTION
211:                         /*
212:                          * ignore all exceptions during first loading of view. The view might actually be an outdated view, so the
213:                          * second call will migrate the view. if the migration step fails or is not possible at all, we will fail in
214:                          * the later call.
215:                          */
216:                 }
217:
218:                 try {
219:                         registerEcore(resource);
220:                         // BEGIN SUPRESS CATCH EXCEPTION
221:                 } catch (final Exception e) {
222:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
223:                         throw new PartInitException(
224:                                 MessageFormat.format(Messages.ViewEditorPart_ViewCannotBeDisplayed, e.getLocalizedMessage()), e);
225:                 } // END SUPRESS CATCH EXCEPTION
226:
227:                 try {
228:                         // reload view resource after EClass' package resource was loaded into the package registry
229:                         loadView(true, true);
230:                         checkLoadedView();
231:                         // BEGIN SUPRESS CATCH EXCEPTION
232:                 } catch (final Exception e) {
233:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
234:                         throw new PartInitException(
235:                                 MessageFormat.format(Messages.ViewEditorPart_ViewCannotBeDisplayed, e.getLocalizedMessage()), e);
236:                 } // END SUPRESS CATCH EXCEPTION
237:
238:                 basicCommandStack.addCommandStackListener(new CommandStackListener() {
239:                         @Override
240:                         public void commandStackChanged(final EventObject event) {
241:                                 parent.getDisplay().asyncExec(new Runnable() {
242:                                         @Override
243:                                         public void run() {
244:                                                 firePropertyChange(IEditorPart.PROP_DIRTY);
245:                                         }
246:                                 });
247:                         }
248:                 });
249:                 partListener = new ViewPartListener();
250:                 getSite().getPage().addPartListener(partListener);
251:
252:                 final IResourceChangeListener listener = new EditorResourceChangedListener();
253:                 ResourcesPlugin.getWorkspace().addResourceChangeListener(listener);
254:         }
255:
256:         /**
257:          * @since 1.20
258:          */
259:         @Override
260:         public EditingDomain getEditingDomain() {
261:                 return editingDomain;
262:         }
263:
264:         @Override
265:         public <T> T getAdapter(Class<T> adapter) {
266:                 if (adapter == ViewModelContext.class) {
267:                         return adapter.cast(render.getViewModelContext());
268:                 }
269:                 if (adapter == IGotoMarker.class) {
270:                         return adapter.cast(new GotoMarkerAdapter(render.getViewModelContext(), getEditingDomain()));
271:                 }
272:                 return super.getAdapter(adapter);
273:         }
274:
275:         /**
276:          * Checks whether the loaded VView is valid:
277:          * <ul>
278:          * <li>not null</li>
279:          * <li>the root EClass is set</li>
280:          * <li>the root EClass is resolved (no proxy)</li>
281:          * </ul>
282:          * If the VView is invalid, an Exception with a proper error description is thrown.
283:          *
284:          * @throws IllegalArgumentException If the VView is null or no root EClass was set.
285:          * @throws IllegalStateException If the VView's root EClass cannot be resolved.
286:          */
287:         private void checkLoadedView() throws IllegalArgumentException, IllegalStateException {
288:                 if (getView() == null) {
289:                         throw new IllegalArgumentException(Messages.ViewEditorPart_InvalidVView);
290:                 }
291:                 final EClass rootEClass = getView().getRootEClass();
292:                 if (rootEClass == null) {
293:                         throw new IllegalArgumentException(
294:                                 Messages.ViewEditorPart_invalidVView_noRootEClass);
295:                 }
296:                 if (rootEClass.eIsProxy()) {
297:                         final String proxyUri = EcoreUtil.getURI(rootEClass).toString();
298:                         final String packageNsUri = proxyUri.split("#")[0]; //$NON-NLS-1$
299:                         final String rootEClassName = proxyUri.split("#")[1].substring(2); //$NON-NLS-1$
300:                         final EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(packageNsUri);
301:                         if (ePackage == null || ePackage.eIsProxy()) {
302:                                 // the whole ecore is not present in the registry
303:                                 throw new IllegalStateException(MessageFormat.format(
304:                                         Messages.ViewEditorPart_invalidVView_rootEClassPackageNotResolved,
305:                                         rootEClassName, packageNsUri));
306:                         }
307:                         // The package is resolved but the Root EClass is not => Ecore was registered but misses the needed
308:                         // class.
309:                         throw new IllegalStateException(MessageFormat.format(
310:                                 Messages.ViewEditorPart_invalidVView_rootEClassNotInPackage,
311:                                 rootEClassName, ePackage.getName(), ePackage.getNsURI()));
312:                 }
313:         }
314:
315:         @Override
316:         public boolean isDirty() {
317:                 return basicCommandStack.isSaveNeeded();
318:         }
319:
320:         @Override
321:         public boolean isSaveAsAllowed() {
322:                 return false;
323:         }
324:
325:         /**
326:          * Loads the view model.
327:          *
328:          * @param migrate whether the view model should be migrated (if actually needed) <b>before</b> attempting to load it
329:          * @throws IOException if the view model resource failed to load
330:          * @throws PartInitException
331:          */
332:         private void loadView(boolean migrate, boolean resolve) throws IOException, PartInitException {
333:
334:                 if (inputUri == null) {
335:                         inputUri = getInputUri(getEditorInput())
336:                                 .orElseThrow(() -> new PartInitException("Invalid editor input.")); //$NON-NLS-1$
337:                 }
338:
339:                 final URI resourceURI = inputUri;
340:                 if (migrate) {
341:                         checkMigration(resourceURI);
342:                 }
343:                 editingDomain.getResourceSet().getResources().clear();
344:                 resource = editingDomain.getResourceSet().getResource(resourceURI, true);
345:                 if (resource.getContents().size() == 0 || !VView.class.isInstance(resource.getContents().get(0))) {
346:                         throw new PartInitException(Messages.ViewEditorPart_InvalidVView);
347:                 }
348:                 if (resolve) {
349:                         // resolve all proxies
350:                         final ResourceSet resourceSet = editingDomain.getResourceSet();
351:                         ResourceSetHelpers.resolveAllProxies(resourceSet);
352:                 }
353:         }
354:
355:         /**
356:          * Gets a uri from the given {@link IEditorInput}. If the editor input is a {@link IPathEditorInput} or a
357:          * {@link IStorageEditorInput} whose {@link IStorage} has a path, the uri is directly derived from the
358:          * input. In case of a {@link IStorageEditorInput} without a path, a temporary file is created which contains the
359:          * storage's contents.
360:          * In any other case, an empty Optional is returned.
361:          *
362:          * @param editorInput The editor's input
363:          * @return The File containing the editor inputs contents if possible, nothing otherwise
364:          */
365:         private Optional<URI> getInputUri(IEditorInput editorInput) {
366:                 if (isEditable(editorInput)) {
367:                         // Normal file that can be edited on the hard drive
368:                         return Optional.of(EditUIUtil.getURI(getEditorInput()));
369:                 } else if (editorInput instanceof IStorageEditorInput) {
370:                         try {
371:                                 final IStorage storage = IStorageEditorInput.class.cast(editorInput).getStorage();
372:                                 // Create a temporary file and copy the storage's content to it.
373:                                 final File tempFile = File.createTempFile("view-", ".tmp.view"); //$NON-NLS-1$ //$NON-NLS-2$
374:                                 tempFile.delete();
375:                                 tempFile.deleteOnExit();
376:                                 try (InputStream contents = storage.getContents()) {
377:                                         Files.copy(contents, tempFile.toPath());
378:                                         return Optional.of(URI.createFileURI(tempFile.getAbsolutePath()));
379:                                 }
380:                         } catch (final CoreException | IOException ex) {
381:                                 Activator.getDefault().getReportService().report(new AbstractReport(ex));
382:                                 return Optional.empty();
383:                         }
384:
385:                 }
386:                 return Optional.empty();
387:         }
388:
389:         /**
390:          * Returns whether the editor input allows editing of its contents.
391:          *
392:          * @param editorInput the editor's {@link IEditorInput}
393:          * @return <code>true</code> if the input source allows editing, <code>false</code> otherwise
394:          */
395:         private boolean isEditable(IEditorInput editorInput) {
396:                 // Only allow editing data if it can be persisted
397:                 return editorInput.getPersistable() != null;
398:         }
399:
400:         private void checkMigration(final URI resourceURI) {
401:                 final ViewModelMigrator migrator = ViewModelMigratorUtil.getViewModelMigrator();
402:                 if (migrator == null) {
403:                         return;
404:                 }
405:                 final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
406:                 final boolean needsMigration = checkIfMigrationIsNeeded(shell, resourceURI, migrator);
407:                 if (needsMigration) {
408:                         final boolean migrate = MessageDialog.openQuestion(shell, Messages.ViewEditorPart_MigrationTitle,
409:                                 Messages.ViewEditorPart_MigrationQuestion);
410:                         if (migrate) {
411:                                 final boolean migrateWorkspace = MessageDialog.openQuestion(shell,
412:                                         Messages.WorkspaceMigrationDialog_Title,
413:                                         Messages.WorkspaceMigrationDialog_Description);
414:                                 final List<URI> toMigrate = new ArrayList<URI>();
415:                                 final Set<URI> successfullyMigrated = new HashSet<>();
416:                                 if (migrateWorkspace) {
417:                                         for (final URI uri : getWorkspaceURIsToMigrate(resourceURI)) {
418:                                                 try {
419:                                                         final Resource workspaceResource = editingDomain.getResourceSet().getResource(uri, true);
420:                                                         registerEcore(workspaceResource);
421:                                                         toMigrate.add(uri);
422:                                                 }
423:                                                 // BEGIN SUPRESS CATCH EXCEPTION
424:                                                 catch (final Exception ex) {// END SUPRESS CATCH EXCEPTION
425:                                                         /*
426:                                                          * catch any exception because loading the workspace resource may also lead to exception
427:                                                          * like NoClassDefFound, IAE, etc. We want to continue in any case, in order to migrate as
428:                                                          * much as possible
429:                                                          */
430:                                                         Activator.getDefault().getLog()
431:                                                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(
432:                                                                         Messages.ViewEditorPart_WorkspaceMigrationError,
433:                                                                         uri.toString()), ex));
434:                                                 }
435:                                         }
436:                                 }
437:                                 toMigrate.add(resourceURI);
438:                                 final IRunnableWithProgress runnable = new IRunnableWithProgress() {
439:                                         @Override
440:                                         public void run(IProgressMonitor monitor)
441:                                                 throws InvocationTargetException {
442:                                                 try {
443:                                                         for (final URI uri : toMigrate) {
444:                                                                 migrator.performMigration(uri);
445:                                                                 successfullyMigrated.add(uri);
446:                                                         }
447:                                                 } catch (final ViewModelMigrationException ex) {
448:                                                         throw new InvocationTargetException(ex);
449:                                                 }
450:                                         }
451:                                 };
452:                                 try {
453:                                         new ProgressMonitorDialog(shell).run(true, false, runnable);
454:                                 } catch (final InvocationTargetException e) {
455:                                         MessageDialog.openError(
456:                                                 Display.getDefault().getActiveShell(), Messages.ViewEditorPart_MigrationErrorTitle,
457:                                                 Messages.ViewEditorPart_MigrationErrorText1 +
458:                                                         Messages.ViewEditorPart_MigrationErrorText2);
459:                                         Activator
460:                                                 .getDefault()
461:                                                 .getLog()
462:                                                 .log(
463:                                                         new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ViewEditorPart_MigrationErrorTitle,
464:                                                                 e));
465:                                 } catch (final InterruptedException e) {
466:                                         MessageDialog.openError(
467:                                                 Display.getDefault().getActiveShell(), Messages.ViewEditorPart_MigrationErrorTitle,
468:                                                 Messages.ViewEditorPart_MigrationErrorText1 +
469:                                                         Messages.ViewEditorPart_MigrationErrorText2);
470:                                         Activator
471:                                                 .getDefault()
472:                                                 .getLog()
473:                                                 .log(
474:                                                         new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ViewEditorPart_MigrationErrorTitle,
475:                                                                 e));
476:                                 }
477:
478:                                 // If a migration is necessary, only allow legacy dmr migration if the view model was migrated
479:                                 // successfully
480:                                 if (ToolingModeUtil.isSegmentToolingEnabled() && successfullyMigrated.contains(resourceURI)) {
481:                                         migrateLegacyDmrs(shell, resourceURI);
482:                                 }
483:                         }
484:
485:                         migrateTemplateModels(shell);
486:
487:                 } else if (ToolingModeUtil.isSegmentToolingEnabled()) {
488:                         migrateLegacyDmrs(shell, resourceURI);
489:                 }
490:         }
491:
492:         /**
493:          * Checks whether the current view model contains any legacy DMRs. If yes, ask the user whether (s)he wants to
494:          * migrate them to segment based DMRs and execute the migration if the user accepts.
495:          *
496:          * @param shell The shell to open UI dialogs on
497:          * @param resourceURI the resource URI of the view model to migrate
498:          */
499:         private void migrateLegacyDmrs(Shell shell, final URI resourceURI) {
500:                 final DmrToSegmentsMigrator migrator = getEditorSite().getService(DmrToSegmentsMigrator.class);
501:                 if (migrator.needsMigration(resourceURI)) {
502:                         final boolean migrate = MessageDialog.openQuestion(shell, Messages.ViewEditorPart_LegacyMigrationTitle,
503:                                 Messages.ViewEditorPart_LegacyMigrationQuestion);
504:                         if (migrate) {
505:                                 try {
506:                                         new ProgressMonitorDialog(shell).run(true, false, monitor -> {
507:                                                 try {
508:                                                         migrator.performMigration(resourceURI);
509:                                                 } catch (final DmrToSegmentsMigrationException ex) {
510:                                                         throw new InvocationTargetException(ex);
511:                                                 }
512:                                         });
513:                                 } catch (InvocationTargetException | InterruptedException ex) {
514:                                         MessageDialog.openError(
515:                                                 Display.getDefault().getActiveShell(), Messages.ViewEditorPart_LegacyMigrationErrorTitle,
516:                                                 Messages.ViewEditorPart_LegacyMigrationErrorText +
517:                                                         Messages.ViewEditorPart_MigrationErrorText2);
518:                                         Activator.getDefault().getLog().log(
519:                                                 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
520:                                                         Messages.ViewEditorPart_LegacyMigrationErrorTitle, ex));
521:                                 }
522:                         }
523:                 }
524:         }
525:
526:         /**
527:          * If there is a template migrator, prompt the user if (s)he wants to search the workspace for template models that
528:          * need migration. Afterwards, let the user chose which models to migrate and execute the migration.
529:          *
530:          * @param shell The {@link Shell} to create the dialogs for prompting the user on.
531:          */
532:         private void migrateTemplateModels(final Shell shell) {
533:                 final TemplateModelWorkspaceMigrator templateMigrator = TemplateModelMigratorUtil
534:                         .getTemplateModelWorkspaceMigrator();
535:                 if (templateMigrator == null) {
536:                         return;
537:                 }
538:                 // Prompt user to migrate template models in the workspace
539:                 final boolean migrateTemplates = MessageDialog.openQuestion(shell,
540:                         Messages.ViewEditorPart_TemplateMigrationTitle,
541:                         Messages.ViewEditorPart_TemplateMigrationDescription);
542:                 if (migrateTemplates) {
543:                         final List<URI> templateModelsToMigrate = getTemplateModelWorkspaceURIsToMigrate();
544:
545:                         final IRunnableWithProgress runnable = new IRunnableWithProgress() {
546:                                 @Override
547:                                 public void run(IProgressMonitor monitor)
548:                                         throws InvocationTargetException {
549:                                         try {
550:                                                 for (final URI uri : templateModelsToMigrate) {
551:                                                         templateMigrator.performMigration(uri);
552:                                                 }
553:                                         } catch (final TemplateModelMigrationException ex) {
554:                                                 throw new InvocationTargetException(ex);
555:                                         }
556:                                 }
557:                         };
558:
559:                         try {
560:                                 new ProgressMonitorDialog(shell).run(true, false, runnable);
561:                         } catch (final InvocationTargetException e) {
562:                                 MessageDialog.openError(
563:                                         Display.getDefault().getActiveShell(), Messages.ViewEditorPart_TemplateMigrationErrorTitle,
564:                                         Messages.ViewEditorPart_TemplateMigrationErrorMessage);
565:                                 Activator
566:                                         .getDefault().getLog().log(
567:                                                 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
568:                                                         Messages.ViewEditorPart_TemplateMigrationErrorTitle, e));
569:                         } catch (final InterruptedException e) {
570:                                 MessageDialog.openError(
571:                                         Display.getDefault().getActiveShell(), Messages.ViewEditorPart_TemplateMigrationErrorTitle,
572:                                         Messages.ViewEditorPart_TemplateMigrationErrorMessage);
573:                                 Activator.getDefault().getLog().log(
574:                                         new Status(IStatus.ERROR, Activator.PLUGIN_ID,
575:                                                 Messages.ViewEditorPart_TemplateMigrationErrorTitle, e));
576:                         }
577:
578:                 }
579:         }
580:
581:         /**
582:          * @param resourceURI the resource URI for which the migration dialog was opened. This URI will be removed from the
583:          * list of workspace URI in need of migration, which will be presented to the user.
584:          */
585:         private List<URI> getWorkspaceURIsToMigrate(URI resourceURI) {
586:                 final List<URI> uris = new ArrayList<URI>();
587:
588:                 final ViewModelWorkspaceMigrator workspaceMigrator = ViewModelMigratorUtil
589:                         .getViewModelWorkspaceMigrator();
590:                 if (workspaceMigrator == null) {
591:                         return uris;
592:                 }
593:                 try {
594:                         final ArrayList<URI> urIsToMigrate = workspaceMigrator.getURIsToMigrate();
595:
596:                         // Get the editors's resource uri as a uri with an absolute file path and remove it from the workspace URIs
597:                         // to migrate in order to avoid migrating it two times (this would throw an exception).
598:                         final IResource findMember = ResourcesPlugin.getWorkspace().getRoot()
599:                                 .findMember(resourceURI.toPlatformString(true));
600:                         final String osString = findMember.getLocation().toOSString();
601:                         urIsToMigrate.remove(URI.createFileURI(osString));
602:
603:                         if (urIsToMigrate.size() > 0) {
604:                                 final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
605:                                 final ListSelectionDialog migrationDialog = MigrationDialogHelper
606:                                         .getViewModelListMigrationDialog(shell,
607:                                                 urIsToMigrate);
608:
609:                                 if (migrationDialog.open() == Window.OK) {
610:                                         final Object[] selectedURIs = migrationDialog.getResult();
611:                                         if (selectedURIs != null) {
612:                                                 for (final Object selectedUri : selectedURIs) {
613:                                                         uris.add((URI) selectedUri);
614:                                                 }
615:                                         }
616:                                 }
617:                         }
618:                 } catch (final CoreException ex) {
619:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));
620:                 }
621:                 return uris;
622:         }
623:
624:         private List<URI> getTemplateModelWorkspaceURIsToMigrate() {
625:                 final List<URI> uris = new LinkedList<URI>();
626:
627:                 final TemplateModelWorkspaceMigrator workspaceMigrator = TemplateModelMigratorUtil
628:                         .getTemplateModelWorkspaceMigrator();
629:                 if (workspaceMigrator == null) {
630:                         return uris;
631:                 }
632:                 try {
633:                         final List<URI> urIsToMigrate = workspaceMigrator.getURIsToMigrate();
634:
635:                         if (urIsToMigrate.size() > 0) {
636:                                 final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
637:                                 final ListSelectionDialog migrationDialog = MigrationDialogHelper
638:                                         .getTemplateModelListMigrationDialog(shell, urIsToMigrate);
639:
640:                                 if (migrationDialog.open() == Window.OK) {
641:                                         final Object[] selectedURIs = migrationDialog.getResult();
642:                                         if (selectedURIs != null) {
643:                                                 for (final Object selectedUri : selectedURIs) {
644:                                                         uris.add((URI) selectedUri);
645:                                                 }
646:                                         }
647:                                 }
648:                         }
649:                 } catch (final CoreException ex) {
650:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));
651:                 }
652:                 return uris;
653:         }
654:
655:         private boolean checkIfMigrationIsNeeded(Shell shell, final URI resourceURI, final ViewModelMigrator migrator) {
656:                 final CheckMigrationRunnable runnable = new CheckMigrationRunnable(migrator, resourceURI);
657:                 try {
658:                         new ProgressMonitorDialog(shell).run(true, false, runnable);
659:                 } catch (final InvocationTargetException ex) {
660:                         Activator.getDefault().getLog()
661:                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ViewEditorPart_MigrationErrorTitle, ex));
662:                 } catch (final InterruptedException ex) {
663:                         Activator.getDefault().getLog()
664:                                 .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ViewEditorPart_MigrationErrorTitle, ex));
665:                 }
666:                 return runnable.getResult();
667:         }
668:
669:         @Override
670:         public void createPartControl(Composite parent) {
671:                 this.parent = parent;
672:                 parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
673:
674:                 final VView view = getView();
675:
676:                 Activator.getViewModelRegistry().registerViewModel(view, resource.getURI().toString());
677:                 try {
678:                         Activator.getViewModelRegistry().registerViewModelEditor(view, this);
679:                 } catch (final IOException e) {
680:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
681:                 }
682:                 if (view.getRootEClass() != null) {
683:                         if (view.getRootEClass().eResource() != null) {
684:                                 Activator.getViewModelRegistry().register(view.getRootEClass().eResource().getURI().toString(),
685:                                         view);
686:                         } else {
687:                                 Activator
688:                                         .getDefault()
689:                                         .getLog()
690:                                         .log(
691:                                                 new Status(IStatus.WARNING, Activator.PLUGIN_ID,
692:                                                         "The Root EClass of the view cannot be resolved." + view.getRootEClass())); //$NON-NLS-1$
693:                         }
694:                 }
695:                 showView();
696:         }
697:
698:         private void registerEcore(Resource viewResource) throws IOException {
699:                 for (final String ecorePath : ViewModelHelper.getEcorePaths(viewResource)) {
700:                         if (ecorePath == null) {
701:                                 return;
702:                         }
703:                         EcoreHelper.registerEcore(ecorePath);
704:                 }
705:         }
706:
707:         private void saveChangedView(VView view) {
708:                 try {
709:                         view.eResource().save(getSaveOptions());
710:                 } catch (final IOException e) {
711:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
712:                 }
713:         }
714:
715:         private String selectEcoreFromWorkspace() {
716:                 final ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(Display.getDefault()
717:                         .getActiveShell(), new WorkbenchLabelProvider(), new BaseWorkbenchContentProvider());
718:                 dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
719:                 dialog.setAllowMultiple(false);
720:                 dialog.setValidator(new ISelectionStatusValidator() {
721:
722:                         @Override
723:                         public IStatus validate(Object[] selection) {
724:                                 if (selection.length == 1) {
725:                                         if (selection[0] instanceof IFile) {
726:                                                 final IFile file = (IFile) selection[0];
727:                                                 if (file.getType() == IResource.FILE) {
728:                                                         return new Status(IStatus.OK, Activator.PLUGIN_ID, IStatus.OK, null, null);
729:                                                 }
730:                                         }
731:                                 }
732:                                 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR,
733:                                         Messages.ViewEditorPart_EcoreSelectionValidation,
734:                                         null);
735:                         }
736:                 });
737:                 dialog.setTitle(Messages.ViewEditorPart_EcoreSelectionTitle);
738:
739:                 if (dialog.open() == Window.OK) {
740:
741:                         final IFile file = (IFile) dialog.getFirstResult();
742:                         return file.getFullPath()
743:                                 .toString();
744:                 }
745:                 return null;
746:         }
747:
748:         private void showView() {
749:                 final VView view = getView();
750:
751:                 if (XMLResource.class.isInstance(view.eResource())
752:                         && !XMLResource.class.cast(view.eResource()).getEObjectToExtensionMap().isEmpty()) {
753:                         // we are showing a view which wasn't fully loaded
754:                         MessageDialog
755:                                 .openWarning(
756:                                         parent.getShell(),
757:                                         Messages.ViewEditorPart_LoadedPartlyTitle,
758:                                         Messages.ViewEditorPart_LoadedPartlyDescription);
759:                 }
760:
761:                 try {
762:                         final Map<String, Object> contextValues = Collections.singletonMap(
763:                                 IEclipseContext.class.getName(),
764:                                 getSite().getService(IEclipseContext.class));
765:                         final ViewModelContext viewModelContext = ViewModelContextFactory.INSTANCE
766:                                 .createViewModelContext(ViewProviderHelper.getView(view, null), view,
767:                                         provide(new DefaultReferenceService(), new EMFDeleteServiceImpl()),
768:                                         contextValues);
769:
770:                         if (!isEditable(getEditorInput())) {
771:                                 viewModelContext.getViewModel().setReadonly(true);
772:                         }
773:
774:                         viewModelContext.putContextValue("enableMultiEdit", Boolean.TRUE); //$NON-NLS-1$
775:                         render = ECPSWTViewRenderer.INSTANCE.render(parent, viewModelContext);
776:                         getSite().setSelectionProvider(
777:                                 viewModelContext.getService(ECPSelectionProviderService.class).getSelectionProvider());
778:                 } catch (final ECPRendererException ex) {
779:                         Activator.getDefault().getReportService().report(
780:                                 new StatusReport(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex)));
781:                 }
782:         }
783:
784:         @Override
785:         public void setFocus() {
786:         }
787:
788:         /**
789:          * {@inheritDoc}
790:          *
791:          * @see org.eclipse.emf.ecp.ide.view.service.ViewModelEditorCallback#reloadViewModel()
792:          */
793:         @Override
794:         public void reloadViewModel() {
795:                 Display.getDefault().asyncExec(new ReloadViewModelRunnable());
796:         }
797:
798:         @Override
799:         public void dispose() {
800:                 final VView view = getView();
801:                 if (view != null) {
802:                         Activator.getViewModelRegistry().unregisterViewModelEditor(view, this);
803:                 }
804:                 if (partListener != null) {
805:                         getSite().getPage().removePartListener(partListener);
806:                 }
807:                 super.dispose();
808:         }
809:
810:         /**
811:          * @return the VView object
812:          */
813:         public VView getView() {
814:                 if (resource == null || resource.getContents().isEmpty()) {
815:                         return null;
816:                 }
817:                 final EObject eObject = resource.getContents().get(0);
818:                 if (!VView.class.isInstance(eObject)) {
819:                         return null;
820:                 }
821:                 return (VView) eObject;
822:         }
823:
824:         /**
825:          * Runnable to check if a migration is needed.
826:          *
827:          * @author Johannes Faltermeier
828:          *
829:          */
830:         private static final class CheckMigrationRunnable implements IRunnableWithProgress {
831:                 private final ViewModelMigrator migrator;
832:                 private final URI resourceURI;
833:                 private boolean needsMigration;
834:
835:                 /**
836:                  * Default constructor.
837:                  *
838:                  * @param migrator the migrator
839:                  * @param resourceURI the resource uri to check
840:                  */
841:                 CheckMigrationRunnable(ViewModelMigrator migrator, URI resourceURI) {
842:                         this.migrator = migrator;
843:                         this.resourceURI = resourceURI;
844:                 }
845:
846:                 @Override
847:                 public void run(IProgressMonitor monitor)
848:                         throws InvocationTargetException {
849:                         needsMigration = !migrator.checkMigration(resourceURI);
850:                 }
851:
852:                 /**
853:                  * Returns the result of the migration check.
854:                  *
855:                  * @return <code>true</code> if migration is needed, <code>false</code> otherwise
856:                  */
857:                 public boolean getResult() {
858:                         return needsMigration;
859:                 }
860:         }
861:
862:         /**
863:          * @author Jonas
864:          *
865:          */
866:         private final class ReloadViewModelRunnable implements Runnable {
867:                 @Override
868:                 public void run() {
869:                         if (parent == null || parent.isDisposed()) {
870:                                 final IWorkbenchPage page = instance.getSite().getPage();
871:                                 page.closeEditor(instance, true);
872:                                 return;
873:                         }
874:                         if (render != null) {
875:                                 render.dispose();
876:                                 render.getSWTControl().dispose();
877:                         }
878:
879:                         for (final String ecorePath : getView().getEcorePaths()) {
880:                                 if (ecorePath != null) {
881:                                         try {
882:                                                 EcoreHelper.registerEcore(ecorePath);
883:                                         } catch (final IOException e) {
884:                                                 Activator.getDefault().getLog()
885:                                                         .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
886:                                         }
887:                                 }
888:                         }
889:
890:                         // reload view resource after EClass' package resource was loaded into the package registry
891:                         try {
892:                                 loadView(true, true);
893:                         } catch (final IOException e) {
894:                                 Activator.getDefault().getLog()
895:                                         .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
896:                         } catch (final PartInitException e) {
897:                                 Activator.getDefault().getLog()
898:                                         .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
899:                                 return;
900:                         }
901:                         final VView view = getView();
902:
903:                         try {
904:                                 Activator.getViewModelRegistry().registerViewModelEditor(view, instance);
905:                         } catch (final IOException e) {
906:                                 Activator.getDefault().getLog()
907:                                         .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
908:                         }
909:
910:                         if (view.getRootEClass() != null) {
911:                                 if (view.getRootEClass().eResource() != null) {
912:                                         Activator.getViewModelRegistry().register(
913:                                                 view.getRootEClass().eResource().getURI().toString(),
914:                                                 view);
915:                                 } else {
916:                                         Activator
917:                                                 .getDefault()
918:                                                 .getLog()
919:                                                 .log(
920:                                                         new Status(IStatus.WARNING, Activator.PLUGIN_ID,
921:                                                                 "The Root EClass of the view cannot be resolved." + view.getRootEClass())); //$NON-NLS-1$
922:                                 }
923:                         }
924:                         showView();
925:                         parent.layout(true);
926:                 }
927:         }
928:
929:         /**
930:          *
931:          * */
932:         private class ViewPartListener implements IPartListener2 {
933:                 @Override
934:                 public void partActivated(IWorkbenchPartReference partRef) {
935:                         if (instance.equals(partRef.getPart(true))) {
936:
937:                                 final VView view = getView();
938:
939:                                 // TODO: remove? Should probably handled manually by the user instead.
940:                                 if ((view.getEcorePaths().isEmpty()
941:                                         || ResourcesPlugin.getWorkspace().getRoot().findMember(view.getEcorePaths().get(0)) == null)
942:                                         && view.getRootEClass() != null && view.getRootEClass().eIsProxy()) {
943:
944:                                         final String selectedECorePath = selectEcoreFromWorkspace();
945:                                         if (selectedECorePath != null) {
946:                                                 view.getEcorePaths().add(selectedECorePath);
947:                                                 saveChangedView(view);
948:                                                 reloadViewModel();
949:                                         }
950:                                 }
951:                                 if (ecoreOutOfSync) {
952:                                         PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
953:                                                 @Override
954:                                                 public void run() {
955:                                                         final Shell activeShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
956:                                                                 .getShell();
957:                                                         final MessageDialog dialog = new MessageDialog(
958:                                                                 activeShell,
959:                                                                 Messages.ViewEditorPart_Warning,
960:                                                                 null,
961:                                                                 Messages.ViewEditorPart_EditorViewChanged,
962:                                                                 MessageDialog.WARNING,
963:                                                                 new String[] { Messages.ViewEditorPart_Yes, Messages.ViewEditorPart_No },
964:                                                                 0);
965:                                                         final int result = dialog.open();
966:•                                                        if (result == 0) {
967:                                                                 Activator.getViewModelRegistry().unregisterViewModelEditor(getView(), instance);
968:                                                                 Activator.getViewModelRegistry().unregister(
969:                                                                         getView().getRootEClass().eResource().getURI().toString(),
970:                                                                         getView());
971:                                                                 reloadViewModel();
972:                                                         }
973:                                                         ecoreOutOfSync = false;
974:                                                 }
975:                                         });
976:                                 }
977:                         }
978:                 }
979:
980:                 @Override
981:                 public void partBroughtToTop(IWorkbenchPartReference partRef) {
982:                 }
983:
984:                 @Override
985:                 public void partClosed(IWorkbenchPartReference partRef) {
986:                 }
987:
988:                 @Override
989:                 public void partDeactivated(IWorkbenchPartReference partRef) {
990:                 }
991:
992:                 @Override
993:                 public void partOpened(IWorkbenchPartReference partRef) {
994:                 }
995:
996:                 @Override
997:                 public void partHidden(IWorkbenchPartReference partRef) {
998:                 }
999:
1000:                 @Override
1001:                 public void partVisible(IWorkbenchPartReference partRef) {
1002:                 }
1003:
1004:                 @Override
1005:                 public void partInputChanged(IWorkbenchPartReference partRef) {
1006:                 }
1007:         }
1008:
1009:         /**
1010:          * {@inheritDoc}
1011:          *
1012:          * @see org.eclipse.emf.ecp.ide.view.service.ViewModelEditorCallback#signalEcoreOutOfSync()
1013:          */
1014:         @Override
1015:         public void signalEcoreOutOfSync() {
1016:                 ecoreOutOfSync = true;
1017:
1018:         }
1019:
1020:         /** Listens for changes in the editor's resource. */
1021:         private class EditorResourceChangedListener implements IResourceChangeListener {
1022:
1023:                 /**
1024:                  * {@inheritDoc}
1025:                  *
1026:                  * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
1027:                  */
1028:                 @Override
1029:                 public void resourceChanged(IResourceChangeEvent event) {
1030:                         final IResourceDelta delta = event.getDelta();
1031:                         final IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
1032:                                 @Override
1033:                                 public boolean visit(IResourceDelta delta) {
1034:                                         if (delta.getKind() == IResourceDelta.REMOVED) {
1035:                                                 final FileEditorInput fei = (FileEditorInput) instance.getEditorInput();
1036:                                                 if (delta.getFullPath().equals(fei.getFile().getFullPath())) {
1037:                                                         final IWorkbenchPage page = instance.getSite().getPage();
1038:                                                         Display.getDefault().asyncExec(new Runnable() {
1039:                                                                 @Override
1040:                                                                 public void run() {
1041:                                                                         if (page != null) {
1042:                                                                                 page.closeEditor(instance, false);
1043:                                                                         }
1044:                                                                 }
1045:                                                         });
1046:                                                         return false;
1047:                                                 }
1048:                                         }
1049:                                         return true;
1050:                                 }
1051:                         };
1052:                         try {
1053:                                 if (delta == null) {
1054:                                         return;
1055:                                 }
1056:                                 delta.accept(visitor);
1057:                         } catch (final CoreException ex) {
1058:                         }
1059:                 }
1060:         }
1061: }