1 /******************************************************************************* 2 * Copyright (c) 2010, 2017 BestSolution.at and others. 3 * 4 * 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 * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation 13 * Wim Jongman <wim.jongman@remainsoftware.com> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=393150 14 * Olivier Prouvost <olivier.prouvost@opcoach.com> - Bug 509603 15 ******************************************************************************/ 16 package org.eclipse.e4.tools.emf.ui.internal.wbm; 17 18 import java.io.IOException; 19 20 import javax.annotation.PreDestroy; 21 import javax.inject.Inject; 22 import javax.inject.Named; 23 24 import org.eclipse.core.resources.IProject; 25 import org.eclipse.core.resources.IResourceChangeEvent; 26 import org.eclipse.core.resources.IResourceChangeListener; 27 import org.eclipse.core.resources.IResourceDelta; 28 import org.eclipse.core.runtime.IStatus; 29 import org.eclipse.core.runtime.NullProgressMonitor; 30 import org.eclipse.core.runtime.Path; 31 import org.eclipse.core.runtime.Status; 32 import org.eclipse.e4.core.contexts.IEclipseContext; 33 import org.eclipse.e4.core.di.annotations.Optional; 34 import org.eclipse.e4.tools.emf.ui.common.IModelResource; 35 import org.eclipse.e4.tools.emf.ui.internal.common.ModelEditor; 36 import org.eclipse.e4.tools.services.IResourcePool; 37 import org.eclipse.e4.ui.di.UISynchronize; 38 import org.eclipse.e4.ui.model.application.ui.basic.MPart; 39 import org.eclipse.e4.ui.workbench.modeling.EPartService; 40 import org.eclipse.emf.common.util.EList; 41 import org.eclipse.emf.ecore.resource.Resource; 42 import org.eclipse.jface.dialogs.ErrorDialog; 43 import org.eclipse.swt.widgets.Composite; 44 import org.eclipse.swt.widgets.Shell; 45 import org.osgi.framework.FrameworkUtil; 46 47 public class ApplicationModelEditor extends ModelEditor { 48 49 private static final String EDITORPROJECT = "org.eclipse.e4.tools.emf.ui.editorproject"; //$NON-NLS-1$ 50 51 @Inject 52 @Optional 53 MPart part; 54 55 @Inject 56 EPartService partService; 57 58 private Resource resource; 59 60 private IProject project; 61 62 @Inject 63 Shell shell; 64 65 @Inject 66 UISynchronize sync; 67 68 @Inject ApplicationModelEditor(Composite composite, IEclipseContext context, IModelResource modelProvider, @Named(EDITORPROJECT) @Optional IProject project, IResourcePool resourcePool)69 public ApplicationModelEditor(Composite composite, IEclipseContext context, IModelResource modelProvider, @Named(EDITORPROJECT) @Optional IProject project, IResourcePool resourcePool) { 70 super(composite, context, modelProvider, project, resourcePool); 71 EList<Resource> resources = modelProvider.getEditingDomain().getResourceSet().getResources(); 72 if (!resources.isEmpty()) { 73 resource = resources.get(0); 74 } 75 } 76 77 @Inject addResourceListener(@amedEDITORPROJECT) @ptional IProject project)78 public void addResourceListener(@Named(EDITORPROJECT) @Optional IProject project) { 79 if (project != null && resource != null) { 80 this.project = project; 81 project.getWorkspace().addResourceChangeListener(listener); 82 } 83 } 84 85 @PreDestroy removeResourceListener()86 private void removeResourceListener() { 87 if (project != null) { 88 project.getWorkspace().removeResourceChangeListener(listener); 89 } 90 } 91 92 /** 93 * Listen for changes on the resource being edited. Will close the part if 94 * the resource was deleted or the containing project was closed. 95 */ 96 private IResourceChangeListener listener = new IResourceChangeListener() { 97 @Override 98 public void resourceChanged(IResourceChangeEvent event) { 99 100 if (event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE) { 101 if (event.getResource().equals(project)) { 102 hidePart(true); 103 } 104 return; 105 } 106 107 if (resource == null) { 108 return; 109 } 110 111 IResourceDelta delta = event.getDelta().findMember(new Path(resource.getURI().toPlatformString(false))); 112 if (delta == null) { 113 return; 114 } 115 116 if (delta.getKind() == IResourceDelta.REMOVED) { 117 hidePart(true); 118 } 119 120 // If the current model editor is causing this resource change event 121 // then skip the reload. 122 if (!isSaving()) { 123 124 // reload the model if the file has changed 125 if ((delta.getKind() == IResourceDelta.CHANGED) && (delta.getMarkerDeltas().length == 0)) { 126 reloadModel(); 127 } 128 } 129 } 130 131 132 private void hidePart(final boolean force) { 133 sync.asyncExec(() -> partService.hidePart(part, force)); 134 } 135 }; 136 137 /** 138 * Shows an error dialog based on the passed exception. It should never 139 * occur but if it does, the user can report a problem. 140 * 141 * @param exc 142 */ statusDialog(final Exception exc)143 protected void statusDialog(final Exception exc) { 144 try { 145 sync.syncExec(() -> { 146 String bundle = FrameworkUtil.getBundle(getClass()).getSymbolicName(); 147 Status status = new Status(IStatus.ERROR, bundle, exc.getMessage()); 148 ErrorDialog.openError(shell, exc.getMessage(), exc.getMessage(), status); 149 exc.printStackTrace(System.err); 150 }); 151 } catch (Exception e) { 152 } 153 } 154 155 /** 156 * Reload the model. 157 */ reloadModel()158 protected void reloadModel() { 159 getModelProvider().getRoot().getRealm().asyncExec(() -> { 160 try { 161 resource.unload(); 162 resource.load(null); 163 getModelProvider().replaceRoot(resource.getContents().get(0)); 164 doSave(new NullProgressMonitor()); 165 refreshViewer(); 166 } catch (IOException e) { 167 statusDialog(e); 168 } 169 }); 170 } 171 }