diff options
Diffstat (limited to 'rba.tool.editor.ui/src/rba/tool/editor/ui/editor')
8 files changed, 1099 insertions, 0 deletions
diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/processor/RBAModelProcessorUtil.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/processor/RBAModelProcessorUtil.xtend new file mode 100644 index 0000000..5eebb92 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/processor/RBAModelProcessorUtil.xtend @@ -0,0 +1,177 @@ +package rba.tool.editor.ui.editor.model.edit.processor + +import java.util.ArrayList +import java.util.Collection +import java.util.Collections +import java.util.List +import java.util.ListIterator +import org.eclipse.emf.common.util.BasicEList +import org.eclipse.emf.common.util.EList +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.common.util.WrappedException +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.util.concurrent.IUnitOfWork +import rba.tool.editor.ui.editor.model.edit.refactoring.RBAModelRenameElementUtil + +class RBAModelProcessorUtil { + + public static final int NO_INDEX = -1; + public static final Object UNSET_VALUE = new Object(); + + def public static IUnitOfWork.Void<XtextResource> getAddProcessor(EObject owner, EStructuralFeature feature, Object object, int index) { + return new IUnitOfWork.Void<XtextResource>() { + override process(XtextResource xtextResource) throws Exception { + val allOwners = xtextResource.allContents.toIterable.filter[it === owner].toList(); + if(!allOwners.isEmpty()) { + doAddProcess(allOwners.get(0), feature, object, index); + } + } + }; + } + + def public static IUnitOfWork.Void<XtextResource> getRemoveProcessor(EObject owner, EStructuralFeature feature, Collection<Object> collection) { + return new IUnitOfWork.Void<XtextResource>() { + override process(XtextResource xtextResource) throws Exception { + val allOwners = xtextResource.allContents.toIterable.filter[it === owner].toList(); + if(!allOwners.isEmpty()) { + doRemoveProcess(allOwners.get(0), feature, collection); + } + } + }; + } + + def public static IUnitOfWork.Void<XtextResource> getSetProcessor(EObject owner, EStructuralFeature feature, Object value) { + return new IUnitOfWork.Void<XtextResource>() { + override process(XtextResource xtextResource) throws Exception { + val EObject docOwner = RBAModelProcessorUtil.findEObjectByURI(owner, xtextResource); + if(docOwner !== null && !docOwner.eIsProxy) { + doSetProcess(docOwner, feature, value); + } + } + }; + } + + def public static void doSetNameProcess(String value) { + RBAModelRenameElementUtil.INSTANCE.execute(value); + } + + def public static IUnitOfWork.Void<XtextResource> getUnexecutableProcessor() { + return new IUnitOfWork.Void<XtextResource>() { + override process(XtextResource xtextResource) throws Exception { + return; + } + }; + } + + def public static void doAddProcess(EObject owner, EStructuralFeature feature, Object object, int index) { + if(feature.isMany()) { + val sibling = owner.eGet(feature) as List<Object>; + if(!sibling.contains(object)) { + sibling.add(if(index === NO_INDEX || index > sibling.size()) sibling.size() else index, object); + } + } else { + owner.eSet(feature, object); + } + } + + def public static void doRemoveProcess(EObject owner, EStructuralFeature feature, Collection<Object> collection) { + if(feature.isMany()) { + val List<Object> objects = new ArrayList<Object>(collection); + val List<Object> sibling = owner.eGet(feature) as List<Object>; + for (obj : objects) { + if(sibling.contains(obj)) { + sibling.remove(obj); + } + } + } else { + if(feature.isUnsettable()) { + owner.eUnset(feature); + } + } + } + + def public static void doSetProcess(EObject owner, EStructuralFeature feature, Object value) { + if(feature.isMany()) { + val List<Object> values = if(value == UNSET_VALUE) Collections.EMPTY_LIST else value as List<Object>; + val EList<Object> oldValues = owner.eGet(feature) as EList<Object>; + + if(!oldValues.isEmpty()) { + if(!values.isEmpty()) { + val List<Object> removedValues = new BasicEList.FastCompare<Object>(oldValues); + removedValues.removeAll(values); + + // If we aren't simply removing all the old values... + if(!removedValues.equals(oldValues)) { + // If there are values to remove, append a command for them. + if(!removedValues.isEmpty()) { + oldValues.removeAll(removedValues); + } + + // Determine the values that will remain and move them into the right order, if necessary. + val EList<Object> remainingValues = new BasicEList.FastCompare<Object>(oldValues); + var count = -1; + for (object : values) { + val position = remainingValues.indexOf(object); + if(position != -1 && position != count.operator_plusPlus()) { + oldValues.move(count, position); + remainingValues.move(count, position); + } + } + + // Determine the values to be added and add them at the right position. + val List<Object> addedValues = new BasicEList.FastCompare<Object>(values); + addedValues.removeAll(remainingValues); + if(!addedValues.isEmpty()) { + var addIndex = remainingValues.size(); + for (val ListIterator<?> i = values.listIterator(values.size()); i.hasPrevious();) { + val Object object = i.previous(); + if(addedValues.contains(object)) { + doAddProcess(owner, feature, object, addIndex); + } else { + addIndex.operator_minusMinus(); + } + } + } + return; + } + } + oldValues.clear(); + } + + if(!values.isEmpty()) { + oldValues.addAll(values); + } else if(value == UNSET_VALUE && feature.isUnsettable()) { + owner.eUnset(feature); + } + } else { + if(value == UNSET_VALUE && feature.isUnsettable()) { + owner.eUnset(feature); + } else { + owner.eSet(feature, value); + } + } + } + + def public static EObject findEObjectByURI(EObject object, XtextResource resource) { + val URI uri = EcoreUtil.getURI(object); + if(uri !== null) { + return findEObjectByURI(uri, resource); + } + return null; + } + + def public static EObject findEObjectByURI(URI uri, XtextResource resource) { + if(uri.fragment() !== null) { + try { + val EObject result = resource.getEObject(uri.fragment()); + return result; + } catch(IllegalArgumentException e) { + } catch(WrappedException e) { + } + } + return null; + } +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameElementUtil.java b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameElementUtil.java new file mode 100644 index 0000000..cd84388 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameElementUtil.java @@ -0,0 +1,143 @@ +package rba.tool.editor.ui.editor.model.edit.refactoring; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.swt.widgets.Display; +import org.eclipse.xtext.ide.refactoring.IRenameStrategy2; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.resource.EObjectAtOffsetHelper; +import org.eclipse.xtext.resource.IGlobalServiceProvider; +import org.eclipse.xtext.resource.ILocationInFileProvider; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.ui.editor.XtextEditor; +import org.eclipse.xtext.ui.editor.utils.EditorUtils; +import org.eclipse.xtext.ui.refactoring.IRenameStrategy; +import org.eclipse.xtext.ui.refactoring.IRenameStrategy.Provider.NoSuchStrategyException; +import org.eclipse.xtext.ui.refactoring.ui.IRenameContextFactory; +import org.eclipse.xtext.ui.refactoring.ui.IRenameElementContext; +import org.eclipse.xtext.ui.refactoring.ui.RefactoringPreferences; +import org.eclipse.xtext.ui.refactoring.ui.RefactoringType; +import org.eclipse.xtext.ui.refactoring2.rename.ISimpleNameProvider; +import org.eclipse.xtext.util.ITextRegion; +import org.eclipse.xtext.util.TextRegion; +import org.eclipse.xtext.util.concurrent.IUnitOfWork; + +import com.google.inject.Inject; + +import rba.tool.editor.ui.activator.ExtensionEditorActivator; + +public class RBAModelRenameElementUtil { + + public static RBAModelRenameElementUtil INSTANCE = new RBAModelRenameElementUtil(); + + @Inject + private EObjectAtOffsetHelper eObjectAtOffsetHelper; + + @Inject + private ILocationInFileProvider locationInFileProvider; + + @Inject + protected RBAModelRenameRefactoringController renameRefactoringController; + + @Inject + protected IGlobalServiceProvider globalServiceProvider; + + @Inject + protected RefactoringPreferences preferences; + + @Inject + protected IRenameContextFactory renameContextFactory; + + @Inject + protected RBAModelSyncUtil syncUtil; + + private RBAModelRenameElementUtil() { + ExtensionEditorActivator.getInstance().injectMembers(this); + } + + public void execute(String value) { + try { + final XtextEditor editor = EditorUtils.getActiveXtextEditor(); + if (editor != null) { + syncUtil.totalSync(preferences.isSaveAllBeforeRefactoring(), renameRefactoringController.getActiveLinkedMode() == null); + final ITextSelection selection = (ITextSelection) editor.getSelectionProvider().getSelection(); + IRenameElementContext renameElementContext = editor.getDocument().priorityReadOnly(new IUnitOfWork<IRenameElementContext, XtextResource>() { + @Override + public IRenameElementContext exec(XtextResource resource) throws Exception { + EObject selectedElement = eObjectAtOffsetHelper.resolveElementAt(resource, selection.getOffset()); + if (selectedElement != null) { + IRenameElementContext renameElementContext = renameContextFactory.createRenameElementContext(selectedElement, editor, selection, resource); + if (isRefactoringEnabled(renameElementContext, resource)) + return renameElementContext; + } + return null; + } + }); + if (renameElementContext != null) { + startRenameElement(renameElementContext, value); + } + } + } catch (OperationCanceledException e) { + MessageDialog.openError(Display.getCurrent().getActiveShell(), "Error initializing refactoring 1", "\nSee log for details"); + // cancelled by user, ok + return; + } catch (InterruptedException e) { + MessageDialog.openError(Display.getCurrent().getActiveShell(), "Error initializing refactoring 2", "\nSee log for details"); + // cancelled by user, ok + return; + } catch (Exception exc) { + exc.printStackTrace(); + MessageDialog.openError(Display.getCurrent().getActiveShell(), "Error initializing refactoring", exc.getMessage() + "\nSee log for details"); + } + } + + public IRenameElementContext createRenameElementContext(EObject targetElement, final XtextEditor triggeringEditor, final ITextSelection selection, + XtextResource triggeringResource) { + return renameContextFactory.createRenameElementContext(targetElement, triggeringEditor, selection, triggeringResource); + } + + protected boolean isRefactoringEnabled(IRenameElementContext renameElementContext, XtextResource resource) { + ResourceSet resourceSet = resource.getResourceSet(); + if (renameElementContext != null && resourceSet != null) { + EObject targetElement = resourceSet.getEObject(renameElementContext.getTargetElementURI(), true); + if (targetElement != null && !targetElement.eIsProxy()) { + if (targetElement.eResource() == resource && renameElementContext.getTriggeringEditorSelection() instanceof ITextSelection) { + ITextSelection textSelection = (ITextSelection) renameElementContext.getTriggeringEditorSelection(); + ITextRegion selectedRegion = new TextRegion(textSelection.getOffset(), textSelection.getLength()); + INode crossReferenceNode = eObjectAtOffsetHelper.getCrossReferenceNode(resource, selectedRegion); + if (crossReferenceNode == null) { + // selection is on the declaration. make sure it's the name + ITextRegion significantRegion = locationInFileProvider.getSignificantTextRegion(targetElement); + if (!significantRegion.contains(selectedRegion)) + return false; + } + } + IRenameStrategy.Provider renameStrategyProvider = globalServiceProvider.findService(targetElement, IRenameStrategy.Provider.class); + try { + if (renameStrategyProvider.get(targetElement, renameElementContext) != null) { + return true; + } else { + IRenameStrategy2 strategy2 = globalServiceProvider.findService(targetElement, IRenameStrategy2.class); + ISimpleNameProvider simpleNameProvider = globalServiceProvider.findService(targetElement, ISimpleNameProvider.class); + return strategy2 != null && simpleNameProvider.canRename(targetElement); + } + + } catch (NoSuchStrategyException e) { + MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "Cannot rename element", e.getMessage()); + } + } + } + return false; + } + + protected void startRenameElement(IRenameElementContext renameElementContext, String value) throws InterruptedException { + // renameRefactoringController.startRefactoring(renameElementContext); + // renameRefactoringController.startRefactoring(RefactoringType.REFACTORING_DIALOG); + renameRefactoringController.initialize(renameElementContext); + renameRefactoringController.setNewNameText(value); + renameRefactoringController.startRefactoring(RefactoringType.REFACTORING_DIALOG); + } +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameRefactoringController.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameRefactoringController.xtend new file mode 100644 index 0000000..737d004 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelRenameRefactoringController.xtend @@ -0,0 +1,24 @@ +package rba.tool.editor.ui.editor.model.edit.refactoring + +import com.google.inject.Singleton +import org.eclipse.xtext.ui.editor.XtextEditor +import org.eclipse.xtext.ui.refactoring.ui.RenameRefactoringController + +@Singleton +class RBAModelRenameRefactoringController extends RenameRefactoringController { + + private String newNameText; + + override protected getOriginalName(XtextEditor xtextEditor) { + if(this instanceof RBAModelRenameRefactoringController) { + return newNameText; + } else { + super.getOriginalName(xtextEditor); + } + } + + def public void setNewNameText(String name) { + this.newNameText = name; + } + +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelSyncUtil.java b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelSyncUtil.java new file mode 100644 index 0000000..ae6cfb3 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/edit/refactoring/RBAModelSyncUtil.java @@ -0,0 +1,175 @@ +package rba.tool.editor.ui.editor.model.edit.refactoring; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.service.OperationCanceledError; +import org.eclipse.xtext.ui.editor.XtextEditor; +import org.eclipse.xtext.ui.editor.model.XtextDocument; +import org.eclipse.xtext.util.concurrent.IUnitOfWork; + +import com.google.inject.Inject; + +public class RBAModelSyncUtil { + + @Inject(optional = true) + private IWorkbench workbench; + + @Inject(optional = true) + private IWorkspace workspace; + + public void totalSync(final boolean saveAll, boolean useProgressDialog) throws InvocationTargetException, InterruptedException { + totalSync(saveAll, useProgressDialog, true); + } + + public void totalSync(final boolean saveAll, boolean useProgressDialog, boolean fork) throws InvocationTargetException, InterruptedException { + if (Display.getCurrent() != null && workbench != null) { + if (useProgressDialog) { + workbench.getProgressService().run(fork, true, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + doReconcileAndBuild(saveAll, monitor); + } + }); + } else { + doReconcileAndBuild(saveAll, null); + } + } + } + + private void doReconcileAndBuild(final boolean saveAll, IProgressMonitor monitor) throws InterruptedException { + try { + SubMonitor progress = SubMonitor.convert(monitor, 10); + reconcileAllEditors(workbench, saveAll, progress.newChild(1)); + if (progress.isCanceled()) { + throw new InterruptedException(); + } + waitForBuild(progress.newChild(4)); + if (progress.isCanceled()) { + throw new InterruptedException(); + } + yieldToQueuedDisplayJobs(progress.newChild(1)); + if (progress.isCanceled()) { + throw new InterruptedException(); + } + waitForAutoBuild(progress.newChild(4)); + } catch (OperationCanceledException e) { + throw new InterruptedException(); + } + } + + public void totalSync(final boolean saveAll) throws InvocationTargetException, InterruptedException { + totalSync(saveAll, true); + } + + public void reconcileAllEditors(IWorkbench workbench, final boolean saveAll, final IProgressMonitor monitor) { + for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) { + for (IWorkbenchPage page : window.getPages()) { + for (IEditorReference editorReference : page.getEditorReferences()) { + if (monitor.isCanceled()) + return; + final IEditorPart editor = editorReference.getEditor(false); + if (editor != null) { + if (editor instanceof XtextEditor) { + waitForReconciler((XtextEditor) editor); + } + if (saveAll) { + Display display = workbench.getDisplay(); + display.syncExec(new Runnable() { + @Override + public void run() { + if (editor.isDirty()) { + editor.doSave(monitor); + } + } + }); + } + } + } + } + } + } + + /** + * this methods blocks until the following jobs have finished, - the reconciler - the editor validation job - the dirty + * state editor updater job + */ + public void waitForReconciler(XtextEditor editor) { + try { + editor.getDocument().readOnly(new IUnitOfWork.Void<XtextResource>() { + @Override + public void process(XtextResource state) throws Exception { + // this doesn't execute before the reconciler has finished + } + }); + // reconciling schedules both, validation and dirty state + Job validationJob = ((XtextDocument) editor.getDocument()).getValidationJob(); + validationJob.join(); + editor.getDirtyStateEditorSupport().waitForUpdateEditorJob(); + } catch (OperationCanceledException e) { + } catch (OperationCanceledError e) { + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void waitForBuild(IProgressMonitor monitor) { + try { + workspace.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + } catch (CoreException e) { + throw new OperationCanceledException(e.getMessage()); + } + } + + /** + * @deprecated we should not rely on auto build to be triggered. Use {@link #waitForBuild(IProgressMonitor)} instead. + */ + @Deprecated + public void waitForAutoBuild(IProgressMonitor monitor) { + boolean wasInterrupted = false; + do { + try { + Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, monitor); + wasInterrupted = false; + } catch (OperationCanceledException e) { + throw e; + } catch (InterruptedException e) { + wasInterrupted = true; + } + } while (wasInterrupted); + } + + public void yieldToQueuedDisplayJobs(IProgressMonitor monitor) { + yieldToQueuedDisplayJobs(monitor, 50000); + } + + public void yieldToQueuedDisplayJobs(IProgressMonitor monitor, int maxJobsToYieldTo) { + int count = 0; + if (Display.getCurrent() != null) { + while (count < maxJobsToYieldTo && Display.getCurrent().readAndDispatch()) { + if (monitor.isCanceled()) + throw new OperationCanceledException(); + ++count; + } + if (count == maxJobsToYieldTo) { + System.out.println("maxJobsToYieldTo probably exceeded. Worked: " + count); + } + } + } + +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/manager/ResourceManagerUI.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/manager/ResourceManagerUI.xtend new file mode 100644 index 0000000..105d9de --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/model/manager/ResourceManagerUI.xtend @@ -0,0 +1,428 @@ +package rba.tool.editor.ui.editor.model.manager + +import com.google.inject.Inject +import java.util.ArrayList +import java.util.Collection +import java.util.Collections +import java.util.List +import org.eclipse.core.resources.IProject +import org.eclipse.core.resources.IncrementalProjectBuilder +import org.eclipse.core.resources.ResourcesPlugin +import org.eclipse.core.runtime.IProgressMonitor +import org.eclipse.core.runtime.OperationCanceledException +import org.eclipse.core.runtime.SubMonitor +import org.eclipse.core.runtime.jobs.Job +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.EAttribute +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.ecore.resource.ResourceSet +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.emf.edit.provider.ComposeableAdapterFactory +import org.eclipse.emf.edit.provider.IEditingDomainItemProvider +import org.eclipse.jface.dialogs.MessageDialog +import org.eclipse.swt.widgets.Display +import org.eclipse.ui.IEditorPart +import org.eclipse.xtext.resource.ILocationInFileProvider +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.serializer.ISerializer +import org.eclipse.xtext.service.OperationCanceledError +import org.eclipse.xtext.ui.editor.LanguageSpecificURIEditorOpener +import org.eclipse.xtext.ui.editor.XtextEditor +import org.eclipse.xtext.ui.editor.model.IXtextDocument +import org.eclipse.xtext.ui.editor.utils.EditorUtils +import org.eclipse.xtext.util.ITextRegion +import org.eclipse.xtext.util.concurrent.IUnitOfWork +import rba.core.provider.RBACoreItemProviderAdapterFactory +import rba.sound.provider.RBASoundItemProviderAdapterFactory +import rba.tool.editor.resource.IRBAModelResourceLoader +import rba.tool.editor.ui.activator.ExtensionEditorActivator +import rba.tool.editor.ui.editor.model.edit.processor.RBAModelProcessorUtil +import rba.tool.editor.ui.resource.RBAModelResourceSetProvider +import rba.view.provider.RBAViewItemProviderAdapterFactory + +class ResourceManagerUI { + + public static ResourceManagerUI INSTANCE = new ResourceManagerUI(); + + @Inject private RBAModelResourceSetProvider resourceSetProvider; + + @Inject private LanguageSpecificURIEditorOpener editorOpener ; + + @Inject private ILocationInFileProvider locationProvider; + + @Inject private ISerializer serializer; + + @Inject IRBAModelResourceLoader resourceLoader; + + private List<ComposeableAdapterFactory> adapterFactorys = new ArrayList<ComposeableAdapterFactory>; + + private IProject currentProject; + + private new() { + ExtensionEditorActivator.getInstance().injectMembers(this); + adapterFactorys.add(new RBACoreItemProviderAdapterFactory()); + adapterFactorys.add(new RBAViewItemProviderAdapterFactory()); + adapterFactorys.add(new RBASoundItemProviderAdapterFactory()); + } + + def public IProject getCurrentProject() { + return currentProject; + } + + def public void setCurrentProject(IProject project) { + currentProject = project; + } + + def public boolean isCurrentProject(IProject project) { + if (project === null || !project.isOpen()) { + return false; + } + + if (project.equals(currentProject)) { + return true; + } + + return false; + } + + def public ResourceSet getCurrentResourceSet() { + return resourceSetProvider.getResourceSet(currentProject); + } + + def public void setCurrentResourceSet(ResourceSet resourceSet) { + resourceSetProvider.setResourceSet(currentProject, resourceSet); + } + + def public IXtextDocument getXtextDocument(IEditorPart openEditor) { + val XtextEditor xtextEditor = EditorUtils.getXtextEditor(openEditor); + if (xtextEditor !== null) { + return xtextEditor.getDocument(); + } + return null; + } + + def public void add(EObject owner, EStructuralFeature feature, Object object, int index) { + val Object outerOwner = owner ?: getParent(object); + if (outerOwner === null) { + return; + } + if (!(outerOwner instanceof EObject)) { + return; + } + + if (feature === null || object === null) { + return; + } + + if (!isValid(outerOwner as EObject, feature)) { + return; + } + + val editorPart = open(outerOwner as EObject, false); + var IXtextDocument document = getXtextDocument(editorPart); + + if (document !== null) { + document.modify(RBAModelProcessorUtil.getAddProcessor(outerOwner as EObject, feature, object, if (index < 0) RBAModelProcessorUtil.NO_INDEX else index)); + } + } + + def public void remove(EObject owner, EStructuralFeature feature, Object object) { + val Object outerOwner = owner ?: getParent(object); + if (outerOwner === null) { + return; + } + if (!(outerOwner instanceof EObject)) { + return; + } + + remove(outerOwner as EObject, feature, Collections.singleton(object)); + } + + def public void remove(EObject owner, EStructuralFeature feature, Collection<Object> collection) { + if (owner !== null) { + if (feature === null || collection === null || collection.isEmpty()) { + return; + } + + if (!isValid(owner, feature)) { + return; + } + + val editorPart = open(owner as EObject, false); + var IXtextDocument document = getXtextDocument(editorPart); + + if (document !== null) { + document.modify(RBAModelProcessorUtil.getRemoveProcessor(owner as EObject, feature, collection)); + } + } else { + remove(feature, collection); + } + } + + def public void remove(EStructuralFeature feature, Collection<Object> collection) { + if (feature === null || collection === null || collection.isEmpty()) { + return; + } + + val List<Object> objects = new ArrayList<Object>(collection); + while (!objects.isEmpty()) { + // We will iterate over the whole collection, removing some as we go. + val remainingObjects = objects.listIterator(); + + // Take the first object, and remove it. + val object = remainingObjects.next(); + remainingObjects.remove(); + + // Determine the object's parent. + val parent = getParent(object); + if (parent instanceof EObject) { + // Now we want to find all the other objects with this same parent. + // So we can collection siblings together and give the parent control over their removal. + val List<Object> siblings = new ArrayList<Object>(); + siblings.add(object); + + while (remainingObjects.hasNext()) { + // Get the next object and check if it has the same parent. + val otherObject = remainingObjects.next(); + val otherParent = getParent(otherObject); + if (otherParent == parent) { + // Remove the object and add it as a sibling. + remainingObjects.remove(); + siblings.add(otherObject); + } + } + remove(parent as EObject, feature, siblings); + } + } + } + + def public void set(EObject owner, EStructuralFeature feature, Object value) { + val Object outerOwner = owner ?: getParent(value); + if (outerOwner === null) { + return; + } + if (!(outerOwner instanceof EObject)) { + return; + } + + if (feature === null) { + return; + } + + if (!isValid(owner, feature)) { + return; + } + + val innerValue = value ?: RBAModelProcessorUtil.UNSET_VALUE; + val editorPart = open(outerOwner as EObject, false); + var IXtextDocument document = getXtextDocument(editorPart); + + if (document !== null) { + document.modify(RBAModelProcessorUtil.getSetProcessor(outerOwner as EObject, feature, innerValue)); + selectAndReveal(editorPart, EcoreUtil.getURI(outerOwner as EObject), feature, true); + } + } + + def public void unset(EObject owner, EStructuralFeature feature) { + if (owner === null || feature === null) { + return; + } + + if (!isValid(owner, feature)) { + return; + } + + val editorPart = open(owner as EObject, false); + var IXtextDocument document = getXtextDocument(editorPart); + + if (document !== null) { + document.modify(RBAModelProcessorUtil.getSetProcessor(owner, feature, RBAModelProcessorUtil.UNSET_VALUE)); + } + } + + def public void setName(EObject owner, EStructuralFeature feature, Object value) { + val Object outerOwner = owner ?: getParent(value); + if (outerOwner === null) { + return; + } + if (!(outerOwner instanceof EObject)) { + return; + } + + val XtextEditor editor = open(outerOwner as EObject, true); + if (editor === null) { + return; + } + + if (feature === null) { + return; + } + + if (!isValid(owner, feature)) { + return; + } + + if (!(value instanceof String)) { + return; + } + val innerValue = value as String; + + RBAModelProcessorUtil.doSetNameProcess(innerValue) + } + + def public void waitForBuildProgress(Object family, IProgressMonitor monitor) { + var boolean wasInterrupted = false; + do { + try { + Job.getJobManager().join(family, monitor); + wasInterrupted = false; + } catch (OperationCanceledException e) { + throw e; + } catch (InterruptedException e) { + wasInterrupted = true; + } + } while (wasInterrupted); + } + + def public XtextEditor open(EObject eObject, boolean select) { + val resource = eObject.eResource(); + if (resource === null) { + return null; + } + + val editorPart = editorOpener.open(EcoreUtil.getURI(eObject), select); + if (!(editorPart instanceof XtextEditor)) { + return null; + } + + return (editorPart as XtextEditor); + } + + def public XtextEditor open(URI uri, boolean select) { + if (uri === null || uri.isEmpty()) { + return null + } + + val editorPart = editorOpener.open(uri, select); + if (!(editorPart instanceof XtextEditor)) { + return null; + } + + return (editorPart as XtextEditor); + } + + def private Object getParent(Object object) { + for (adapterFactory : adapterFactorys) { + val IEditingDomainItemProvider editingDomainItemProvider = adapterFactory.adapt(object, IEditingDomainItemProvider) as IEditingDomainItemProvider; + if (editingDomainItemProvider !== null) { + return editingDomainItemProvider.getParent(object); + } + } + return null; + } + + def private static isValid(EObject owner, EStructuralFeature feature) { + if (feature instanceof EReference && owner.eClass().getEAllReferences().contains(feature)) { + return true; + } + if (feature instanceof EAttribute && owner.eClass().getEAllAttributes().contains(feature)) { + return true; + } + return false; + } + + def public void switchToProject(IProject project, IProgressMonitor monitor) throws InterruptedException { + if (project === null) { + return; + } + + try { + val SubMonitor progress = SubMonitor.convert(monitor, 10); + doSwitch(project, progress.newChild(2)); + if (progress.isCanceled()) { + throw new InterruptedException(); + } + doBuild(project, progress.newChild(6)); + if (progress.isCanceled()) { + throw new InterruptedException(); + } + waitForBuildProgress(ResourcesPlugin.FAMILY_MANUAL_BUILD, progress.newChild(2)); + } catch (Exception e) { + throw new InterruptedException(e.getMessage()); + } + } + + def public boolean doConfirm(IProject project, boolean showConfirmDialog) throws InterruptedException { + if (project === null || !project.isOpen()) { + throw new InterruptedException(); + } + if (isCurrentProject(project)) { + return true; + } + + val boolean confirm = if (showConfirmDialog) + MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Switch Project", "Do you want to switch to [" + project.getName() + "] project?") + else + true; + + return confirm; + } + + def private void doSwitch(IProject project, IProgressMonitor monitor) { + try { + setCurrentProject(project); + } catch (Exception e) { + throw new InterruptedException(e.getMessage()); + } + } + + def private void doBuild(IProject project, IProgressMonitor monitor) { + try { + project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); + } catch (Exception e) { + throw new InterruptedException(e.getMessage()); + } + } + + def private void selectAndReveal(IEditorPart openEditor, URI uri, EStructuralFeature feature, boolean select) { + if (openEditor instanceof XtextEditor && select) { + val xtextEditor = openEditor as XtextEditor; + var boolean success = false; + var int tries = 0; + while (!success || tries >= 5) { + try { + xtextEditor.getDocument().readOnly(new IUnitOfWork.Void<XtextResource>() { + override process(XtextResource resource) throws Exception { + if (resource !== null) { + val EObject object = RBAModelProcessorUtil.findEObjectByURI(uri, resource); + if (object !== null) { + val ITextRegion location = if (feature !== null) + locationProvider.getSignificantTextRegion(object, feature, 0) + else + locationProvider.getSignificantTextRegion(object); + xtextEditor.selectAndReveal(location.getOffset(), location.getLength()); + } + } + } + }); + xtextEditor.doSave(null) + success = true; + } catch (OperationCanceledException e) { + } catch (OperationCanceledError e) { + } finally { + tries++; + } + } + } + } + + def public String serialize(EObject object) { + return serializer.serialize(object) + } + + def public void loadAndResolveResource(ResourceSet resourceSet, URI[] URIs, IProject project) { + resourceLoader.loadAndResolveResource(resourceSet, URIs, project); + } +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateRegistry.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateRegistry.xtend new file mode 100644 index 0000000..0b1126c --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateRegistry.xtend @@ -0,0 +1,99 @@ +package rba.tool.editor.ui.editor.templates + +import com.google.common.collect.Lists +import com.google.inject.Inject +import com.google.inject.Singleton +import java.util.List +import java.util.Map +import org.apache.commons.lang.StringUtils +import org.eclipse.jface.text.templates.Template +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.GrammarUtil +import org.eclipse.xtext.IGrammarAccess +import org.eclipse.xtext.Keyword +import org.eclipse.xtext.ui.editor.templates.ContextTypeIdHelper +import rba.tool.editor.ui.util.CharacterUtil + +@Singleton +class RBAModelTemplateRegistry extends TemplateRegistry { + + private final Map<String, String> PATTERNS = newLinkedHashMap( + "rba.tool.editor.RBAModel.kw_runtime:" -> "${true}", + "rba.tool.editor.RBAModel.kw_global:" -> "${false}", + "rba.tool.editor.RBAModel.kw_description:" -> "\"${}\"", + "rba.tool.editor.RBAModel.kw_width:" -> "${0}", + "rba.tool.editor.RBAModel.kw_height:" -> "${0}", + "rba.tool.editor.RBAModel.kw_x:" -> "${0}", + "rba.tool.editor.RBAModel.kw_y:" -> "${0}", + "rba.tool.editor.RBAModel.kw_attenuateValue:" -> "${0}", + "rba.tool.editor.RBAModel.kw_loserType:" -> "${NEVER_GIVEUP}", + "rba.tool.editor.RBAModel.kw_arbitrationPolicy:" -> "${DEFAULT}", + "rba.tool.editor.RBAModel.kw_basePoint:" -> "${LEFT_TOP}", + "rba.tool.editor.RBAModel.kw_type:" -> "${DEFAULT}", + "rba.tool.editor.RBAModel.kw_allocatable:" -> "[${cursor}]", + "rba.tool.editor.RBAModel.kw_subarea:" -> "[${cursor}]", + "rba.tool.editor.RBAModel.kw_sizeReference:" -> "${size_id}", + "rba.tool.editor.RBAModel.kw_layout:" -> "", + "rba.tool.editor.RBAModel.kw_visibility:" -> "${STANDARD_VALUE}", + "rba.tool.editor.RBAModel.kw_priority:" -> "${STANDARD_VALUE}", + "rba.tool.editor.RBAModel.kw_value:" -> "${STANDARD_VALUE}", + "rba.tool.editor.RBAModel.kw_zorder:" -> "${STANDARD_VALUE}", + "rba.tool.editor.RBAModel.kw_contentStateRef:" -> "${contentState_id}", + "rba.tool.editor.RBAModel.kw_areaReference:" -> "${area_id}", + "rba.tool.editor.RBAModel.kw_condition:" -> "", + "rba.tool.editor.RBAModel.kw_area:" -> "${area_id}", + "rba.tool.editor.RBAModel.kw_content:" -> "${content_id}" + ) ; + + private final ContextTypeIdHelper helper; + + @Inject + public new(IGrammarAccess grammarAccess, ContextTypeIdHelper helper) { + this.helper = helper; + registerTemplates(grammarAccess); + } + + def protected void registerTemplates(IGrammarAccess grammarAccess) { + val List<Template> allTemplates = Lists.newArrayList(); + for (parserRule : GrammarUtil.allParserRules(grammarAccess.getGrammar())) { + var Template template; + for (keyword : EcoreUtil2.getAllContentsOfType(parserRule, Keyword)) { + if (CharacterUtil.isKeywordWorthyToPropose(keyword)) { + val name = keyword.value; + if (!StringUtils.isEmpty(name)) { + if (StringUtils.endsWith(name, ":")) { + template = new Template(name, "", getId(keyword), getPattern(keyword), true); + } else { + template = new Template(name, "", getId(keyword), name, true); + } + allTemplates.add(template); + } + } + } + } + for (enumRule : GrammarUtil.allEnumRules(grammarAccess.getGrammar())) { + var Template template; + for (keyword : EcoreUtil2.getAllContentsOfType(enumRule, Keyword)) { + if (CharacterUtil.isKeywordWorthyToPropose(keyword)) { + val name = keyword.value; + if (!StringUtils.isEmpty(name)) { + template = new Template(name, "", getId(keyword), name, true); + allTemplates.add(template); + } + } + } + } + + for (template : allTemplates) { + addTemplate(template); + } + } + + def public String getId(Keyword k) { + return helper.getId(k); + } + + def private String getPattern(Keyword k) { + return StringUtils.join(#[k.value, " ", PATTERNS.get(getId(k)) ?: ""]); + } +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateStore.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateStore.xtend new file mode 100644 index 0000000..7330f91 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/RBAModelTemplateStore.xtend @@ -0,0 +1,30 @@ +package rba.tool.editor.ui.editor.templates + +import com.google.inject.Inject +import com.google.inject.Singleton +import java.util.ArrayList +import java.util.List +import org.eclipse.jface.preference.IPreferenceStore +import org.eclipse.jface.text.templates.ContextTypeRegistry +import org.eclipse.jface.text.templates.Template +import org.eclipse.ui.plugin.AbstractUIPlugin +import org.eclipse.xtext.ui.editor.templates.XtextTemplateStore + +@Singleton +class RBAModelTemplateStore extends XtextTemplateStore { + + private TemplateRegistry templateRegistry; + + @Inject + new(TemplateRegistry templateRegistry, ContextTypeRegistry registry, IPreferenceStore store, String key, AbstractUIPlugin plugin) { + super(registry, store, key, plugin); + this.templateRegistry = templateRegistry; + } + + override getTemplates(String contextTypeId) { + val List<Template> templates = new ArrayList<Template>(super.getTemplates(contextTypeId)); + val template = templateRegistry.getTemplate(contextTypeId); + if (template !== null) templates.add(template); + return templates.toArray(newArrayOfSize(templates.size())); + } +} diff --git a/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/TemplateRegistry.xtend b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/TemplateRegistry.xtend new file mode 100644 index 0000000..edba477 --- /dev/null +++ b/rba.tool.editor.ui/src/rba/tool/editor/ui/editor/templates/TemplateRegistry.xtend @@ -0,0 +1,23 @@ +package rba.tool.editor.ui.editor.templates + +import java.util.Iterator +import java.util.LinkedHashMap +import java.util.Map +import org.eclipse.jface.text.templates.Template + +class TemplateRegistry { + + private final Map<String, Template> fTemplates = new LinkedHashMap<String, Template>(); + + def public void addTemplate(Template template) { + fTemplates.put(template.contextTypeId, template); + } + + def public Template getTemplate(String id) { + return fTemplates.get(id); + } + + def public Iterator<Template> templates() { + return fTemplates.values().iterator(); + } +} |