Skip to content

Package: TemplateModelEditorPart$DmrSelectorPreReplaceProcessor

TemplateModelEditorPart$DmrSelectorPreReplaceProcessor

nameinstructionbranchcomplexitylinemethod
TemplateModelEditorPart.DmrSelectorPreReplaceProcessor(LegacyDmrToRootEClass)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
process(VDomainModelReference, VDomainModelReference)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 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: * Lucas Koehler - add migration of view ecore namespace URI
14: * Lucas Koehler - add support to open file from history revision (bug 541191)
15: ******************************************************************************/
16: package org.eclipse.emf.ecp.view.template.tooling.editor;
17:
18: import java.io.File;
19: import java.io.IOException;
20: import java.io.InputStream;
21: import java.lang.reflect.InvocationTargetException;
22: import java.nio.file.Files;
23: import java.util.Collections;
24: import java.util.LinkedList;
25: import java.util.List;
26: import java.util.Optional;
27:
28: import org.eclipse.core.resources.IStorage;
29: import org.eclipse.core.runtime.CoreException;
30: import org.eclipse.core.runtime.IPath;
31: import org.eclipse.core.runtime.IProgressMonitor;
32: import org.eclipse.core.runtime.IStatus;
33: import org.eclipse.core.runtime.Path;
34: import org.eclipse.core.runtime.Status;
35: import org.eclipse.emf.common.util.EList;
36: import org.eclipse.emf.common.util.URI;
37: import org.eclipse.emf.ecore.EClass;
38: import org.eclipse.emf.ecore.EObject;
39: import org.eclipse.emf.ecore.resource.Resource;
40: import org.eclipse.emf.ecore.resource.ResourceSet;
41: import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
42: import org.eclipse.emf.ecore.xmi.XMLResource;
43: import org.eclipse.emf.ecp.ide.spi.util.EcoreHelper;
44: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelMigrationException;
45: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelMigratorUtil;
46: import org.eclipse.emf.ecp.spi.view.migrator.TemplateModelWorkspaceMigrator;
47: import org.eclipse.emf.ecp.spi.view.migrator.ViewNsMigrationUtil;
48: import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
49: import org.eclipse.emf.ecp.view.template.internal.tooling.Activator;
50: import org.eclipse.emf.ecp.view.template.internal.tooling.Messages;
51: import org.eclipse.emf.ecp.view.template.internal.tooling.util.MigrationDialogHelper;
52: import org.eclipse.emf.ecp.view.template.model.VTViewTemplate;
53: import org.eclipse.emf.ecp.view.template.selector.domainmodelreference.model.VTDomainModelReferenceSelector;
54: import org.eclipse.emfforms.spi.core.services.segments.LegacyDmrToRootEClass;
55: import org.eclipse.emfforms.spi.editor.GenericEditor;
56: import org.eclipse.emfforms.spi.editor.helpers.ResourceSetHelpers;
57: import org.eclipse.emfforms.spi.ide.view.segments.DmrToSegmentsMigrationException;
58: import org.eclipse.emfforms.spi.ide.view.segments.DmrToSegmentsMigrator;
59: import org.eclipse.emfforms.spi.ide.view.segments.DmrToSegmentsMigrator.PreReplaceProcessor;
60: import org.eclipse.emfforms.spi.ide.view.segments.ToolingModeUtil;
61: import org.eclipse.emfforms.spi.swt.treemasterdetail.TreeMasterDetailComposite;
62: import org.eclipse.emfforms.spi.swt.treemasterdetail.util.CreateElementCallback;
63: import org.eclipse.emfforms.spi.swt.treemasterdetail.util.RootObject;
64: import org.eclipse.jface.dialogs.MessageDialog;
65: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
66: import org.eclipse.jface.operation.IRunnableWithProgress;
67: import org.eclipse.jface.viewers.StructuredSelection;
68: import org.eclipse.jface.window.Window;
69: import org.eclipse.swt.widgets.Composite;
70: import org.eclipse.swt.widgets.Display;
71: import org.eclipse.swt.widgets.Shell;
72: import org.eclipse.ui.IEditorInput;
73: import org.eclipse.ui.IEditorSite;
74: import org.eclipse.ui.IFileEditorInput;
75: import org.eclipse.ui.IPathEditorInput;
76: import org.eclipse.ui.IStorageEditorInput;
77: import org.eclipse.ui.PartInitException;
78: import org.eclipse.ui.PlatformUI;
79: import org.eclipse.ui.dialogs.ListSelectionDialog;
80:
81: /**
82: * EditorPart for the Template Model Editor.
83: *
84: * @author Eugen Neufeld
85: *
86: */
87: public class TemplateModelEditorPart extends GenericEditor {
88:
89:         private VTViewTemplate template;
90:         private TreeMasterDetailComposite treeMasterDetail;
91:         private File inputFile;
92:
93:         @Override
94:         public void init(IEditorSite site, IEditorInput input) throws PartInitException {
95:                 super.setSite(site);
96:                 final Optional<File> inputFileOptional = getInputFile(input);
97:                 if (!inputFileOptional.isPresent()) {
98:                         throw new PartInitException(Messages.TemplateModelEditorPart_invalidEditorInput);
99:                 }
100:
101:                 inputFile = inputFileOptional.get();
102:                 try {
103:                         // Register the referenced ecores before the migrations because the legacy dmr to segment dmr migration only
104:                         // works if all referenced ecores are registered
105:                         registerReferencedEcores(URI.createFileURI(inputFile.getAbsolutePath()));
106:
107:                         if (!ViewNsMigrationUtil.checkMigration(inputFile)) {
108:                                 final boolean migrate = MessageDialog.openQuestion(site.getShell(),
109:                                         Messages.TemplateModelEditorPart_MigrationQuestion,
110:                                         Messages.TemplateModelEditorPart_MigrationDescription);
111:                                 if (migrate) {
112:                                         ViewNsMigrationUtil.migrateViewEcoreNsUri(inputFile);
113:                                         migrateWorkspaceModels(site.getShell());
114:                                         if (ToolingModeUtil.isSegmentToolingEnabled()) {
115:                                                 migrateLegacyDmrs(site.getShell(), Path.fromOSString(inputFile.getAbsolutePath()));
116:                                         }
117:                                 }
118:                         } else if (ToolingModeUtil.isSegmentToolingEnabled()) {
119:                                 migrateLegacyDmrs(site.getShell(), Path.fromOSString(inputFile.getAbsolutePath()));
120:                         }
121:                 } catch (final IOException e) {
122:                         Activator.log(e);
123:                         throw new PartInitException(Messages.TemplateModelEditorPart_initError, e);
124:                 }
125:
126:                 // super.init is called at the end because we need to check for necessary migrations and register referenced
127:                 // ecores before the resource is finally loaded in GenericEditor#init
128:                 super.init(site, input);
129:                 super.setPartName(input.getName());
130:         }
131:
132:         /**
133:          * Gets a file from the given {@link IEditorInput}. If the editor input is a {@link IPathEditorInput} or a
134:          * {@link IStorageEditorInput} whose {@link IStorage} has a path, the {@link File} is directly derived from the
135:          * path. In case of a {@link IStorageEditorInput} without a path, a temporary file is created which contains the
136:          * storage's contents.
137:          * In any other case, an empty Optional is returned.
138:          *
139:          * @param editorInput The editor's input
140:          * @return The File containing the editor inputs contents if possible, nothing otherwise
141:          */
142:         private Optional<File> getInputFile(IEditorInput editorInput) {
143:                 if (isEditable(editorInput)) {
144:                         // Normal file that can be edited on the hard drive
145:                         if (editorInput instanceof IPathEditorInput) {
146:                                 return Optional.of(IPathEditorInput.class.cast(editorInput).getPath().toFile());
147:                         }
148:                         if (editorInput instanceof IFileEditorInput) {
149:                                 return Optional.of(IFileEditorInput.class.cast(editorInput).getFile().getFullPath().toFile());
150:                         }
151:                 } else if (editorInput instanceof IStorageEditorInput) {
152:                         try {
153:                                 final IStorage storage = IStorageEditorInput.class.cast(editorInput).getStorage();
154:                                 // Create a temporary file and copy the storage's content to it.
155:                                 final File tempFile = File.createTempFile("template-", ".tmp.template"); //$NON-NLS-1$ //$NON-NLS-2$
156:                                 tempFile.delete();
157:                                 tempFile.deleteOnExit();
158:                                 try (InputStream contents = storage.getContents()) {
159:                                         Files.copy(contents, tempFile.toPath());
160:                                         return Optional.of(tempFile);
161:                                 }
162:                         } catch (final CoreException | IOException ex) {
163:                                 Activator.log(ex);
164:                                 return Optional.empty();
165:                         }
166:
167:                 }
168:                 return Optional.empty();
169:         }
170:
171:         private void registerReferencedEcores(URI resourceUri) throws IOException, PartInitException {
172:                 final ResourceSet resourceSet = new ResourceSetImpl();
173:                 final Resource resource = resourceSet.createResource(resourceUri);
174:                 resource.load(Collections.singletonMap(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE));
175:                 final EList<EObject> resourceContents = resource.getContents();
176:                 if (resourceContents.size() > 0 && VTViewTemplate.class.isInstance(resourceContents.get(0))) {
177:                         final VTViewTemplate template = (VTViewTemplate) resourceContents.get(0);
178:                         for (final String ecorePath : template.getReferencedEcores()) {
179:                                 EcoreHelper.registerEcore(ecorePath);
180:                         }
181:                 } else {
182:                         throw new PartInitException(Messages.TemplateModelEditorPart_initError);
183:                 }
184:         }
185:
186:         @Override
187:         protected ResourceSet loadResource(IEditorInput editorInput) throws PartInitException {
188:                 ResourceSet resourceSet = ResourceSetHelpers.createResourceSet(getCommandStack());
189:                 // Load resource from input file that we determined or created during initialization
190:                 final URI resourceURI = URI.createFileURI(inputFile.getAbsolutePath());
191:
192:                 try {
193:                         resourceSet = ResourceSetHelpers.loadResourceWithProxies(resourceURI, resourceSet,
194:                                 getResourceLoadOptions());
195:                         verifyEditorResource(resourceURI, resourceSet);
196:                         return resourceSet;
197:                         // CHECKSTYLE.OFF: IllegalCatch
198:                 } catch (final Exception e) {
199:                         // CHECKSTYLE.ON: IllegalCatch
200:                         throw new PartInitException(e.getLocalizedMessage(), e);
201:                 }
202:         }
203:
204:         @Override
205:         protected void refreshTreeAfterResourceChange() {
206:                 // Need to reset the resource after a resource change because the resource is unloaded and reloaded and we wrap
207:                 // the template model in our own root object. Without explicitly resetting the input again, all objects in the
208:                 // editor are proxies.
209:                 getRootView().setInput(modifyEditorInput(getResourceSet()));
210:         }
211:
212:         @Override
213:         protected Object modifyEditorInput(ResourceSet resourceSet) {
214:                 /* this access is save, otherwise we would have thrown a part init exception in init */
215:                 template = VTViewTemplate.class.cast(resourceSet.getResources().get(0).getContents().get(0));
216:                 return new RootObject(template);
217:         }
218:
219:         @Override
220:         protected TreeMasterDetailComposite createTreeMasterDetail(Composite composite, Object editorInput,
221:                 CreateElementCallback createElementCallback) {
222:                 treeMasterDetail = super.createTreeMasterDetail(composite, editorInput, createElementCallback);
223:                 return treeMasterDetail;
224:         }
225:
226:         @Override
227:         public void dispose() {
228:                 if (template != null) {
229:                         for (final String ecorePath : template.getReferencedEcores()) {
230:                                 EcoreHelper.unregisterEcore(ecorePath);
231:                         }
232:                 }
233:                 super.dispose();
234:         }
235:
236:         /**
237:          * Gives access to the template model which is the input of the editor.
238:          *
239:          * @return the {@link VTViewTemplate}
240:          */
241:         public VTViewTemplate getTemplate() {
242:                 return template;
243:         }
244:
245:         /**
246:          * The given element will be revealed in the tree of the editor.
247:          *
248:          * @param objectToReveal the object to reveal
249:          */
250:         @Override
251:         public void reveal(EObject objectToReveal) {
252:                 treeMasterDetail.getSelectionProvider().refresh();
253:                 treeMasterDetail.getSelectionProvider().reveal(objectToReveal);
254:                 treeMasterDetail.setSelection(new StructuredSelection(objectToReveal));
255:         }
256:
257:         /**
258:          * Checks whether the current view model contains any legacy DMRs. If yes, ask the user whether (s)he wants to
259:          * migrate them to segment based DMRs and execute the migration if the user accepts.
260:          *
261:          * @param shell The shell to open UI dialogs on
262:          * @param resourcePath the resource path of the template model to migrate
263:          */
264:         private void migrateLegacyDmrs(Shell shell, final IPath resourcePath) {
265:                 final DmrToSegmentsMigrator migrator = getEditorSite().getService(DmrToSegmentsMigrator.class);
266:                 final URI resourceURI = URI.createFileURI(resourcePath.toFile().getAbsolutePath());
267:                 if (migrator.needsMigration(resourceURI)) {
268:                         final boolean migrate = MessageDialog.openQuestion(shell,
269:                                 Messages.TemplateModelEditorPart_LegacyMigrationQuestionTitle,
270:                                 Messages.TemplateModelEditorPart_LegacyMigrationQuestionMessage);
271:                         if (migrate) {
272:                                 try {
273:                                         new ProgressMonitorDialog(shell).run(true, false, monitor -> {
274:                                                 try {
275:                                                         final LegacyDmrToRootEClass dmrToRootEClass = getEditorSite()
276:                                                                 .getService(LegacyDmrToRootEClass.class);
277:                                                         migrator.performMigration(resourceURI, new DmrSelectorPreReplaceProcessor(dmrToRootEClass));
278:                                                 } catch (final DmrToSegmentsMigrationException ex) {
279:                                                         throw new InvocationTargetException(ex);
280:                                                 }
281:                                         });
282:                                 } catch (InvocationTargetException | InterruptedException ex) {
283:                                         MessageDialog.openError(
284:                                                 Display.getDefault().getActiveShell(),
285:                                                 Messages.TemplateModelEditorPart_LegacyMigrationErrorTitle,
286:                                                 Messages.TemplateModelEditorPart_LegacyMigrationErrorMessage);
287:                                         Activator.getDefault().getLog().log(
288:                                                 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
289:                                                         Messages.TemplateModelEditorPart_LegacyMigrationErrorTitle, ex));
290:                                 }
291:                         }
292:                 }
293:         }
294:
295:         /**
296:          * If there is a template migrator, prompt the user if (s)he wants to search the workspace for template models that
297:          * need migration. Afterwards, let the user chose which models to migrate and execute the migration.
298:          * <p>
299:          *
300:          * @param shell The {@link Shell} to create the dialogs for prompting the user on.
301:          */
302:         // TODO This is (nearly) duplicated from the ViewEditor Part and should be refactored into a single source
303:         private void migrateWorkspaceModels(final Shell shell) {
304:                 final TemplateModelWorkspaceMigrator templateMigrator = TemplateModelMigratorUtil
305:                         .getTemplateModelWorkspaceMigrator();
306:                 if (templateMigrator == null) {
307:                         return;
308:                 }
309:                 // Prompt user to migrate template models in the workspace
310:                 final boolean migrateTemplates = MessageDialog.openQuestion(shell,
311:                         Messages.TemplateModelEditorPart_TemplateMigrationTitle,
312:                         Messages.TemplateModelEditorPart_TemplateMigrationDescription);
313:                 if (migrateTemplates) {
314:                         final List<URI> templateModelsToMigrate = getTemplateModelWorkspaceURIsToMigrate();
315:
316:                         final IRunnableWithProgress runnable = new IRunnableWithProgress() {
317:                                 @Override
318:                                 public void run(IProgressMonitor monitor)
319:                                         throws InvocationTargetException {
320:                                         try {
321:                                                 for (final URI uri : templateModelsToMigrate) {
322:                                                         templateMigrator.performMigration(uri);
323:                                                 }
324:                                         } catch (final TemplateModelMigrationException ex) {
325:                                                 throw new InvocationTargetException(ex);
326:                                         }
327:                                 }
328:                         };
329:
330:                         try {
331:                                 new ProgressMonitorDialog(shell).run(true, false, runnable);
332:                         } catch (final InvocationTargetException e) {
333:                                 MessageDialog.openError(
334:                                         Display.getDefault().getActiveShell(), Messages.TemplateModelEditorPart_TemplateMigrationErrorTitle,
335:                                         Messages.TemplateModelEditorPart_TemplateMigrationErrorMessage);
336:                                 Activator
337:                                         .getDefault().getLog().log(
338:                                                 new Status(IStatus.ERROR, Activator.PLUGIN_ID,
339:                                                         Messages.TemplateModelEditorPart_TemplateMigrationErrorTitle, e));
340:                         } catch (final InterruptedException e) {
341:                                 MessageDialog.openError(
342:                                         Display.getDefault().getActiveShell(), Messages.TemplateModelEditorPart_TemplateMigrationErrorTitle,
343:                                         Messages.TemplateModelEditorPart_TemplateMigrationErrorMessage);
344:                                 Activator.getDefault().getLog().log(
345:                                         new Status(IStatus.ERROR, Activator.PLUGIN_ID,
346:                                                 Messages.TemplateModelEditorPart_TemplateMigrationErrorTitle, e));
347:                         }
348:
349:                 }
350:         }
351:
352:         private List<URI> getTemplateModelWorkspaceURIsToMigrate() {
353:                 final List<URI> uris = new LinkedList<URI>();
354:
355:                 final TemplateModelWorkspaceMigrator workspaceMigrator = TemplateModelMigratorUtil
356:                         .getTemplateModelWorkspaceMigrator();
357:                 if (workspaceMigrator == null) {
358:                         return uris;
359:                 }
360:                 try {
361:                         final List<URI> urIsToMigrate = workspaceMigrator.getURIsToMigrate();
362:
363:                         if (urIsToMigrate.size() > 0) {
364:                                 final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
365:                                 final ListSelectionDialog migrationDialog = MigrationDialogHelper
366:                                         .getTemplateModelListMigrationDialog(shell, urIsToMigrate);
367:
368:                                 if (migrationDialog.open() == Window.OK) {
369:                                         final Object[] selectedURIs = migrationDialog.getResult();
370:                                         if (selectedURIs != null) {
371:                                                 for (final Object selectedUri : selectedURIs) {
372:                                                         uris.add((URI) selectedUri);
373:                                                 }
374:                                         }
375:                                 }
376:                         }
377:                 } catch (final CoreException ex) {
378:                         Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));
379:                 }
380:                 return uris;
381:         }
382:
383:         @Override
384:         protected boolean enableValidation() {
385:                 return true;
386:         }
387:
388:         /**
389:          * {@link PreReplaceProcessor} for the legacy dmr migration which extracts the root EClass from a legacy dmr and
390:          * sets it to its containing {@link VTDomainModelReferenceSelector}.
391:          */
392:         protected static class DmrSelectorPreReplaceProcessor implements PreReplaceProcessor {
393:
394:                 private final LegacyDmrToRootEClass dmrToRootEClass;
395:
396:                 /**
397:                  * Default constructor.
398:                  *
399:                  * @param dmrToRootEClass The {@link LegacyDmrToRootEClass}
400:                  */
401:                 public DmrSelectorPreReplaceProcessor(LegacyDmrToRootEClass dmrToRootEClass) {
402:                         this.dmrToRootEClass = dmrToRootEClass;
403:                 }
404:
405:                 @Override
406:                 public void process(VDomainModelReference legacyDmr, VDomainModelReference segmentDmr) {
407:•                        if (legacyDmr.eContainer() instanceof VTDomainModelReferenceSelector) {
408:                                 final VTDomainModelReferenceSelector selector = (VTDomainModelReferenceSelector) legacyDmr.eContainer();
409:                                 final Optional<EClass> rootEClass = dmrToRootEClass.getRootEClass(legacyDmr);
410:                                 rootEClass.ifPresent(selector::setRootEClass);
411:                         }
412:                 }
413:
414:         }
415: }