diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo')
11 files changed, 5828 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionActionBarContributor.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionActionBarContributor.java new file mode 100644 index 0000000000..bb586373cb --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionActionBarContributor.java @@ -0,0 +1,812 @@ +/** + */ +package org.eclipse.emf.cdo.evolution.presentation; + +import org.eclipse.emf.cdo.evolution.util.ElementHandler; +import org.eclipse.emf.cdo.evolution.util.ElementRunnable; +import org.eclipse.emf.cdo.evolution.util.IDAnnotation; + +import org.eclipse.emf.common.ui.action.ViewerFilterAction; +import org.eclipse.emf.common.ui.viewer.IViewerProvider; +import org.eclipse.emf.ecore.EAnnotation; +import org.eclipse.emf.ecore.EGenericType; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.ETypeParameter; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.presentation.EcoreEditorPlugin; +import org.eclipse.emf.edit.command.ChangeCommand; +import org.eclipse.emf.edit.command.CommandParameter; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.edit.domain.IEditingDomainProvider; +import org.eclipse.emf.edit.ui.action.CollapseAllAction; +import org.eclipse.emf.edit.ui.action.ControlAction; +import org.eclipse.emf.edit.ui.action.CreateChildAction; +import org.eclipse.emf.edit.ui.action.CreateSiblingAction; +import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor; +import org.eclipse.emf.edit.ui.action.FindAction; +import org.eclipse.emf.edit.ui.action.LoadResourceAction; +import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IContributionManager; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.action.SubContributionItem; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PartInitException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * This is the action bar contributor for the Evolution model editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ +public class EvolutionActionBarContributor extends EditingDomainActionBarContributor implements ISelectionChangedListener +{ + /** + * This keeps track of the active editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IEditorPart activeEditorPart; + + /** + * This keeps track of the current selection provider. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected ISelectionProvider selectionProvider; + + /** + * This action opens the Properties view. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IAction showPropertiesViewAction = new Action(EvolutionEditorPlugin.INSTANCE.getString("_UI_ShowPropertiesView_menu_item")) + { + @Override + public void run() + { + try + { + getPage().showView("org.eclipse.ui.views.PropertySheet"); + } + catch (PartInitException exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + } + } + }; + + /** + * This action refreshes the viewer of the current editor if the editor + * implements {@link org.eclipse.emf.common.ui.viewer.IViewerProvider}. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IAction refreshViewerAction = new Action(EvolutionEditorPlugin.INSTANCE.getString("_UI_RefreshViewer_menu_item")) + { + @Override + public boolean isEnabled() + { + return activeEditorPart instanceof IViewerProvider; + } + + @Override + public void run() + { + if (activeEditorPart instanceof IViewerProvider) + { + Viewer viewer = ((IViewerProvider)activeEditorPart).getViewer(); + if (viewer != null) + { + viewer.refresh(); + } + } + } + }; + + protected IAction assignIDsAction = new IDAction("Assign IDs") + { + @Override + protected void handleID(EModelElement modelElement) + { + IDAnnotation.ensureValue(modelElement); + } + }; + + protected IAction removeIDsAction = new IDAction("Remove IDs") + { + @Override + protected void handleID(EModelElement modelElement) + { + IDAnnotation.removeFrom(modelElement); + } + }; + + /** + * This will contain one {@link org.eclipse.emf.edit.ui.action.CreateChildAction} corresponding to each descriptor + * generated for the current selection by the item provider. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<IAction> createChildActions; + + /** + * This is the menu manager into which menu contribution items should be added for CreateChild actions. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IMenuManager createChildMenuManager; + + /** + * This will contain one {@link org.eclipse.emf.edit.ui.action.CreateSiblingAction} corresponding to each descriptor + * generated for the current selection by the item provider. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<IAction> createSiblingActions; + + /** + * This is the menu manager into which menu contribution items should be added for CreateSibling actions. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IMenuManager createSiblingMenuManager; + + protected SelectionChangedEvent lastSelectionChangedEvent; + + protected ViewerFilterAction showGenericsAction = new ViewerFilterAction(EcoreEditorPlugin.INSTANCE.getString("_UI_ShowGenerics_menu_item"), + IAction.AS_CHECK_BOX) + { + @Override + protected void refreshViewers() + { + if (activeEditorPart instanceof EvolutionEditor) + { + ((EvolutionEditor)activeEditorPart).ecoreItemProviderAdapterFactory.setShowGenerics(isChecked()); + } + + super.refreshViewers(); + + if (lastSelectionChangedEvent != null && activeEditorPart instanceof EvolutionEditor) + { + selectionChanged(lastSelectionChangedEvent); + } + } + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) + { + return isChecked() || !(element instanceof ETypeParameter || element instanceof EGenericType); + } + }; + + /** + * This creates an instance of the contributor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + public EvolutionActionBarContributor() + { + super(ADDITIONS_LAST_STYLE); + loadResourceAction = new LoadResourceAction(); + // validateAction = new ValidateAction(); + liveValidationAction = new DiagnosticDecorator.LiveValidator.LiveValidationAction(EvolutionEditorPlugin.getPlugin().getDialogSettings()); + controlAction = new ControlAction(); + findAction = FindAction.create(); + collapseAllAction = new CollapseAllAction(); + + showGenericsAction.setChecked(Boolean.parseBoolean(EcoreEditorPlugin.getPlugin().getDialogSettings().get("showGenericsAction"))); + } + + public void showGenerics(boolean isChecked) + { + if (showGenericsAction != null) + { + showGenericsAction.setChecked(isChecked); + } + } + + @Override + public void dispose() + { + EcoreEditorPlugin.getPlugin().getDialogSettings().put("showGenericsAction", Boolean.toString(showGenericsAction.isChecked())); + + super.dispose(); + } + + /** + * This adds Separators for editor additions to the tool bar. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + @Override + public void contributeToToolBar(IToolBarManager toolBarManager) + { + super.contributeToToolBar(toolBarManager); + toolBarManager.add(new Separator("evolution-settings")); + toolBarManager.add(new Separator("evolution-additions")); + toolBarManager.add(assignIDsAction); + toolBarManager.add(removeIDsAction); + } + + /** + * This adds to the menu bar a menu and some separators for editor additions, + * as well as the sub-menus for object creation items. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + @Override + public void contributeToMenu(IMenuManager menuManager) + { + super.contributeToMenu(menuManager); + + IMenuManager submenuManager = new MenuManager(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionEditor_menu"), "org.eclipse.emf.cdo.evolutionMenuID"); + menuManager.insertAfter("additions", submenuManager); + submenuManager.add(new Separator("settings")); + submenuManager.add(new Separator("actions")); + submenuManager.add(new Separator("additions")); + submenuManager.add(new Separator("additions-end")); + + // Prepare for CreateChild item addition or removal. + // + createChildMenuManager = new MenuManager(EvolutionEditorPlugin.INSTANCE.getString("_UI_CreateChild_menu_item")); + submenuManager.insertBefore("additions", createChildMenuManager); + + // Prepare for CreateSibling item addition or removal. + // + createSiblingMenuManager = new MenuManager(EvolutionEditorPlugin.INSTANCE.getString("_UI_CreateSibling_menu_item")); + submenuManager.insertBefore("additions", createSiblingMenuManager); + + // Force an update because Eclipse hides empty menus now. + // + submenuManager.addMenuListener(new IMenuListener() + { + public void menuAboutToShow(IMenuManager menuManager) + { + menuManager.updateAll(true); + } + }); + + addGlobalActions(submenuManager); + submenuManager.insertBefore("additions-end", showGenericsAction); + } + + /** + * When the active editor changes, this remembers the change and registers with it as a selection provider. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void setActiveEditorGen(IEditorPart part) + { + super.setActiveEditor(part); + activeEditorPart = part; + + // Switch to the new selection provider. + // + if (selectionProvider != null) + { + selectionProvider.removeSelectionChangedListener(this); + } + if (part == null) + { + selectionProvider = null; + } + else + { + selectionProvider = part.getSite().getSelectionProvider(); + selectionProvider.addSelectionChangedListener(this); + + // Fake a selection changed event to update the menus. + // + if (selectionProvider.getSelection() != null) + { + selectionChanged(new SelectionChangedEvent(selectionProvider, selectionProvider.getSelection())); + } + } + } + + /** + * When the active editor changes, this remembers the change and registers with it as a selection provider. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + @Override + public void setActiveEditor(IEditorPart part) + { + setActiveEditorGen(part); + + if (part instanceof EvolutionEditor) + { + showGenericsAction.addViewer(((EvolutionEditor)part).getViewer()); + showGenericsAction.setEnabled(true); + } + else + { + showGenericsAction.setEnabled(false); + } + } + + /** + * This implements {@link org.eclipse.jface.viewers.ISelectionChangedListener}, + * handling {@link org.eclipse.jface.viewers.SelectionChangedEvent}s by querying for the children and siblings + * that can be added to the selected object and updating the menus accordingly. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void selectionChanged(SelectionChangedEvent event) + { + // Remove any menu items for old selection. + // + if (createChildMenuManager != null) + { + depopulateManager(createChildMenuManager, createChildActions); + } + if (createSiblingMenuManager != null) + { + depopulateManager(createSiblingMenuManager, createSiblingActions); + } + + // Query the new selection for appropriate new child/sibling descriptors + // + Collection<?> newChildDescriptors = null; + Collection<?> newSiblingDescriptors = null; + + ISelection selection = event.getSelection(); + if (selection instanceof IStructuredSelection && ((IStructuredSelection)selection).size() == 1) + { + Object object = ((IStructuredSelection)selection).getFirstElement(); + + EditingDomain domain = ((IEditingDomainProvider)activeEditorPart).getEditingDomain(); + + newChildDescriptors = domain.getNewChildDescriptors(object, null); + newSiblingDescriptors = domain.getNewChildDescriptors(null, object); + } + + // Generate actions for selection; populate and redraw the menus. + // + createChildActions = generateCreateChildActions(newChildDescriptors, selection); + createSiblingActions = generateCreateSiblingActions(newSiblingDescriptors, selection); + + if (createChildMenuManager != null) + { + populateManager(createChildMenuManager, createChildActions, null); + createChildMenuManager.update(true); + } + if (createSiblingMenuManager != null) + { + populateManager(createSiblingMenuManager, createSiblingActions, null); + createSiblingMenuManager.update(true); + } + } + + /** + * This generates a {@link org.eclipse.emf.edit.ui.action.CreateChildAction} for each object in <code>descriptors</code>, + * and returns the collection of these actions. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + protected Collection<IAction> generateCreateChildActions(Collection<?> descriptors, ISelection selection) + { + Collection<IAction> actions = new ArrayList<IAction>(); + if (descriptors != null) + { + for (Object descriptor : descriptors) + { + if (!showGenericsAction.isChecked() && descriptor instanceof CommandParameter) + { + Object feature = ((CommandParameter)descriptor).getFeature(); + if (isGenericFeature(feature)) + { + continue; + } + } + actions.add(new EcoreCreateChildAction(activeEditorPart, selection, descriptor)); + } + } + return actions; + } + + /** + * This generates a {@link org.eclipse.emf.edit.ui.action.CreateSiblingAction} for each object in <code>descriptors</code>, + * and returns the collection of these actions. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + protected Collection<IAction> generateCreateSiblingActions(Collection<?> descriptors, ISelection selection) + { + Collection<IAction> actions = new ArrayList<IAction>(); + if (descriptors != null) + { + for (Object descriptor : descriptors) + { + if (!showGenericsAction.isChecked() && descriptor instanceof CommandParameter) + { + Object feature = ((CommandParameter)descriptor).getFeature(); + if (isGenericFeature(feature)) + { + continue; + } + } + actions.add(new EcoreCreateSiblingAction(activeEditorPart, selection, descriptor)); + } + } + return actions; + } + + protected boolean isGenericFeature(Object feature) + { + return feature == EcorePackage.Literals.ECLASS__EGENERIC_SUPER_TYPES || feature == EcorePackage.Literals.ECLASSIFIER__ETYPE_PARAMETERS + || feature == EcorePackage.Literals.EOPERATION__EGENERIC_EXCEPTIONS || feature == EcorePackage.Literals.EOPERATION__ETYPE_PARAMETERS + || feature == EcorePackage.Literals.ETYPED_ELEMENT__EGENERIC_TYPE; + } + + /** + * This populates the specified <code>manager</code> with {@link org.eclipse.jface.action.ActionContributionItem}s + * based on the {@link org.eclipse.jface.action.IAction}s contained in the <code>actions</code> collection, + * by inserting them before the specified contribution item <code>contributionID</code>. + * If <code>contributionID</code> is <code>null</code>, they are simply added. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + protected void populateManager(IContributionManager manager, Collection<? extends IAction> actions, String contributionID) + { + if (actions != null) + { + // Look for actions that create EAnnotations. + // + Set<IAction> ignoredActions = new HashSet<IAction>(); + Set<IAction> annotationActions = new LinkedHashSet<IAction>(); + for (IAction action : actions) + { + if (action instanceof EObjectProvider) + { + EObjectProvider eObjectProvider = (EObjectProvider)action; + EObject eObject = eObjectProvider.getEObject(); + if (eObject instanceof EAnnotation) + { + annotationActions.add(action); + ignoredActions.add(action); + } + } + } + + // If there is more than one action that creates an annotation... + // + if (annotationActions.size() > 1) + { + // Create a menu manager to group them. + // This assumes the first action is one for the null source. + // + IAction action = annotationActions.iterator().next(); + String actionText = action.getText(); + MenuManager annotationMenuManager = new MenuManager(actionText, action.getImageDescriptor(), "annotations"); + + // Add that menu manager instead of the individual actions. + if (contributionID != null) + { + manager.insertBefore(contributionID, annotationMenuManager); + } + else + { + manager.add(annotationMenuManager); + } + + // Add an item for each annotation action. + // + for (IAction annotationAction : annotationActions) + { + annotationMenuManager.add(annotationAction); + String source = ((EAnnotation)((EObjectProvider)annotationAction).getEObject()).getSource(); + if (source != null) + { + // Set the label to include the source. + // + annotationAction.setText(actionText + " - " + source); + } + } + } + else + { + ignoredActions.clear(); + } + + for (IAction action : actions) + { + if (!ignoredActions.contains(action)) + { + if (contributionID != null) + { + manager.insertBefore(contributionID, action); + } + else + { + manager.add(action); + } + } + } + } + } + + /** + * This removes from the specified <code>manager</code> all {@link org.eclipse.jface.action.ActionContributionItem}s + * based on the {@link org.eclipse.jface.action.IAction}s contained in the <code>actions</code> collection. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void depopulateManager(IContributionManager manager, Collection<? extends IAction> actions) + { + if (actions != null) + { + IContributionItem[] items = manager.getItems(); + for (int i = 0; i < items.length; i++) + { + // Look into SubContributionItems + // + IContributionItem contributionItem = items[i]; + while (contributionItem instanceof SubContributionItem) + { + contributionItem = ((SubContributionItem)contributionItem).getInnerItem(); + } + + // Delete the ActionContributionItems with matching action. + // + if (contributionItem instanceof ActionContributionItem) + { + IAction action = ((ActionContributionItem)contributionItem).getAction(); + if (actions.contains(action)) + { + manager.remove(contributionItem); + } + } + } + } + } + + /** + * This populates the pop-up menu before it appears. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void menuAboutToShow(IMenuManager menuManager) + { + super.menuAboutToShow(menuManager); + MenuManager submenuManager = null; + + submenuManager = new MenuManager(EvolutionEditorPlugin.INSTANCE.getString("_UI_CreateChild_menu_item")); + populateManager(submenuManager, createChildActions, null); + menuManager.insertBefore("edit", submenuManager); + + submenuManager = new MenuManager(EvolutionEditorPlugin.INSTANCE.getString("_UI_CreateSibling_menu_item")); + populateManager(submenuManager, createSiblingActions, null); + menuManager.insertBefore("edit", submenuManager); + } + + /** + * This inserts global actions before the "additions-end" separator. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + protected void addGlobalActions(IMenuManager menuManager) + { + menuManager.insertAfter("additions-end", new Separator("ui-actions")); + menuManager.insertAfter("ui-actions", showPropertiesViewAction); + + refreshViewerAction.setEnabled(refreshViewerAction.isEnabled()); + menuManager.insertAfter("ui-actions", refreshViewerAction); + + super.addGlobalActions(menuManager); + } + + /** + * This ensures that a delete action will clean up all references to deleted objects. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + protected boolean removeAllReferencesOnDelete() + { + return true; + } + + /** + * An interface implemented by {@link EcoreCreateChildAction} and {@link EcoreCreateSiblingAction} to provide access to the data in the descriptor. + */ + public interface EObjectProvider + { + public EObject getEObject(); + } + + /** + * A create child action subclass that provides access to the {@link #descriptor} and specializes {@link #run()} to show the properties view. + */ + public class EcoreCreateChildAction extends CreateChildAction implements EObjectProvider + { + public EcoreCreateChildAction(IWorkbenchPart workbenchPart, ISelection selection, Object descriptor) + { + super(workbenchPart, selection, descriptor); + } + + public EObject getEObject() + { + if (descriptor instanceof CommandParameter) + { + CommandParameter commandParameter = (CommandParameter)descriptor; + return commandParameter.getEValue(); + } + else + { + return null; + } + } + + @Override + public void run() + { + super.run(); + + // This is dispatched twice because the command stack listener dispatches once and then the viewer selection is + // also dispatches once, + // and we need to delay until the selection is established. + // + final Display display = getPage().getWorkbenchWindow().getShell().getDisplay(); + display.asyncExec(new Runnable() + { + public void run() + { + display.asyncExec(new Runnable() + { + public void run() + { + showPropertiesViewAction.run(); + } + }); + } + }); + } + } + + /** + * A create sibling action subclass that provides access to the {@link #descriptor} and specializes {@link #run()} to show the properties view. + */ + public class EcoreCreateSiblingAction extends CreateSiblingAction implements EObjectProvider + { + public EcoreCreateSiblingAction(IWorkbenchPart workbenchPart, ISelection selection, Object descriptor) + { + super(workbenchPart, selection, descriptor); + } + + public EObject getEObject() + { + if (descriptor instanceof CommandParameter) + { + CommandParameter commandParameter = (CommandParameter)descriptor; + return commandParameter.getEValue(); + } + else + { + return null; + } + } + + @Override + public void run() + { + super.run(); + + // This is dispatched twice because the command stack listener dispatches once and then the viewer selection is + // also dispatches once, + // and we need to delay until the selection is established. + // + final Display display = getPage().getWorkbenchWindow().getShell().getDisplay(); + display.asyncExec(new Runnable() + { + public void run() + { + display.asyncExec(new Runnable() + { + public void run() + { + showPropertiesViewAction.run(); + } + }); + } + }); + } + } + + /** + * @author Eike Stepper + */ + private abstract class IDAction extends Action + { + public IDAction(String text) + { + super(text); + } + + @Override + public void run() + { + if (selectionProvider != null) + { + ISelection selection = selectionProvider.getSelection(); + if (selection instanceof IStructuredSelection) + { + IStructuredSelection ssel = (IStructuredSelection)selection; + final Object element = ssel.getFirstElement(); + if (element instanceof EModelElement) + { + final EModelElement rootElement = (EModelElement)element; + + EditingDomain domain = ((IEditingDomainProvider)activeEditorPart).getEditingDomain(); + ChangeCommand command = new ChangeCommand(rootElement) + { + @Override + protected void doExecute() + { + ElementHandler.execute(rootElement, new ElementRunnable() + { + public void run(EModelElement modelElement) + { + handleID(modelElement); + } + }); + } + }; + + domain.getCommandStack().execute(command); + } + } + } + } + + protected abstract void handleID(EModelElement modelElement); + } + +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditor.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditor.java new file mode 100644 index 0000000000..bff82ec24b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditor.java @@ -0,0 +1,3024 @@ +/** + */ +package org.eclipse.emf.cdo.evolution.presentation; + +import org.eclipse.emf.cdo.evolution.Change; +import org.eclipse.emf.cdo.evolution.Evolution; +import org.eclipse.emf.cdo.evolution.EvolutionPackage; +import org.eclipse.emf.cdo.evolution.Release; +import org.eclipse.emf.cdo.evolution.impl.EvolutionImpl; +import org.eclipse.emf.cdo.evolution.presentation.quickfix.DiagnosticResolution; +import org.eclipse.emf.cdo.evolution.presentation.quickfix.QuickFixWizard; +import org.eclipse.emf.cdo.evolution.provider.EvolutionItemProviderAdapterFactory; +import org.eclipse.emf.cdo.evolution.util.DiagnosticID; +import org.eclipse.emf.cdo.evolution.util.ElementHandler; +import org.eclipse.emf.cdo.evolution.util.ValidationContext; +import org.eclipse.emf.cdo.evolution.util.ValidationPhase; + +import org.eclipse.net4j.ui.shared.SharedIcons; +import org.eclipse.net4j.util.ReflectUtil; +import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.WrappedException; + +import org.eclipse.emf.common.command.AbstractCommand; +import org.eclipse.emf.common.command.BasicCommandStack; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.command.CommandStackListener; +import org.eclipse.emf.common.command.UnexecutableCommand; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.ui.ImageURIRegistry; +import org.eclipse.emf.common.ui.MarkerHelper; +import org.eclipse.emf.common.ui.editor.ProblemEditorPart; +import org.eclipse.emf.common.ui.viewer.ColumnViewerInformationControlToolTipSupport; +import org.eclipse.emf.common.ui.viewer.IViewerProvider; +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EGenericType; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.ETypeParameter; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.ecore.util.EContentAdapter; +import org.eclipse.emf.ecore.util.EObjectValidator; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.edit.command.CommandParameter; +import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.edit.domain.IEditingDomainProvider; +import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; +import org.eclipse.emf.edit.provider.IItemPropertySource; +import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; +import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; +import org.eclipse.emf.edit.ui.EMFEditUIPlugin; +import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor; +import org.eclipse.emf.edit.ui.celleditor.AdapterFactoryTreeEditor; +import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter; +import org.eclipse.emf.edit.ui.dnd.LocalTransfer; +import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; +import org.eclipse.emf.edit.ui.provider.DecoratingColumLabelProvider; +import org.eclipse.emf.edit.ui.provider.DelegatingStyledCellLabelProvider; +import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator; +import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator.DiagnosticAdapter; +import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator.LiveValidator; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; +import org.eclipse.emf.edit.ui.provider.PropertySource; +import org.eclipse.emf.edit.ui.provider.UnwrappingSelectionProvider; +import org.eclipse.emf.edit.ui.util.EditUIMarkerHelper; +import org.eclipse.emf.edit.ui.util.EditUIUtil; +import org.eclipse.emf.edit.ui.util.FindAndReplaceTarget; +import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Adapters; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.util.LocalSelectionTransfer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IOpenListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.OpenEvent; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.dialogs.SaveAsDialog; +import org.eclipse.ui.ide.IGotoMarker; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.part.MultiPageEditorPart; +import org.eclipse.ui.progress.IWorkbenchSiteProgressService; +import org.eclipse.ui.views.contentoutline.ContentOutline; +import org.eclipse.ui.views.contentoutline.ContentOutlinePage; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySheetEntry; +import org.eclipse.ui.views.properties.IPropertySheetPage; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.PropertySheet; +import org.eclipse.ui.views.properties.PropertySheetPage; +import org.eclipse.ui.views.properties.PropertySheetSorter; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EventObject; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * This is an example of a Evolution model editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ +public class EvolutionEditor extends MultiPageEditorPart implements IEditingDomainProvider, ISelectionProvider, IMenuListener, IViewerProvider, IGotoMarker +{ + /** + * This keeps track of the editing domain that is used to track all changes to the model. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected AdapterFactoryEditingDomain editingDomain; + + /** + * This is the one adapter factory used for providing views of the model. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected ComposedAdapterFactory adapterFactory; + + /** + * This is the content outline page. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IContentOutlinePage contentOutlinePage; + + /** + * This is a kludge... + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IStatusLineManager contentOutlineStatusLineManager; + + /** + * This is the content outline page's viewer. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected TreeViewer contentOutlineViewer; + + /** + * This is the property sheet page. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected List<PropertySheetPage> propertySheetPages = new ArrayList<PropertySheetPage>(); + + /** + * This is the viewer that shadows the selection in the content outline. + * The parent relation must be correctly defined for this to work. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected TreeViewer selectionViewer; + + /** + * This keeps track of the active content viewer, which may be either one of the viewers in the pages or the content outline viewer. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Viewer currentViewer; + + /** + * This listens to which ever viewer is active. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected ISelectionChangedListener selectionChangedListener; + + /** + * This keeps track of all the {@link org.eclipse.jface.viewers.ISelectionChangedListener}s that are listening to this editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>(); + + /** + * This keeps track of the selection of the editor as a whole. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected ISelection editorSelection = StructuredSelection.EMPTY; + + /** + * The MarkerHelper is responsible for creating workspace resource markers presented + * in Eclipse's Problems View. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected MarkerHelper markerHelper = new EditUIMarkerHelper(); + + /** + * This listens for when the outline becomes active + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IPartListener partListener = new IPartListener() + { + public void partActivated(IWorkbenchPart p) + { + if (p instanceof ContentOutline) + { + if (((ContentOutline)p).getCurrentPage() == contentOutlinePage) + { + getActionBarContributor().setActiveEditor(EvolutionEditor.this); + + setCurrentViewer(contentOutlineViewer); + } + } + else if (p instanceof PropertySheet) + { + if (propertySheetPages.contains(((PropertySheet)p).getCurrentPage())) + { + getActionBarContributor().setActiveEditor(EvolutionEditor.this); + handleActivate(); + } + } + else if (p == EvolutionEditor.this) + { + handleActivate(); + } + } + + public void partBroughtToTop(IWorkbenchPart p) + { + // Ignore. + } + + public void partClosed(IWorkbenchPart p) + { + // Ignore. + } + + public void partDeactivated(IWorkbenchPart p) + { + // Ignore. + } + + public void partOpened(IWorkbenchPart p) + { + // Ignore. + } + }; + + /** + * Resources that have been removed since last activation. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<Resource> removedResources = new ArrayList<Resource>(); + + /** + * Resources that have been changed since last activation. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<Resource> changedResources = new ArrayList<Resource>(); + + /** + * Resources that have been saved. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<Resource> savedResources = new ArrayList<Resource>(); + + /** + * Map to store the diagnostic associated with a resource. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Map<Resource, Diagnostic> resourceToDiagnosticMap = new LinkedHashMap<Resource, Diagnostic>(); + + /** + * Controls whether the problem indication should be updated. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected boolean updateProblemIndication = true; + + /** + * Adapter used to update the problem indication when resources are demanded loaded. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EContentAdapter problemIndicationAdapter = new EContentAdapter() + { + protected boolean dispatching; + + @Override + public void notifyChanged(Notification notification) + { + if (notification.getNotifier() instanceof Resource) + { + switch (notification.getFeatureID(Resource.class)) + { + case Resource.RESOURCE__IS_LOADED: + case Resource.RESOURCE__ERRORS: + case Resource.RESOURCE__WARNINGS: + { + Resource resource = (Resource)notification.getNotifier(); + Diagnostic diagnostic = analyzeResourceProblems(resource, null); + if (diagnostic.getSeverity() != Diagnostic.OK) + { + resourceToDiagnosticMap.put(resource, diagnostic); + } + else + { + resourceToDiagnosticMap.remove(resource); + } + dispatchUpdateProblemIndication(); + break; + } + } + } + else + { + super.notifyChanged(notification); + } + } + + protected void dispatchUpdateProblemIndication() + { + if (updateProblemIndication && !dispatching) + { + dispatching = true; + getSite().getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + dispatching = false; + updateProblemIndication(); + } + }); + } + } + + @Override + protected void setTarget(Resource target) + { + basicSetTarget(target); + } + + @Override + protected void unsetTarget(Resource target) + { + basicUnsetTarget(target); + resourceToDiagnosticMap.remove(target); + dispatchUpdateProblemIndication(); + } + }; + + /** + * This listens for workspace changes. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IResourceChangeListener resourceChangeListener = new IResourceChangeListener() + { + public void resourceChanged(IResourceChangeEvent event) + { + IResourceDelta delta = event.getDelta(); + try + { + class ResourceDeltaVisitor implements IResourceDeltaVisitor + { + protected ResourceSet resourceSet = editingDomain.getResourceSet(); + + protected Collection<Resource> changedResources = new ArrayList<Resource>(); + + protected Collection<Resource> removedResources = new ArrayList<Resource>(); + + public boolean visit(final IResourceDelta delta) + { + if (delta.getResource().getType() == IResource.FILE) + { + if (delta.getKind() == IResourceDelta.REMOVED || delta.getKind() == IResourceDelta.CHANGED) + { + final Resource resource = resourceSet.getResource(URI.createPlatformResourceURI(delta.getFullPath().toString(), true), false); + if (resource != null) + { + if (delta.getKind() == IResourceDelta.REMOVED) + { + removedResources.add(resource); + } + else + { + if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) + { + DiagnosticDecorator.Styled.DiagnosticAdapter.update(resource, + markerHelper.getMarkerDiagnostics(resource, (IFile)delta.getResource(), false)); + } + if ((delta.getFlags() & IResourceDelta.CONTENT) != 0) + { + if (!savedResources.remove(resource)) + { + changedResources.add(resource); + } + } + } + } + } + return false; + } + + return true; + } + + public Collection<Resource> getChangedResources() + { + return changedResources; + } + + public Collection<Resource> getRemovedResources() + { + return removedResources; + } + } + + final ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(); + delta.accept(visitor); + + if (!visitor.getRemovedResources().isEmpty()) + { + getSite().getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + removedResources.addAll(visitor.getRemovedResources()); + if (!isDirty()) + { + getSite().getPage().closeEditor(EvolutionEditor.this, false); + } + } + }); + } + + if (!visitor.getChangedResources().isEmpty()) + { + getSite().getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + changedResources.addAll(visitor.getChangedResources()); + if (getSite().getPage().getActiveEditor() == EvolutionEditor.this) + { + handleActivate(); + } + } + }); + } + } + catch (CoreException exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + } + } + }; + + protected EcoreItemProviderAdapterFactory ecoreItemProviderAdapterFactory; + + private TableViewer problemViewer; + + private final Set<Object> readOnlyObjects = new HashSet<Object>(); + + private Evolution evolution; + + private Diagnostic[] allDiagnostics; + + /** + * Handles activation of the editor or it's associated views. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void handleActivate() + { + // Recompute the read only state. + // + if (editingDomain.getResourceToReadOnlyMap() != null) + { + editingDomain.getResourceToReadOnlyMap().clear(); + + // Refresh any actions that may become enabled or disabled. + // + setSelection(getSelection()); + } + + if (!removedResources.isEmpty()) + { + if (handleDirtyConflict()) + { + getSite().getPage().closeEditor(EvolutionEditor.this, false); + } + else + { + removedResources.clear(); + changedResources.clear(); + savedResources.clear(); + } + } + else if (!changedResources.isEmpty()) + { + changedResources.removeAll(savedResources); + handleChangedResources(); + changedResources.clear(); + savedResources.clear(); + } + } + + /** + * Handles what to do with changed resources on activation. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void handleChangedResources() + { + if (!changedResources.isEmpty() && (!isDirty() || handleDirtyConflict())) + { + ResourceSet resourceSet = editingDomain.getResourceSet(); + if (isDirty()) + { + changedResources.addAll(resourceSet.getResources()); + } + editingDomain.getCommandStack().flush(); + + updateProblemIndication = false; + for (Resource resource : changedResources) + { + if (resource.isLoaded()) + { + resource.unload(); + try + { + resource.load(resourceSet.getLoadOptions()); + } + catch (IOException exception) + { + if (!resourceToDiagnosticMap.containsKey(resource)) + { + resourceToDiagnosticMap.put(resource, analyzeResourceProblems(resource, exception)); + } + } + } + } + + if (AdapterFactoryEditingDomain.isStale(editorSelection)) + { + setSelection(StructuredSelection.EMPTY); + } + + updateProblemIndication = true; + updateProblemIndication(); + } + } + + /** + * Updates the problems indication with the information described in the specified diagnostic. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void updateProblemIndication() + { + if (updateProblemIndication) + { + BasicDiagnostic diagnostic = new BasicDiagnostic(Diagnostic.OK, "org.eclipse.emf.cdo.evolution.editor", 0, null, + new Object[] { editingDomain.getResourceSet() }); + for (Diagnostic childDiagnostic : resourceToDiagnosticMap.values()) + { + if (childDiagnostic.getSeverity() != Diagnostic.OK) + { + diagnostic.add(childDiagnostic); + } + } + + int lastEditorPage = getPageCount() - 1; + if (lastEditorPage >= 0 && getEditor(lastEditorPage) instanceof ProblemEditorPart) + { + ((ProblemEditorPart)getEditor(lastEditorPage)).setDiagnostic(diagnostic); + if (diagnostic.getSeverity() != Diagnostic.OK) + { + setActivePage(lastEditorPage); + } + } + else if (diagnostic.getSeverity() != Diagnostic.OK) + { + ProblemEditorPart problemEditorPart = new ProblemEditorPart(); + problemEditorPart.setDiagnostic(diagnostic); + problemEditorPart.setMarkerHelper(markerHelper); + try + { + addPage(++lastEditorPage, problemEditorPart, getEditorInput()); + setPageText(lastEditorPage, problemEditorPart.getPartName()); + setActivePage(lastEditorPage); + showTabs(); + } + catch (PartInitException exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + } + } + + if (markerHelper.hasMarkers(editingDomain.getResourceSet())) + { + try + { + markerHelper.updateMarkers(diagnostic); + } + catch (CoreException exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + } + } + } + } + + /** + * Shows a dialog that asks if conflicting changes should be discarded. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected boolean handleDirtyConflict() + { + return MessageDialog.openQuestion(getSite().getShell(), getString("_UI_FileConflict_label"), getString("_WARN_FileConflict")); + } + + /** + * This creates a model editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EvolutionEditor() + { + super(); + initializeEditingDomain(); + } + + /** + * This sets up the editing domain for the model editor. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + protected void initializeEditingDomain() + { + // Create an adapter factory that yields item providers. + // + adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); + + adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory()); + adapterFactory.addAdapterFactory(new EvolutionItemProviderAdapterFactory()); + ecoreItemProviderAdapterFactory = new EcoreItemProviderAdapterFactory(); + adapterFactory.addAdapterFactory(ecoreItemProviderAdapterFactory); + adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); + + // Create the command stack that will notify this editor as commands are executed. + // + BasicCommandStack commandStack = new BasicCommandStack() + { + @Override + public void execute(Command command) + { + // Cancel live validation before executing a command that will trigger a new round of validation. + // + if (!(command instanceof AbstractCommand.NonDirtying)) + { + DiagnosticDecorator.Styled.cancel(editingDomain); + } + super.execute(command); + } + }; + + // Add a listener to set the most recent command's affected objects to be the selection of the viewer with focus. + // + commandStack.addCommandStackListener(new CommandStackListener() + { + public void commandStackChanged(final EventObject event) + { + ((EvolutionImpl)evolution).invalidateChange(); + + getContainer().getDisplay().asyncExec(new Runnable() + { + public void run() + { + firePropertyChange(IEditorPart.PROP_DIRTY); + + // Try to select the affected objects. + // + Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand(); + if (mostRecentCommand != null) + { + setSelectionToViewer(mostRecentCommand.getAffectedObjects()); + } + for (Iterator<PropertySheetPage> i = propertySheetPages.iterator(); i.hasNext();) + { + PropertySheetPage propertySheetPage = i.next(); + if (propertySheetPage.getControl().isDisposed()) + { + i.remove(); + } + else + { + propertySheetPage.refresh(); + } + } + } + }); + } + }); + + // Create the editing domain with a special command stack. + // + editingDomain = new AdapterFactoryEditingDomain(adapterFactory, commandStack, new HashMap<Resource, Boolean>()) + { + @Override + public Command createCommand(Class<? extends Command> commandClass, CommandParameter commandParameter) + { + Collection<?> collection = commandParameter.getCollection(); + if (collection != null && !collection.isEmpty()) + { + Object value = collection.iterator().next(); + if (isReadOnlyObject(value)) + { + return UnexecutableCommand.INSTANCE; + } + } + + return super.createCommand(commandClass, commandParameter); + } + }; + } + + protected boolean isReadOnlyObject(Object object) + { + if (object instanceof Release) + { + return true; + } + + if (object instanceof Change) + { + return true; + } + + if (readOnlyObjects.contains(object)) + { + return true; + } + + if (object instanceof EModelElement) + { + EModelElement modelElement = (EModelElement)object; + + if (evolution.containsElement(modelElement)) + { + return false; + } + + for (Release release : evolution.getReleases()) + { + if (release.containsElement(modelElement)) + { + readOnlyObjects.add(modelElement); + return true; + } + } + } + + return false; + } + + /** + * This is here for the listener to be able to call it. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + protected void firePropertyChange(int action) + { + super.firePropertyChange(action); + } + + /** + * This sets the selection into whichever viewer is active. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void setSelectionToViewer(Collection<?> collection) + { + final Collection<?> theSelection = collection; + // Make sure it's okay. + // + if (theSelection != null && !theSelection.isEmpty()) + { + Runnable runnable = new Runnable() + { + public void run() + { + // Try to select the items in the current content viewer of the editor. + // + if (currentViewer != null) + { + currentViewer.setSelection(new StructuredSelection(theSelection.toArray()), true); + } + } + }; + getSite().getShell().getDisplay().asyncExec(runnable); + } + } + + /** + * This returns the editing domain as required by the {@link IEditingDomainProvider} interface. + * This is important for implementing the static methods of {@link AdapterFactoryEditingDomain} + * and for supporting {@link org.eclipse.emf.edit.ui.action.CommandAction}. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EditingDomain getEditingDomain() + { + return editingDomain; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public class ReverseAdapterFactoryContentProvider extends AdapterFactoryContentProvider + { + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public ReverseAdapterFactoryContentProvider(AdapterFactory adapterFactory) + { + super(adapterFactory); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public Object[] getElements(Object object) + { + Object parent = super.getParent(object); + return (parent == null ? Collections.EMPTY_SET : Collections.singleton(parent)).toArray(); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public Object[] getChildren(Object object) + { + Object parent = super.getParent(object); + return (parent == null ? Collections.EMPTY_SET : Collections.singleton(parent)).toArray(); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public boolean hasChildren(Object object) + { + Object parent = super.getParent(object); + return parent != null; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public Object getParent(Object object) + { + return null; + } + } + + /** + * This makes sure that one content viewer, either for the current page or the outline view, if it has focus, + * is the current one. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void setCurrentViewer(Viewer viewer) + { + // If it is changing... + // + if (currentViewer != viewer) + { + if (selectionChangedListener == null) + { + // Create the listener on demand. + // + selectionChangedListener = new ISelectionChangedListener() + { + // This just notifies those things that are affected by the section. + // + public void selectionChanged(SelectionChangedEvent selectionChangedEvent) + { + setSelection(selectionChangedEvent.getSelection()); + } + }; + } + + // Stop listening to the old one. + // + if (currentViewer != null) + { + currentViewer.removeSelectionChangedListener(selectionChangedListener); + } + + // Start listening to the new one. + // + if (viewer != null) + { + viewer.addSelectionChangedListener(selectionChangedListener); + } + + // Remember it. + // + currentViewer = viewer; + + // Set the editors selection based on the current viewer's selection. + // + setSelection(currentViewer == null ? StructuredSelection.EMPTY : currentViewer.getSelection()); + } + } + + /** + * This returns the viewer as required by the {@link IViewerProvider} interface. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public Viewer getViewer() + { + return currentViewer; + } + + /** + * This creates a context menu for the viewer and adds a listener as well registering the menu for extension. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + protected void createContextMenuFor(StructuredViewer viewer) + { + MenuManager contextMenu = new MenuManager("#PopUp"); + contextMenu.add(new Separator("additions")); + contextMenu.setRemoveAllWhenShown(true); + contextMenu.addMenuListener(this); + Menu menu = contextMenu.createContextMenu(viewer.getControl()); + viewer.getControl().setMenu(menu); + getSite().registerContextMenu(contextMenu, new UnwrappingSelectionProvider(viewer)); + + int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK; + Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance(), LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance() }; + viewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(viewer)); + viewer.addDropSupport(dndOperations, transfers, new EditingDomainViewerDropAdapter(editingDomain, viewer) + { + @Override + public void dropAccept(DropTargetEvent event) + { + super.dropAccept(event); + } + + @Override + public void drop(DropTargetEvent event) + { + super.drop(event); + } + }); + } + + /** + * This is the method called to load a resource into the editing domain's resource set based on the editor's input. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void createModelGen() + { + URI resourceURI = EditUIUtil.getURI(getEditorInput(), editingDomain.getResourceSet().getURIConverter()); + Exception exception = null; + Resource resource = null; + try + { + // Load the resource through the editing domain. + // + resource = editingDomain.getResourceSet().getResource(resourceURI, true); + } + catch (Exception e) + { + exception = e; + resource = editingDomain.getResourceSet().getResource(resourceURI, false); + } + + Diagnostic diagnostic = analyzeResourceProblems(resource, exception); + if (diagnostic.getSeverity() != Diagnostic.OK) + { + resourceToDiagnosticMap.put(resource, analyzeResourceProblems(resource, exception)); + } + editingDomain.getResourceSet().eAdapters().add(problemIndicationAdapter); + } + + /** + * This is the method called to load a resource into the editing domain's resource set based on the editor's input. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + public void createModel() + { + createModelGen(); + + ResourceSet resourceSet = editingDomain.getResourceSet(); + evolution = EvolutionImpl.get(resourceSet); + if (evolution != null) + { + if (hasGenerics(evolution)) + { + ((EvolutionActionBarContributor)getActionBarContributor()).showGenerics(true); + } + } + } + + private boolean hasGenerics(Evolution evolution) + { + if (hasGenerics(evolution.getRootPackages())) + { + return true; + } + + for (Release release : evolution.getReleases()) + { + if (hasGenerics(release.getRootPackages())) + { + return true; + } + } + + return false; + } + + private boolean hasGenerics(EList<EPackage> rootPackages) + { + for (EPackage rootPackage : rootPackages) + { + for (Iterator<EObject> i = rootPackage.eAllContents(); i.hasNext();) + { + EObject eObject = i.next(); + if (eObject instanceof ETypeParameter || eObject instanceof EGenericType && !((EGenericType)eObject).getETypeArguments().isEmpty()) + { + return true; + } + } + } + + return false; + } + + /** + * Returns a diagnostic describing the errors and warnings listed in the resource + * and the specified exception (if any). + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public Diagnostic analyzeResourceProblems(Resource resource, Exception exception) + { + boolean hasErrors = !resource.getErrors().isEmpty(); + if (hasErrors || !resource.getWarnings().isEmpty()) + { + BasicDiagnostic basicDiagnostic = new BasicDiagnostic(hasErrors ? Diagnostic.ERROR : Diagnostic.WARNING, "org.eclipse.emf.cdo.evolution.editor", 0, + getString("_UI_CreateModelError_message", resource.getURI()), new Object[] { exception == null ? (Object)resource : exception }); + basicDiagnostic.merge(EcoreUtil.computeDiagnostic(resource, true)); + return basicDiagnostic; + } + else if (exception != null) + { + return new BasicDiagnostic(Diagnostic.ERROR, "org.eclipse.emf.cdo.evolution.editor", 0, getString("_UI_CreateModelError_message", resource.getURI()), + new Object[] { exception }); + } + else + { + return Diagnostic.OK_INSTANCE; + } + } + + /** + * @author Eike Stepper + */ + private static class PhasedLiveValidator extends LiveValidator + { + public PhasedLiveValidator(EditingDomain editingDomain, IDialogSettings dialogSettings) + { + super(editingDomain, dialogSettings); + } + + @Override + public void scheduleValidation() + { + if (validationJob == null && (dialogSettings == null || dialogSettings.getBoolean(LiveValidationAction.LIVE_VALIDATOR_DIALOG_SETTINGS_KEY))) + { + validationJob = new Job("Validation Job") + { + @Override + protected IStatus run(final IProgressMonitor monitor) + { + try + { + Diagnostician diagnostician = new Diagnostician() + { + @Override + public String getObjectLabel(EObject eObject) + { + String text = labelProvider != null && eObject.eIsProxy() ? ((InternalEObject)eObject).eProxyURI().toString() + : labelProvider.getText(eObject); + if (text == null || text.length() == 0) + { + text = "<i>null</i>"; + } + else + { + text = DiagnosticDecorator.escapeContent(text); + } + Image image = labelProvider != null ? labelProvider.getImage(eObject) : null; + if (image != null) + { + URI imageURI = ImageURIRegistry.INSTANCE.getImageURI(image); + return DiagnosticDecorator.enquote("<img src='" + imageURI + "'/> " + text); + } + else + { + return text; + } + } + + @Override + public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) + { + if (monitor.isCanceled()) + { + throw new RuntimeException(); + } + + monitor.worked(1); + return super.validate(eClass, eObject, diagnostics, context); + } + + @Override + protected boolean doValidateContents(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) + { + Evolution evolution; + List<? extends EObject> eContents; + + ValidationContext validationContext = ValidationContext.getFrom(context); + if (validationContext != null) + { + ValidationPhase phase = validationContext.getPhase(); + evolution = validationContext.getEvolution(); + eContents = phase.getContentsToValidate(this, evolution, eObject, context); + } + else + { + evolution = null; + eContents = eObject.eContents(); + } + + boolean result = true; + for (EObject child : eContents) + { + Resource resource = child.eResource(); + if (resource == null && evolution != null) + { + // Change objects are not contained in a resource. Use the evolution's resource. + resource = evolution.eResource(); + } + + DiagnosticChain resourceDiagnostic = resource != null && validationContext != null + ? validationContext.getResourceDiagnostics().get(resource) + : null; + + result &= validate(child, resourceDiagnostic, context); + } + + return result; + } + }; + + final ResourceSet resourceSet = editingDomain.getResourceSet(); + + Map<Object, Object> context = diagnostician.createDefaultContext(); + context.put(EObjectValidator.ROOT_OBJECT, new Object()); // Disable circular containment validation. + + { /////////////////////////////////////////////////////////////////////////////// + + Evolution evolution = EvolutionImpl.get(resourceSet); + ValidationContext validationContext = new ValidationContext(evolution); + validationContext.putInto(context); + + int count = 0; + for (ValidationPhase phase : ValidationPhase.values()) + { + validationContext.setPhase(phase); + + // int xxx; + // System.out.println("Count " + phase); + + count += countObjects(diagnostician, evolution, validationContext, context, monitor); + } + + scheduledResources.clear(); + monitor.beginTask("", count); + + Map<Resource, BasicDiagnostic> resourceDiagnostics = validationContext.getResourceDiagnostics(); + final BasicDiagnostic rootDiagnostic = new BasicDiagnostic(EObjectValidator.DIAGNOSTIC_SOURCE, 0, + EMFEditUIPlugin.INSTANCE.getString("_UI_DiagnosisOfNObjects_message", new String[] { "" + resourceDiagnostics.size() }), + new Object[] { resourceSet }); + + for (BasicDiagnostic resourceDiagnostic : resourceDiagnostics.values()) + { + rootDiagnostic.add(resourceDiagnostic); + } + + BasicDiagnostic modelSetResourceDiagnostic = resourceDiagnostics.get(evolution.eResource()); + + for (ValidationPhase phase : ValidationPhase.values()) + { + validationContext.setPhase(phase); + + // int xxx; + // System.out.println("Validate " + phase); + + monitor + .setTaskName(EvolutionEditorPlugin.INSTANCE.getString("_UI_ValidatingPhase_message", new Object[] { Integer.toString(phase.ordinal()) })); + + boolean valid = diagnostician.validate(evolution, modelSetResourceDiagnostic, context); + if (!valid) + { + break; + } + } + + if (monitor.isCanceled()) + { + throw new RuntimeException(); + } + + monitor.worked(1); + + DiagnosticAdapter.update(resourceSet, rootDiagnostic); + + } /////////////////////////////////////////////////////////////////////////////// + + Display.getDefault().asyncExec(new Runnable() + { + public void run() + { + validationJob = null; + if (!monitor.isCanceled() && !scheduledResources.isEmpty()) + { + PhasedLiveValidator.this.scheduleValidation(); + } + } + }); + + return Status.OK_STATUS; + } + catch (RuntimeException exception) + { + int xxx; + exception.printStackTrace(); + + validationJob = null; + return Status.CANCEL_STATUS; + } + } + + private int countObjects(Diagnostician diagnostician, EObject eObject, ValidationContext validationContext, Map<Object, Object> context, + IProgressMonitor monitor) + { + if (monitor.isCanceled()) + { + throw new RuntimeException(); + } + + for (EReference eReference : eObject.eClass().getEAllReferences()) + { + if (monitor.isCanceled()) + { + throw new RuntimeException(); + } + + if (eReference == EvolutionPackage.Literals.MODEL_SET__CHANGE) + { + continue; + } + + if (eReference.isContainment() || eReference.isContainer()) + { + continue; + } + + // Resolve all proxies. + if (eReference.isResolveProxies()) + { + Object value = eObject.eGet(eReference, true); + if (eReference.isMany()) + { + @SuppressWarnings("unchecked") + List<EObject> list = (List<EObject>)value; + + for (@SuppressWarnings("unused") + EObject element : list) + { + if (monitor.isCanceled()) + { + throw new RuntimeException(); + } + } + } + } + } + + Resource resource = eObject.eResource(); + if (resource != null) + { + Map<Resource, BasicDiagnostic> resourceDiagnostics = validationContext.getResourceDiagnostics(); + if (!resourceDiagnostics.containsKey(resource)) + { + BasicDiagnostic diagnostic = new BasicDiagnostic(EObjectValidator.DIAGNOSTIC_SOURCE, 0, + EMFEditUIPlugin.INSTANCE.getString("_UI_DiagnosisOfNObjects_message", new String[] { "1" }), new Object[] { resource }); + resourceDiagnostics.put(resource, diagnostic); + } + } + + Evolution evolution = validationContext.getEvolution(); + ValidationPhase phase = validationContext.getPhase(); + int count = 1; + + for (EObject child : phase.getContentsToValidate(diagnostician, evolution, eObject, context)) + { + count += countObjects(diagnostician, child, validationContext, context, monitor); + } + + return count; + } + }; + + validationJob.setPriority(Job.DECORATE); + validationJob.schedule(500); + } + } + } + + /** + * @author Eike Stepper + */ + private static class DiagnosticContentProvider implements IStructuredContentProvider + { + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + } + + public Object[] getElements(Object inputElement) + { + List<Diagnostic> result = new ArrayList<Diagnostic>(); + + @SuppressWarnings("unchecked") + List<Diagnostic> diagnostics = (List<Diagnostic>)inputElement; + for (Diagnostic diagnostic : diagnostics) + { + collectDiagnostics(diagnostic, result); + } + + return result.toArray(new Diagnostic[result.size()]); + } + + private void collectDiagnostics(Diagnostic diagnostic, List<Diagnostic> result) + { + if (isRelevant(diagnostic)) + { + result.add(diagnostic); + } + + for (Diagnostic child : diagnostic.getChildren()) + { + collectDiagnostics(child, result); + } + } + + private boolean isRelevant(Diagnostic diagnostic) + { + // if (diagnostic.getSeverity() != Diagnostic.ERROR) + // { + // return false; + // } + + List<?> data = diagnostic.getData(); + if (data.isEmpty()) + { + return false; + } + + if (data.get(0) instanceof Resource) + { + return false; + } + + return true; + } + + public void dispose() + { + } + } + + /** + * This is the method used by the framework to install your own controls. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + @Override + public void createPages() + { + // Creates the model from the editor input + // + createModel(); + + // Only creates the other pages if there is something that can be edited + // + if (!getEditingDomain().getResourceSet().getResources().isEmpty()) + { + // Create a page for the selection tree view. + // + + SashForm mainSash = new SashForm(getContainer(), SWT.VERTICAL); + mainSash.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL)); + + selectionViewer = createSelectionViewer(mainSash); + TableViewer problemViewer = createProblemViewer(mainSash); + + mainSash.setWeights(new int[] { 70, 30 }); + + int pageIndex = addPage(mainSash); + setPageText(pageIndex, getString("_UI_SelectionPage_label")); + + getSite().getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + if (!getContainer().isDisposed()) + { + setActivePage(0); + } + } + }); + + this.problemViewer = problemViewer; + } + + // Ensures that this editor will only display the page's tab + // area if there are more than one page + // + getContainer().addControlListener(new ControlAdapter() + { + boolean guard = false; + + @Override + public void controlResized(ControlEvent event) + { + if (!guard) + { + guard = true; + hideTabs(); + guard = false; + } + } + }); + + getSite().getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + updateProblemIndication(); + } + }); + } + + private TreeViewer createSelectionViewer(Composite parent) + { + Tree tree = new Tree(parent, SWT.MULTI); + TreeViewer selectionViewer = new TreeViewer(tree); + setCurrentViewer(selectionViewer); + + DiagnosticDecorator diagnosticDecorator = new DiagnosticDecorator.Styled(editingDomain, selectionViewer, + EvolutionEditorPlugin.getPlugin().getDialogSettings()) + { + @Override + protected void redecorate() + { + super.redecorate(); + handleDiagnostics(diagnostics); + } + + @Override + protected LiveValidator getLiveValidator() + { + if (liveValidator == null && editingDomain != null) + { + Field field = ReflectUtil.getField(DiagnosticDecorator.class, "LIVE_VALIDATORS"); + + @SuppressWarnings("unchecked") + Map<EditingDomain, LiveValidator> LIVE_VALIDATORS = (Map<EditingDomain, LiveValidator>)ReflectUtil.getValue(field, null); + + liveValidator = LIVE_VALIDATORS.get(editingDomain); + if (liveValidator == null) + { + liveValidator = new PhasedLiveValidator(editingDomain, dialogSettings); + + LIVE_VALIDATORS.put(editingDomain, liveValidator); + } + + liveValidator.register(this); + } + + return liveValidator; + } + }; + + selectionViewer.setUseHashlookup(true); + selectionViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory)); + selectionViewer.setLabelProvider(new DelegatingStyledCellLabelProvider.FontAndColorProvider(new DecoratingColumLabelProvider.StyledLabelProvider( + new AdapterFactoryLabelProvider.StyledLabelProvider(adapterFactory, selectionViewer), diagnosticDecorator))); + selectionViewer.setInput(editingDomain.getResourceSet().getResources().get(0)); + selectionViewer.setSelection(new StructuredSelection(editingDomain.getResourceSet().getResources().get(0)), true); + + new AdapterFactoryTreeEditor(selectionViewer.getTree(), adapterFactory); + new ColumnViewerInformationControlToolTipSupport(selectionViewer, + new DiagnosticDecorator.Styled.EditingDomainLocationListener(editingDomain, selectionViewer)); + + createContextMenuFor(selectionViewer); + return selectionViewer; + } + + private TableViewer createProblemViewer(Composite parent) + { + final TableViewer problemViewer = new TableViewer(parent, SWT.MULTI); + problemViewer.setContentProvider(new DiagnosticContentProvider()); + problemViewer.setInput(Collections.emptyList()); + + Table problemTable = problemViewer.getTable(); + problemTable.setHeaderVisible(true); + problemTable.setLinesVisible(true); + + createDiagnosticMessageColumn(problemViewer); + createDiagnosticElementColumn(problemViewer, adapterFactory); + createDiagnosticResourceColumn(problemViewer, adapterFactory); + // createDiagnosticIDColumn(problemViewer); + + // { + // TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + // tableViewerColumn.setLabelProvider(new ColumnLabelProvider() + // { + // @Override + // public String getText(Object element) + // { + // return ((Diagnostic)element).getSource(); + // } + // }); + // + // TableColumn tableColumn = tableViewerColumn.getColumn(); + // tableColumn.setResizable(true); + // tableColumn.setAlignment(SWT.LEFT); + // tableColumn.setWidth(200); + // tableColumn.setText("Source"); + // } + // + // { + // TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + // tableViewerColumn.setLabelProvider(new ColumnLabelProvider() + // { + // + // @Override + // public String getText(Object element) + // { + // return Integer.toString(((Diagnostic)element).getCode()); + // } + // }); + // + // TableColumn tableColumn = tableViewerColumn.getColumn(); + // tableColumn.setResizable(true); + // tableColumn.setAlignment(SWT.LEFT); + // tableColumn.setWidth(70); + // tableColumn.setText("Code"); + // } + // + // { + // TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + // tableViewerColumn.setLabelProvider(new ColumnLabelProvider() + // { + // @Override + // public String getText(Object element) + // { + // StringBuilder builder = new StringBuilder(); + // + // List<?> data = ((Diagnostic)element).getData(); + // for (Object object : data) + // { + // if (builder.length() != 0) + // { + // builder.append(", "); + // } + // + // if (object instanceof Resource) + // { + // Resource resource = (Resource)object; + // builder.append("Resource["); + // builder.append(resource.getURI()); + // builder.append("]"); + // } + // else if (object instanceof ENamedElement) + // { + // ENamedElement namedElement = (ENamedElement)object; + // builder.append(namedElement.getName()); + // } + // else if (object instanceof EObject) + // { + // EObject eObject = (EObject)object; + // builder.append(eObject.eClass().getName()); + // } + // else + // { + // builder.append(String.valueOf(object)); + // } + // } + // + // return builder.toString(); + // } + // }); + // + // TableColumn tableColumn = tableViewerColumn.getColumn(); + // tableColumn.setResizable(true); + // tableColumn.setAlignment(SWT.LEFT); + // tableColumn.setWidth(400); + // tableColumn.setText("Data"); + // } + + problemTable.addKeyListener(new KeyAdapter() + { + @Override + public void keyPressed(KeyEvent e) + { + if (e.stateMask == SWT.CTRL && e.character == '1') + { + showQuickFixes(); + } + } + }); + + problemViewer.addOpenListener(new IOpenListener() + { + public void open(OpenEvent event) + { + IStructuredSelection selection = (IStructuredSelection)event.getSelection(); + Object element = selection.getFirstElement(); + if (element instanceof Diagnostic) + { + List<?> data = ((Diagnostic)element).getData(); + int size = data.size(); + if (size != 0) + { + List<Object> list = new ArrayList<Object>(size); + for (Object object : data) + { + Object wrapper = editingDomain.getWrapper(object); + list.add(wrapper); + } + + setSelectionToViewer(list); + } + } + } + }); + + return problemViewer; + } + + public static TableViewerColumn createDiagnosticMessageColumn(final TableViewer problemViewer) + { + TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + tableViewerColumn.setLabelProvider(new ColumnLabelProvider() + { + @Override + public Image getImage(Object element) + { + switch (((Diagnostic)element).getSeverity()) + { + case Diagnostic.INFO: + return SharedIcons.getImage(SharedIcons.OBJ_INFO); + + default: + return SharedIcons.getImage(SharedIcons.OBJ_ERROR); + } + } + + @Override + public String getText(Object element) + { + return ((Diagnostic)element).getMessage(); + } + }); + + TableColumn tableColumn = tableViewerColumn.getColumn(); + tableColumn.setResizable(true); + tableColumn.setAlignment(SWT.LEFT); + tableColumn.setWidth(400); + tableColumn.setText("Message"); + return tableViewerColumn; + } + + public static TableViewerColumn createDiagnosticResourceColumn(TableViewer problemViewer, AdapterFactory adapterFactory) + { + TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + tableViewerColumn.setLabelProvider(new ResourceColumnLabelProvider(adapterFactory)); + + TableColumn tableColumn = tableViewerColumn.getColumn(); + tableColumn.setResizable(true); + tableColumn.setAlignment(SWT.LEFT); + tableColumn.setWidth(450); + tableColumn.setText("Resource"); + return tableViewerColumn; + } + + public static TableViewerColumn createDiagnosticElementColumn(TableViewer problemViewer, AdapterFactory adapterFactory) + { + TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + tableViewerColumn.setLabelProvider(new ElementColumnLabelProvider(adapterFactory)); + + TableColumn tableColumn = tableViewerColumn.getColumn(); + tableColumn.setResizable(true); + tableColumn.setAlignment(SWT.LEFT); + tableColumn.setWidth(200); + tableColumn.setText("Element"); + return tableViewerColumn; + } + + public static TableViewerColumn createDiagnosticIDColumn(final TableViewer problemViewer) + { + TableViewerColumn tableViewerColumn = new TableViewerColumn(problemViewer, SWT.NONE); + tableViewerColumn.setLabelProvider(new ColumnLabelProvider() + { + @Override + public String getText(Object element) + { + DiagnosticID diagnosticID = DiagnosticID.get((Diagnostic)element); + if (diagnosticID != null) + { + return diagnosticID.getValue(); + } + + return ""; + } + }); + + TableColumn tableColumn = tableViewerColumn.getColumn(); + tableColumn.setResizable(true); + tableColumn.setAlignment(SWT.LEFT); + tableColumn.setWidth(800); + tableColumn.setText("ID"); + return tableViewerColumn; + } + + /** + * @author Eike Stepper + */ + public static class ResourceColumnLabelProvider extends ColumnLabelProvider + { + protected final AdapterFactory adapterFactory; + + public ResourceColumnLabelProvider(AdapterFactory adapterFactory) + { + this.adapterFactory = adapterFactory; + } + + @Override + public Image getImage(Object element) + { + List<?> data = ((Diagnostic)element).getData(); + if (!data.isEmpty()) + { + Object object = data.get(0); + if (object instanceof EObject) + { + EObject eObject = (EObject)object; + Resource resource = eObject.eResource(); + if (resource != null) + { + IItemLabelProvider labelProvider = (IItemLabelProvider)adapterFactory.adapt(resource, IItemLabelProvider.class); + if (labelProvider != null) + { + return ExtendedImageRegistry.getInstance().getImage(labelProvider.getImage(resource)); + } + } + } + } + + return null; + } + + @Override + public String getText(Object element) + { + List<?> data = ((Diagnostic)element).getData(); + if (!data.isEmpty()) + { + Object object = data.get(0); + if (object instanceof EObject) + { + EObject eObject = (EObject)object; + Resource resource = eObject.eResource(); + if (resource != null) + { + IItemLabelProvider labelProvider = (IItemLabelProvider)adapterFactory.adapt(resource, IItemLabelProvider.class); + if (labelProvider != null) + { + return labelProvider.getText(resource); + } + } + } + } + + return null; + } + } + + /** + * @author Eike Stepper + */ + public static class ElementColumnLabelProvider extends ColumnLabelProvider + { + protected final AdapterFactory adapterFactory; + + public ElementColumnLabelProvider(AdapterFactory adapterFactory) + { + this.adapterFactory = adapterFactory; + } + + @Override + public Image getImage(Object element) + { + List<?> data = ((Diagnostic)element).getData(); + if (!data.isEmpty()) + { + Object object = data.get(0); + if (object instanceof EObject) + { + IItemLabelProvider labelProvider = (IItemLabelProvider)adapterFactory.adapt(object, IItemLabelProvider.class); + if (labelProvider != null) + { + return ExtendedImageRegistry.getInstance().getImage(labelProvider.getImage(object)); + } + } + } + + return null; + } + + @Override + public String getText(Object element) + { + List<?> data = ((Diagnostic)element).getData(); + if (!data.isEmpty()) + { + Object object = data.get(0); + if (object instanceof EModelElement) + { + EModelElement modelElement = (EModelElement)object; + return ElementHandler.getLabel(modelElement); + } + + if (object instanceof EObject) + { + + IItemLabelProvider labelProvider = (IItemLabelProvider)adapterFactory.adapt(object, IItemLabelProvider.class); + if (labelProvider != null) + { + return labelProvider.getText(object); + } + } + } + + return null; + } + } + + private Diagnostic[] getSelectedDiagnostics() + { + IStructuredSelection selection = problemViewer.getStructuredSelection(); + if (selection.isEmpty()) + { + return DiagnosticResolution.NO_DIAGNOSTICS; + } + + List<Diagnostic> result = new ArrayList<Diagnostic>(); + for (Iterator<?> it = selection.iterator(); it.hasNext();) + { + result.add((Diagnostic)it.next()); + } + + return result.toArray(new Diagnostic[result.size()]); + } + + private void showQuickFixes() + { + final Map<DiagnosticResolution, Collection<Diagnostic>> resolutionsMap = new LinkedHashMap<DiagnosticResolution, Collection<Diagnostic>>(); + final Diagnostic[] selectedDiagnostics = getSelectedDiagnostics(); + if (selectedDiagnostics == null || selectedDiagnostics.length == 0) + { + return; + } + + final Diagnostic firstSelectedDiagnostic = selectedDiagnostics[0]; + + IRunnableWithProgress runnable = new IRunnableWithProgress() + { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException + { + monitor.beginTask("Finding fixes", 100); + monitor.worked(20); + + DiagnosticResolution[] resolutions = DiagnosticResolution.getResolutions(firstSelectedDiagnostic, EvolutionEditor.this); + int progressCount = 80; + if (resolutions.length > 1) + { + progressCount = progressCount / resolutions.length; + } + + for (DiagnosticResolution resolution : resolutions) + { + Diagnostic[] other = resolution.findOtherDiagnostics(allDiagnostics); + if (containsAllButFirst(other, selectedDiagnostics)) + { + Collection<Diagnostic> diagnostics = new LinkedHashSet<Diagnostic>(other.length + 1); + diagnostics.add(firstSelectedDiagnostic); + diagnostics.addAll(Arrays.asList(other)); + resolutionsMap.put(resolution, diagnostics); + } + + monitor.worked(progressCount); + } + + monitor.done(); + } + }; + + IWorkbenchPartSite site = getSite(); + IWorkbenchSiteProgressService service = Adapters.adapt(site, IWorkbenchSiteProgressService.class); + + Shell shell = site.getShell(); + IRunnableContext context = new ProgressMonitorDialog(shell); + + try + { + if (service == null) + { + PlatformUI.getWorkbench().getProgressService().runInUI(context, runnable, null); + } + else + { + service.runInUI(context, runnable, null); + } + } + catch (InvocationTargetException ex) + { + throw WrappedException.wrap(ex); + } + catch (InterruptedException ex) + { + throw WrappedException.wrap(ex); + } + + String description = StringUtil.safe(firstSelectedDiagnostic.getMessage()); + if (resolutionsMap.isEmpty()) + { + if (selectedDiagnostics.length == 1) + { + MessageDialog.openInformation(shell, "Quick Fix", NLS.bind("No fixes available for:\n\n {0}.", new Object[] { description })); + } + else + { + MessageDialog.openInformation(shell, "Quick Fix", "The selected problems do not have a common applicable quick fix."); + } + } + else + { + String problemDescription = NLS.bind("Select the fix for ''{0}''.", description); + + Wizard wizard = new QuickFixWizard(problemDescription, selectedDiagnostics, resolutionsMap, editingDomain); + wizard.setWindowTitle("Quick Fix"); + + WizardDialog dialog = new QuickFixWizardDialog(shell, wizard); + dialog.open(); + } + } + + /** + * Checks whether the given extent contains all but the first element from the given members array. + * + * @param extent the array which should contain the elements + * @param members the elements to check + * @return <code>true</code> if all but the first element are inside the extent + */ + private static boolean containsAllButFirst(Object[] extent, Object[] members) + { + outer: for (int i = 1; i < members.length; i++) + { + for (int j = 0; j < extent.length; j++) + { + if (members[i] == extent[j]) + { + continue outer; + } + } + + return false; + } + + return true; + } + + /** + * @author Eike Stepper + */ + private static final class QuickFixWizardDialog extends WizardDialog + { + public QuickFixWizardDialog(Shell parentShell, IWizard newWizard) + { + super(parentShell, newWizard); + setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER | SWT.MODELESS | SWT.RESIZE | getDefaultOrientation()); + } + } + + protected void handleDiagnostics(List<Diagnostic> diagnostics) + { + List<Diagnostic> result = new ArrayList<Diagnostic>(); + flattenDiagnostics(diagnostics, result); + allDiagnostics = result.toArray(new Diagnostic[result.size()]); + + if (problemViewer != null && !problemViewer.getControl().isDisposed()) + { + problemViewer.setInput(diagnostics); + } + } + + private void flattenDiagnostics(List<Diagnostic> diagnostics, List<Diagnostic> result) + { + for (Diagnostic diagnostic : diagnostics) + { + result.add(diagnostic); + flattenDiagnostics(diagnostic.getChildren(), result); + } + } + + /** + * If there is just one page in the multi-page editor part, + * this hides the single tab at the bottom. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void hideTabs() + { + if (getPageCount() <= 1) + { + setPageText(0, ""); + if (getContainer() instanceof CTabFolder) + { + Point point = getContainer().getSize(); + Rectangle clientArea = getContainer().getClientArea(); + getContainer().setSize(point.x, 2 * point.y - clientArea.height - clientArea.y); + } + } + } + + /** + * If there is more than one page in the multi-page editor part, + * this shows the tabs at the bottom. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void showTabs() + { + if (getPageCount() > 1) + { + setPageText(0, getString("_UI_SelectionPage_label")); + if (getContainer() instanceof CTabFolder) + { + Point point = getContainer().getSize(); + Rectangle clientArea = getContainer().getClientArea(); + getContainer().setSize(point.x, clientArea.height + clientArea.y); + } + } + } + + /** + * This is used to track the active viewer. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + protected void pageChange(int pageIndex) + { + super.pageChange(pageIndex); + + if (contentOutlinePage != null) + { + handleContentOutlineSelection(contentOutlinePage.getSelection()); + } + } + + /** + * This is how the framework determines which interfaces we implement. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public <T> T getAdapter(Class<T> key) + { + if (key.equals(IContentOutlinePage.class)) + { + return showOutlineView() ? key.cast(getContentOutlinePage()) : null; + } + else if (key.equals(IPropertySheetPage.class)) + { + return key.cast(getPropertySheetPage()); + } + else if (key.equals(IGotoMarker.class)) + { + return key.cast(this); + } + else if (key.equals(IFindReplaceTarget.class)) + { + return FindAndReplaceTarget.getAdapter(key, this, EvolutionEditorPlugin.getPlugin()); + } + else + { + return super.getAdapter(key); + } + } + + /** + * This accesses a cached version of the content outliner. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public IContentOutlinePage getContentOutlinePage() + { + if (contentOutlinePage == null) + { + // The content outline is just a tree. + // + class MyContentOutlinePage extends ContentOutlinePage + { + @Override + public void createControl(Composite parent) + { + super.createControl(parent); + contentOutlineViewer = getTreeViewer(); + contentOutlineViewer.addSelectionChangedListener(this); + + // Set up the tree viewer. + // + contentOutlineViewer.setUseHashlookup(true); + contentOutlineViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory)); + contentOutlineViewer.setLabelProvider(new DelegatingStyledCellLabelProvider.FontAndColorProvider( + new DecoratingColumLabelProvider.StyledLabelProvider(new AdapterFactoryLabelProvider.StyledLabelProvider(adapterFactory, contentOutlineViewer), + new DiagnosticDecorator.Styled(editingDomain, contentOutlineViewer, EvolutionEditorPlugin.getPlugin().getDialogSettings())))); + contentOutlineViewer.setInput(editingDomain.getResourceSet()); + + new ColumnViewerInformationControlToolTipSupport(contentOutlineViewer, + new DiagnosticDecorator.Styled.EditingDomainLocationListener(editingDomain, contentOutlineViewer)); + + // Make sure our popups work. + // + createContextMenuFor(contentOutlineViewer); + + if (!editingDomain.getResourceSet().getResources().isEmpty()) + { + // Select the root object in the view. + // + contentOutlineViewer.setSelection(new StructuredSelection(editingDomain.getResourceSet().getResources().get(0)), true); + } + } + + @Override + public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager) + { + super.makeContributions(menuManager, toolBarManager, statusLineManager); + contentOutlineStatusLineManager = statusLineManager; + } + + @Override + public void setActionBars(IActionBars actionBars) + { + super.setActionBars(actionBars); + getActionBarContributor().shareGlobalActions(this, actionBars); + } + } + + contentOutlinePage = new MyContentOutlinePage(); + + // Listen to selection so that we can handle it is a special way. + // + contentOutlinePage.addSelectionChangedListener(new ISelectionChangedListener() + { + // This ensures that we handle selections correctly. + // + public void selectionChanged(SelectionChangedEvent event) + { + handleContentOutlineSelection(event.getSelection()); + } + }); + } + + return contentOutlinePage; + } + + /** + * @author Eike Stepper + */ + private static class DelegatingItemPropertyDescriptor implements IItemPropertyDescriptor + { + private final IItemPropertyDescriptor itemPropertyDescriptor; + + private DelegatingItemPropertyDescriptor(IItemPropertyDescriptor itemPropertyDescriptor) + { + this.itemPropertyDescriptor = itemPropertyDescriptor; + } + + public Object getPropertyValue(Object object) + { + return itemPropertyDescriptor.getPropertyValue(object); + } + + public boolean isPropertySet(Object object) + { + return itemPropertyDescriptor.isPropertySet(object); + } + + public boolean canSetProperty(Object object) + { + return itemPropertyDescriptor.canSetProperty(object); + } + + public void resetPropertyValue(Object object) + { + itemPropertyDescriptor.resetPropertyValue(object); + } + + public void setPropertyValue(Object object, Object value) + { + itemPropertyDescriptor.setPropertyValue(object, value); + } + + public String getCategory(Object object) + { + return itemPropertyDescriptor.getCategory(object); + } + + public String getDescription(Object object) + { + return itemPropertyDescriptor.getDescription(object); + } + + public String getDisplayName(Object object) + { + return itemPropertyDescriptor.getDisplayName(object); + } + + public String[] getFilterFlags(Object object) + { + return itemPropertyDescriptor.getFilterFlags(object); + } + + public Object getHelpContextIds(Object object) + { + return itemPropertyDescriptor.getHelpContextIds(object); + } + + public String getId(Object object) + { + return itemPropertyDescriptor.getId(object); + } + + public IItemLabelProvider getLabelProvider(Object object) + { + return itemPropertyDescriptor.getLabelProvider(object); + } + + public boolean isCompatibleWith(Object object, Object anotherObject, IItemPropertyDescriptor anotherPropertyDescriptor) + { + return itemPropertyDescriptor.isCompatibleWith(object, anotherObject, anotherPropertyDescriptor); + } + + public Object getFeature(Object object) + { + return itemPropertyDescriptor.getFeature(object); + } + + public boolean isMany(Object object) + { + return itemPropertyDescriptor.isMany(object); + } + + public Collection<?> getChoiceOfValues(Object object) + { + return itemPropertyDescriptor.getChoiceOfValues(object); + } + + public boolean isMultiLine(Object object) + { + return itemPropertyDescriptor.isMultiLine(object); + } + + public boolean isSortChoices(Object object) + { + return itemPropertyDescriptor.isSortChoices(object); + } + } + + /** + * This accesses a cached version of the property sheet. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated NOT + */ + public IPropertySheetPage getPropertySheetPage() + { + PropertySheetPage propertySheetPage = new ExtendedPropertySheetPage(editingDomain, ExtendedPropertySheetPage.Decoration.LIVE, + EvolutionEditorPlugin.getPlugin().getDialogSettings(), 0, true) + { + { + setSorter(new PropertySheetSorter() + { + @Override + public void sort(IPropertySheetEntry[] entries) + { + // Intentionally left empty + } + }); + } + + @Override + public void setSelectionToViewer(List<?> selection) + { + EvolutionEditor.this.setSelectionToViewer(selection); + EvolutionEditor.this.setFocus(); + } + + @Override + public void setActionBars(IActionBars actionBars) + { + super.setActionBars(actionBars); + getActionBarContributor().shareGlobalActions(this, actionBars); + } + }; + + propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(adapterFactory) + { + @Override + protected IPropertySource createPropertySource(Object object, IItemPropertySource itemPropertySource) + { + if (isReadOnlyObject(object)) + { + /** + * Create no cell editor for read-only objects. + */ + return new PropertySource(object, itemPropertySource) + { + @Override + protected IPropertyDescriptor createPropertyDescriptor(final IItemPropertyDescriptor itemPropertyDescriptor) + { + return super.createPropertyDescriptor(new DelegatingItemPropertyDescriptor(itemPropertyDescriptor) + { + @Override + public boolean canSetProperty(Object object) + { + return false; + } + }); + } + }; + } + else if (object instanceof EModelElement && evolution.containsElement((EModelElement)object)) + { + /** + * Eliminate released elements from selection choices. + */ + return new PropertySource(object, itemPropertySource) + { + @Override + protected IPropertyDescriptor createPropertyDescriptor(final IItemPropertyDescriptor itemPropertyDescriptor) + { + return super.createPropertyDescriptor(new DelegatingItemPropertyDescriptor(itemPropertyDescriptor) + { + @Override + public Collection<?> getChoiceOfValues(Object object) + { + Collection<?> values = super.getChoiceOfValues(object); + if (values != null) + { + for (Iterator<?> it = values.iterator(); it.hasNext();) + { + Object value = it.next(); + if (value instanceof EModelElement) + { + EModelElement modelElement = (EModelElement)value; + if (!evolution.containsElement(modelElement)) + { + it.remove(); + } + } + } + } + + return values; + } + }); + } + }; + } + + return super.createPropertySource(object, itemPropertySource); + } + }); + + propertySheetPages.add(propertySheetPage); + + return propertySheetPage; + } + + /** + * This deals with how we want selection in the outliner to affect the other views. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void handleContentOutlineSelection(ISelection selection) + { + if (selectionViewer != null && !selection.isEmpty() && selection instanceof IStructuredSelection) + { + Iterator<?> selectedElements = ((IStructuredSelection)selection).iterator(); + if (selectedElements.hasNext()) + { + // Get the first selected element. + // + Object selectedElement = selectedElements.next(); + + ArrayList<Object> selectionList = new ArrayList<Object>(); + selectionList.add(selectedElement); + while (selectedElements.hasNext()) + { + selectionList.add(selectedElements.next()); + } + + // Set the selection to the widget. + // + selectionViewer.setSelection(new StructuredSelection(selectionList)); + } + } + } + + /** + * This is for implementing {@link IEditorPart} and simply tests the command stack. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public boolean isDirty() + { + return ((BasicCommandStack)editingDomain.getCommandStack()).isSaveNeeded(); + } + + /** + * This is for implementing {@link IEditorPart} and simply saves the model file. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void doSave(IProgressMonitor progressMonitor) + { + // Save only resources that have actually changed. + // + final Map<Object, Object> saveOptions = new HashMap<Object, Object>(); + saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER); + saveOptions.put(Resource.OPTION_LINE_DELIMITER, Resource.OPTION_LINE_DELIMITER_UNSPECIFIED); + + // Do the work within an operation because this is a long running activity that modifies the workbench. + // + WorkspaceModifyOperation operation = new WorkspaceModifyOperation() + { + // This is the method that gets invoked when the operation runs. + // + @Override + public void execute(IProgressMonitor monitor) + { + // Save the resources to the file system. + // + boolean first = true; + List<Resource> resources = editingDomain.getResourceSet().getResources(); + for (int i = 0; i < resources.size(); ++i) + { + Resource resource = resources.get(i); + if ((first || !resource.getContents().isEmpty() || isPersisted(resource)) && !editingDomain.isReadOnly(resource)) + { + try + { + long timeStamp = resource.getTimeStamp(); + resource.save(saveOptions); + if (resource.getTimeStamp() != timeStamp) + { + savedResources.add(resource); + } + } + catch (Exception exception) + { + resourceToDiagnosticMap.put(resource, analyzeResourceProblems(resource, exception)); + } + first = false; + } + } + } + }; + + updateProblemIndication = false; + try + { + // This runs the options, and shows progress. + // + new ProgressMonitorDialog(getSite().getShell()).run(true, false, operation); + + // Refresh the necessary state. + // + ((BasicCommandStack)editingDomain.getCommandStack()).saveIsDone(); + firePropertyChange(IEditorPart.PROP_DIRTY); + } + catch (Exception exception) + { + // Something went wrong that shouldn't. + // + EvolutionEditorPlugin.INSTANCE.log(exception); + } + updateProblemIndication = true; + updateProblemIndication(); + } + + /** + * This returns whether something has been persisted to the URI of the specified resource. + * The implementation uses the URI converter from the editor's resource set to try to open an input stream. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected boolean isPersisted(Resource resource) + { + boolean result = false; + try + { + InputStream stream = editingDomain.getResourceSet().getURIConverter().createInputStream(resource.getURI()); + if (stream != null) + { + result = true; + stream.close(); + } + } + catch (IOException e) + { + // Ignore + } + return result; + } + + /** + * This always returns true because it is not currently supported. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public boolean isSaveAsAllowed() + { + return true; + } + + /** + * This also changes the editor's input. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void doSaveAs() + { + SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell()); + saveAsDialog.open(); + IPath path = saveAsDialog.getResult(); + if (path != null) + { + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); + if (file != null) + { + doSaveAs(URI.createPlatformResourceURI(file.getFullPath().toString(), true), new FileEditorInput(file)); + } + } + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected void doSaveAs(URI uri, IEditorInput editorInput) + { + editingDomain.getResourceSet().getResources().get(0).setURI(uri); + setInputWithNotify(editorInput); + setPartName(editorInput.getName()); + IProgressMonitor progressMonitor = getActionBars().getStatusLineManager() != null ? getActionBars().getStatusLineManager().getProgressMonitor() + : new NullProgressMonitor(); + doSave(progressMonitor); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void gotoMarker(IMarker marker) + { + List<?> targetObjects = markerHelper.getTargetObjects(editingDomain, marker); + if (!targetObjects.isEmpty()) + { + setSelectionToViewer(targetObjects); + } + } + + /** + * This is called during startup. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void init(IEditorSite site, IEditorInput editorInput) + { + setSite(site); + setInputWithNotify(editorInput); + setPartName(editorInput.getName()); + site.setSelectionProvider(this); + site.getPage().addPartListener(partListener); + ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void setFocus() + { + getControl(getActivePage()).setFocus(); + } + + /** + * This implements {@link org.eclipse.jface.viewers.ISelectionProvider}. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void addSelectionChangedListener(ISelectionChangedListener listener) + { + selectionChangedListeners.add(listener); + } + + /** + * This implements {@link org.eclipse.jface.viewers.ISelectionProvider}. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void removeSelectionChangedListener(ISelectionChangedListener listener) + { + selectionChangedListeners.remove(listener); + } + + /** + * This implements {@link org.eclipse.jface.viewers.ISelectionProvider} to return this editor's overall selection. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public ISelection getSelection() + { + return editorSelection; + } + + /** + * This implements {@link org.eclipse.jface.viewers.ISelectionProvider} to set this editor's overall selection. + * Calling this result will notify the listeners. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void setSelection(ISelection selection) + { + editorSelection = selection; + + for (ISelectionChangedListener listener : selectionChangedListeners) + { + listener.selectionChanged(new SelectionChangedEvent(this, selection)); + } + setStatusLineManager(selection); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void setStatusLineManager(ISelection selection) + { + IStatusLineManager statusLineManager = currentViewer != null && currentViewer == contentOutlineViewer ? contentOutlineStatusLineManager + : getActionBars().getStatusLineManager(); + + if (statusLineManager != null) + { + if (selection instanceof IStructuredSelection) + { + Collection<?> collection = ((IStructuredSelection)selection).toList(); + switch (collection.size()) + { + case 0: + { + statusLineManager.setMessage(getString("_UI_NoObjectSelected")); + break; + } + case 1: + { + String text = new AdapterFactoryItemDelegator(adapterFactory).getText(collection.iterator().next()); + statusLineManager.setMessage(getString("_UI_SingleObjectSelected", text)); + break; + } + default: + { + statusLineManager.setMessage(getString("_UI_MultiObjectSelected", Integer.toString(collection.size()))); + break; + } + } + } + else + { + statusLineManager.setMessage(""); + } + } + } + + /** + * This looks up a string in the plugin's plugin.properties file. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + private static String getString(String key) + { + return EvolutionEditorPlugin.INSTANCE.getString(key); + } + + /** + * This looks up a string in plugin.properties, making a substitution. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + private static String getString(String key, Object s1) + { + return EvolutionEditorPlugin.INSTANCE.getString(key, new Object[] { s1 }); + } + + /** + * This implements {@link org.eclipse.jface.action.IMenuListener} to help fill the context menus with contributions from the Edit menu. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void menuAboutToShow(IMenuManager menuManager) + { + ((IMenuListener)getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EditingDomainActionBarContributor getActionBarContributor() + { + return (EditingDomainActionBarContributor)getEditorSite().getActionBarContributor(); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public IActionBars getActionBars() + { + return getActionBarContributor().getActionBars(); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public AdapterFactory getAdapterFactory() + { + return adapterFactory; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void dispose() + { + updateProblemIndication = false; + + ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener); + + getSite().getPage().removePartListener(partListener); + + adapterFactory.dispose(); + + if (getActionBarContributor().getActiveEditor() == this) + { + getActionBarContributor().setActiveEditor(null); + } + + for (PropertySheetPage propertySheetPage : propertySheetPages) + { + propertySheetPage.dispose(); + } + + if (contentOutlinePage != null) + { + contentOutlinePage.dispose(); + } + + super.dispose(); + } + + /** + * Returns whether the outline view should be presented to the user. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected boolean showOutlineView() + { + return false; + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditorPlugin.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditorPlugin.java new file mode 100644 index 0000000000..8aa42e9f46 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionEditorPlugin.java @@ -0,0 +1,96 @@ +/** + */ +package org.eclipse.emf.cdo.evolution.presentation; + +import org.eclipse.emf.common.EMFPlugin; +import org.eclipse.emf.common.ui.EclipseUIPlugin; +import org.eclipse.emf.common.util.ResourceLocator; +import org.eclipse.emf.ecore.provider.EcoreEditPlugin; + +/** + * This is the central singleton for the Evolution editor plugin. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ +public final class EvolutionEditorPlugin extends EMFPlugin +{ + public static final String PLUGIN_ID = "org.eclipse.emf.cdo.evolution.editor"; + + /** + * Keep track of the singleton. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public static final EvolutionEditorPlugin INSTANCE = new EvolutionEditorPlugin(); + + /** + * Keep track of the singleton. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + private static Implementation plugin; + + /** + * Create the instance. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EvolutionEditorPlugin() + { + super(new ResourceLocator[] { EcoreEditPlugin.INSTANCE, }); + } + + /** + * Returns the singleton instance of the Eclipse plugin. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @return the singleton instance. + * @generated + */ + @Override + public ResourceLocator getPluginResourceLocator() + { + return plugin; + } + + /** + * Returns the singleton instance of the Eclipse plugin. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @return the singleton instance. + * @generated + */ + public static Implementation getPlugin() + { + return plugin; + } + + /** + * The actual implementation of the Eclipse <b>Plugin</b>. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public static class Implementation extends EclipseUIPlugin + { + /** + * Creates an instance. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public Implementation() + { + super(); + + // Remember the static instance. + // + plugin = this; + } + } + +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionModelWizard.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionModelWizard.java new file mode 100644 index 0000000000..1e7b23d1f7 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/EvolutionModelWizard.java @@ -0,0 +1,657 @@ +/** + */ +package org.eclipse.emf.cdo.evolution.presentation; + +import org.eclipse.emf.cdo.evolution.EvolutionFactory; +import org.eclipse.emf.cdo.evolution.EvolutionPackage; +import org.eclipse.emf.cdo.evolution.provider.EvolutionEditPlugin; + +import org.eclipse.emf.common.CommonPlugin; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.dialogs.WizardNewFileCreationPage; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.part.ISetSelectionTarget; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.StringTokenizer; + +/** + * This is a simple wizard for creating a new model file. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ +public class EvolutionModelWizard extends Wizard implements INewWizard +{ + /** + * The supported extensions for created files. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public static final List<String> FILE_EXTENSIONS = Collections + .unmodifiableList(Arrays.asList(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionEditorFilenameExtensions").split("\\s*,\\s*"))); + + /** + * A formatted list of supported file extensions, suitable for display. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public static final String FORMATTED_FILE_EXTENSIONS = EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionEditorFilenameExtensions") + .replaceAll("\\s*,\\s*", ", "); + + /** + * This caches an instance of the model package. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EvolutionPackage evolutionPackage = EvolutionPackage.eINSTANCE; + + /** + * This caches an instance of the model factory. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EvolutionFactory evolutionFactory = evolutionPackage.getEvolutionFactory(); + + /** + * This is the file creation page. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EvolutionModelWizardNewFileCreationPage newFileCreationPage; + + /** + * This is the initial object creation page. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EvolutionModelWizardInitialObjectCreationPage initialObjectCreationPage; + + /** + * Remember the selection during initialization for populating the default container. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IStructuredSelection selection; + + /** + * Remember the workbench during initialization. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected IWorkbench workbench; + + /** + * Caches the names of the types that can be created as the root object. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected List<String> initialObjectNames; + + /** + * This just records the information. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void init(IWorkbench workbench, IStructuredSelection selection) + { + this.workbench = workbench; + this.selection = selection; + setWindowTitle(EvolutionEditorPlugin.INSTANCE.getString("_UI_Wizard_label")); + setDefaultPageImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(EvolutionEditorPlugin.INSTANCE.getImage("full/wizban/NewEvolution"))); + } + + /** + * Returns the names of the types that can be created as the root object. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<String> getInitialObjectNames() + { + if (initialObjectNames == null) + { + initialObjectNames = new ArrayList<String>(); + for (EClassifier eClassifier : evolutionPackage.getEClassifiers()) + { + if (eClassifier instanceof EClass) + { + EClass eClass = (EClass)eClassifier; + if (!eClass.isAbstract()) + { + initialObjectNames.add(eClass.getName()); + } + } + } + Collections.sort(initialObjectNames, CommonPlugin.INSTANCE.getComparator()); + } + return initialObjectNames; + } + + /** + * Create a new model. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected EObject createInitialModel() + { + EClass eClass = (EClass)evolutionPackage.getEClassifier(initialObjectCreationPage.getInitialObjectName()); + EObject rootObject = evolutionFactory.create(eClass); + return rootObject; + } + + /** + * Do the work after everything is specified. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public boolean performFinish() + { + try + { + // Remember the file. + // + final IFile modelFile = getModelFile(); + + // Do the work within an operation. + // + WorkspaceModifyOperation operation = new WorkspaceModifyOperation() + { + @Override + protected void execute(IProgressMonitor progressMonitor) + { + try + { + // Create a resource set + // + ResourceSet resourceSet = new ResourceSetImpl(); + + // Get the URI of the model file. + // + URI fileURI = URI.createPlatformResourceURI(modelFile.getFullPath().toString(), true); + + // Create a resource for this file. + // + Resource resource = resourceSet.createResource(fileURI); + + // Add the initial model object to the contents. + // + EObject rootObject = createInitialModel(); + if (rootObject != null) + { + resource.getContents().add(rootObject); + } + + // Save the contents of the resource to the file system. + // + Map<Object, Object> options = new HashMap<Object, Object>(); + options.put(XMLResource.OPTION_ENCODING, initialObjectCreationPage.getEncoding()); + resource.save(options); + } + catch (Exception exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + } + finally + { + progressMonitor.done(); + } + } + }; + + getContainer().run(false, false, operation); + + // Select the new file resource in the current view. + // + IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow(); + IWorkbenchPage page = workbenchWindow.getActivePage(); + final IWorkbenchPart activePart = page.getActivePart(); + if (activePart instanceof ISetSelectionTarget) + { + final ISelection targetSelection = new StructuredSelection(modelFile); + getShell().getDisplay().asyncExec(new Runnable() + { + public void run() + { + ((ISetSelectionTarget)activePart).selectReveal(targetSelection); + } + }); + } + + // Open an editor on the new file. + // + try + { + page.openEditor(new FileEditorInput(modelFile), workbench.getEditorRegistry().getDefaultEditor(modelFile.getFullPath().toString()).getId()); + } + catch (PartInitException exception) + { + MessageDialog.openError(workbenchWindow.getShell(), EvolutionEditorPlugin.INSTANCE.getString("_UI_OpenEditorError_label"), exception.getMessage()); + return false; + } + + return true; + } + catch (Exception exception) + { + EvolutionEditorPlugin.INSTANCE.log(exception); + return false; + } + } + + /** + * This is the one page of the wizard. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public class EvolutionModelWizardNewFileCreationPage extends WizardNewFileCreationPage + { + /** + * Pass in the selection. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EvolutionModelWizardNewFileCreationPage(String pageId, IStructuredSelection selection) + { + super(pageId, selection); + } + + /** + * The framework calls this to see if the file is correct. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + protected boolean validatePage() + { + if (super.validatePage()) + { + String extension = new Path(getFileName()).getFileExtension(); + if (extension == null || !FILE_EXTENSIONS.contains(extension)) + { + String key = FILE_EXTENSIONS.size() > 1 ? "_WARN_FilenameExtensions" : "_WARN_FilenameExtension"; + setErrorMessage(EvolutionEditorPlugin.INSTANCE.getString(key, new Object[] { FORMATTED_FILE_EXTENSIONS })); + return false; + } + return true; + } + return false; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public IFile getModelFile() + { + return ResourcesPlugin.getWorkspace().getRoot().getFile(getContainerFullPath().append(getFileName())); + } + } + + /** + * This is the page where the type of object to create is selected. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public class EvolutionModelWizardInitialObjectCreationPage extends WizardPage + { + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Combo initialObjectField; + + /** + * @generated + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + */ + protected List<String> encodings; + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Combo encodingField; + + /** + * Pass in the selection. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public EvolutionModelWizardInitialObjectCreationPage(String pageId) + { + super(pageId); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public void createControl(Composite parent) + { + Composite composite = new Composite(parent, SWT.NONE); + { + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + layout.verticalSpacing = 12; + composite.setLayout(layout); + + GridData data = new GridData(); + data.verticalAlignment = GridData.FILL; + data.grabExcessVerticalSpace = true; + data.horizontalAlignment = GridData.FILL; + composite.setLayoutData(data); + } + + Label containerLabel = new Label(composite, SWT.LEFT); + { + containerLabel.setText(EvolutionEditorPlugin.INSTANCE.getString("_UI_ModelObject")); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + containerLabel.setLayoutData(data); + } + + initialObjectField = new Combo(composite, SWT.BORDER); + { + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + initialObjectField.setLayoutData(data); + } + + for (String objectName : getInitialObjectNames()) + { + initialObjectField.add(getLabel(objectName)); + } + + if (initialObjectField.getItemCount() == 1) + { + initialObjectField.select(0); + } + initialObjectField.addModifyListener(validator); + + Label encodingLabel = new Label(composite, SWT.LEFT); + { + encodingLabel.setText(EvolutionEditorPlugin.INSTANCE.getString("_UI_XMLEncoding")); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + encodingLabel.setLayoutData(data); + } + encodingField = new Combo(composite, SWT.BORDER); + { + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + encodingField.setLayoutData(data); + } + + for (String encoding : getEncodings()) + { + encodingField.add(encoding); + } + + encodingField.select(0); + encodingField.addModifyListener(validator); + + setPageComplete(validatePage()); + setControl(composite); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected ModifyListener validator = new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + setPageComplete(validatePage()); + } + }; + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected boolean validatePage() + { + return getInitialObjectName() != null && getEncodings().contains(encodingField.getText()); + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void setVisible(boolean visible) + { + super.setVisible(visible); + if (visible) + { + if (initialObjectField.getItemCount() == 1) + { + initialObjectField.clearSelection(); + encodingField.setFocus(); + } + else + { + encodingField.clearSelection(); + initialObjectField.setFocus(); + } + } + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public String getInitialObjectName() + { + String label = initialObjectField.getText(); + + for (String name : getInitialObjectNames()) + { + if (getLabel(name).equals(label)) + { + return name; + } + } + return null; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public String getEncoding() + { + return encodingField.getText(); + } + + /** + * Returns the label for the specified type name. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected String getLabel(String typeName) + { + try + { + return EvolutionEditPlugin.INSTANCE.getString("_UI_" + typeName + "_type"); + } + catch (MissingResourceException mre) + { + EvolutionEditorPlugin.INSTANCE.log(mre); + } + return typeName; + } + + /** + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + protected Collection<String> getEncodings() + { + if (encodings == null) + { + encodings = new ArrayList<String>(); + for (StringTokenizer stringTokenizer = new StringTokenizer(EvolutionEditorPlugin.INSTANCE.getString("_UI_XMLEncodingChoices")); stringTokenizer + .hasMoreTokens();) + { + encodings.add(stringTokenizer.nextToken()); + } + } + return encodings; + } + } + + /** + * The framework calls this to create the contents of the wizard. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + @Override + public void addPages() + { + // Create a page, set the title, and the initial model file name. + // + newFileCreationPage = new EvolutionModelWizardNewFileCreationPage("Whatever", selection); + newFileCreationPage.setTitle(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionModelWizard_label")); + newFileCreationPage.setDescription(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionModelWizard_description")); + newFileCreationPage.setFileName(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionEditorFilenameDefaultBase") + "." + FILE_EXTENSIONS.get(0)); + addPage(newFileCreationPage); + + // Try and get the resource selection to determine a current directory for the file dialog. + // + if (selection != null && !selection.isEmpty()) + { + // Get the resource... + // + Object selectedElement = selection.iterator().next(); + if (selectedElement instanceof IResource) + { + // Get the resource parent, if its a file. + // + IResource selectedResource = (IResource)selectedElement; + if (selectedResource.getType() == IResource.FILE) + { + selectedResource = selectedResource.getParent(); + } + + // This gives us a directory... + // + if (selectedResource instanceof IFolder || selectedResource instanceof IProject) + { + // Set this for the container. + // + newFileCreationPage.setContainerFullPath(selectedResource.getFullPath()); + + // Make up a unique new name here. + // + String defaultModelBaseFilename = EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionEditorFilenameDefaultBase"); + String defaultModelFilenameExtension = FILE_EXTENSIONS.get(0); + String modelFilename = defaultModelBaseFilename + "." + defaultModelFilenameExtension; + for (int i = 1; ((IContainer)selectedResource).findMember(modelFilename) != null; ++i) + { + modelFilename = defaultModelBaseFilename + i + "." + defaultModelFilenameExtension; + } + newFileCreationPage.setFileName(modelFilename); + } + } + } + initialObjectCreationPage = new EvolutionModelWizardInitialObjectCreationPage("Whatever2"); + initialObjectCreationPage.setTitle(EvolutionEditorPlugin.INSTANCE.getString("_UI_EvolutionModelWizard_label")); + initialObjectCreationPage.setDescription(EvolutionEditorPlugin.INSTANCE.getString("_UI_Wizard_initial_object_description")); + addPage(initialObjectCreationPage); + } + + /** + * Get the file from the page. + * <!-- begin-user-doc --> + * <!-- end-user-doc --> + * @generated + */ + public IFile getModelFile() + { + return newFileCreationPage.getModelFile(); + } + +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolution.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolution.java new file mode 100644 index 0000000000..91cbd8a227 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolution.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.util.DiagnosticType; + +import org.eclipse.emf.common.util.Diagnostic; + +import org.eclipse.swt.graphics.Image; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eike Stepper + */ +public abstract class BasicDiagnosticResolution extends DiagnosticResolution implements DiagnosticResolutionRelevance +{ + private final Image image; + + private final String text; + + private final String description; + + private final boolean multi; + + public BasicDiagnosticResolution(Image image, String text, String description, boolean multi) + { + this.image = image; + this.text = text; + this.description = description; + this.multi = multi; + } + + @Override + public Image getImage() + { + return image; + } + + @Override + public String getText() + { + return text; + } + + @Override + public String getDescription() + { + return description; + } + + public boolean isMulti() + { + return multi; + } + + @Override + public Diagnostic[] findOtherDiagnostics(Diagnostic[] diagnostics) + { + if (multi && diagnostics != null && diagnostics.length != 0) + { + List<Diagnostic> result = new ArrayList<Diagnostic>(); + for (int i = 0; i < diagnostics.length; i++) + { + Diagnostic diagnostic = diagnostics[i]; + if (isCompatibleDiagnostic(diagnostic)) + { + result.add(diagnostic); + } + } + + return result.toArray(new Diagnostic[result.size()]); + } + + return super.findOtherDiagnostics(diagnostics); + } + + protected boolean isCompatibleDiagnostic(Diagnostic diagnostic) + { + return false; + } + + public int getRelevanceForResolution() + { + return 0; + } + + @Override + public abstract void run(Diagnostic diagnostic); + + /** + * @author Eike Stepper + */ + public static abstract class TypedDiagnosticResolution extends BasicDiagnosticResolution + { + private final DiagnosticType type; + + public TypedDiagnosticResolution(Image image, String text, String description, boolean multi, String source, int code) + { + super(image, text, description, multi); + type = new DiagnosticType(source, code); + } + + public DiagnosticType getType() + { + return type; + } + + protected DiagnosticType[] getCompatibleTypes() + { + return new DiagnosticType[] { type }; + } + + @Override + protected boolean isCompatibleDiagnostic(Diagnostic diagnostic) + { + for (int i = 0; i < getCompatibleTypes().length; i++) + { + DiagnosticType type = getCompatibleTypes()[i]; + if (type.appliesTo(diagnostic)) + { + return true; + } + } + + return super.isCompatibleDiagnostic(diagnostic); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolutionGenerator.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolutionGenerator.java new file mode 100644 index 0000000000..60a5bc7421 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/BasicDiagnosticResolutionGenerator.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.presentation.EvolutionEditorPlugin; + +import org.eclipse.emf.common.util.ResourceLocator; + +/** + * @author Eike Stepper + */ +public abstract class BasicDiagnosticResolutionGenerator implements DiagnosticResolution.Generator +{ + protected ResourceLocator getResourceLocator() + { + return EvolutionEditorPlugin.INSTANCE; + } + + protected String getString(String key, Object... substitutions) + { + return getString(getResourceLocator(), key, substitutions); + } + + private String getString(ResourceLocator resourceLocator, String key, Object[] substitutions) + { + return substitutions == null || substitutions.length == 0 ? resourceLocator.getString(key) : resourceLocator.getString(key, substitutions); + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DefaultDiagnosticResolutionGenerator.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DefaultDiagnosticResolutionGenerator.java new file mode 100644 index 0000000000..75fd4aa4e5 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DefaultDiagnosticResolutionGenerator.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.ChangeKind; +import org.eclipse.emf.cdo.evolution.ElementChange; +import org.eclipse.emf.cdo.evolution.Evolution; +import org.eclipse.emf.cdo.evolution.EvolutionFactory; +import org.eclipse.emf.cdo.evolution.FeaturePathMigration; +import org.eclipse.emf.cdo.evolution.Model; +import org.eclipse.emf.cdo.evolution.Release; +import org.eclipse.emf.cdo.evolution.impl.EvolutionImpl; +import org.eclipse.emf.cdo.evolution.impl.ModelSetChangeImpl; +import org.eclipse.emf.cdo.evolution.presentation.quickfix.DiagnosticResolution.Generator; +import org.eclipse.emf.cdo.evolution.util.DiagnosticID; +import org.eclipse.emf.cdo.evolution.util.DiagnosticType; +import org.eclipse.emf.cdo.evolution.util.ElementHandler; +import org.eclipse.emf.cdo.evolution.util.ElementRunnable; +import org.eclipse.emf.cdo.evolution.util.EvolutionValidator; +import org.eclipse.emf.cdo.evolution.util.IDAnnotation; + +import org.eclipse.net4j.util.factory.ProductCreationException; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Eike Stepper + */ +public class DefaultDiagnosticResolutionGenerator extends BasicDiagnosticResolutionGenerator +{ + public DefaultDiagnosticResolutionGenerator() + { + } + + public void getResolutions(Diagnostic diagnostic, final Context context) + { + if (EvolutionValidator.DIAGNOSTIC_SOURCE.equals(diagnostic.getSource())) + { + int code = diagnostic.getCode(); + switch (code) + { + case EvolutionValidator.CODE_NO_MODEL: + handleNoModel(diagnostic, context); + break; + + case EvolutionValidator.CODE_NO_URI: + handleNoURI(diagnostic, context); + break; + + case EvolutionValidator.CODE_NO_RESOURCE_SET: + break; + + case EvolutionValidator.CODE_RESOURCE_NOT_FOUND: + break; + + case EvolutionValidator.CODE_LOAD_PROBLEM: + break; + + case EvolutionValidator.CODE_CONTENT_PROBLEM: + break; + + case EvolutionValidator.CODE_PACKAGE_MISSING: + handlePackageMissing(diagnostic, context); + break; + + case EvolutionValidator.CODE_PACKAGE_NOT_UNIQUE: + break; + + case EvolutionValidator.CODE_NSURI_NOT_UNIQUE: + break; + + case EvolutionValidator.CODE_NSURI_NOT_CHANGED: + handleNSURINotChanged(diagnostic, context); + break; + + case EvolutionValidator.CODE_ID_ANNOTATION_MISSING: + case EvolutionValidator.CODE_ID_WITHOUT_VALUE: + handleNoID(diagnostic, context); + break; + + case EvolutionValidator.CODE_ID_NOT_UNIQUE: + handleIDNotUnique(diagnostic, context); + break; + + case EvolutionValidator.CODE_FEATURE_PATH_UNKNOWN: + handleFeaturePathUnknown(diagnostic, context); + break; + + case EvolutionValidator.CODE_RELEASE: + handleRelease(diagnostic, context); + break; + } + } + } + + protected void handleNoModel(Diagnostic diagnostic, final Context context) + { + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_SelectModelsFromWorkspace"), null, false, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + Shell shell = context.getEditor().getSite().getShell(); + + FilteredResourcesSelectionDialog dialog = new FilteredResourcesSelectionDialog(shell, true, ResourcesPlugin.getWorkspace().getRoot(), IResource.FILE); + dialog.setInitialPattern("*.ecore"); + dialog.open(); + + Object[] result = dialog.getResult(); + if (result == null || result.length == 0) + { + return; + } + + Evolution evolution = (Evolution)diagnostic.getData().get(0); + for (Object object : result) + { + if (object instanceof IFile) + { + IFile file = (IFile)object; + + Model model = EvolutionFactory.eINSTANCE.createModel(URI.createPlatformResourceURI(file.getFullPath().toString(), true)); + evolution.getModels().add(model); + } + } + } + }); + } + + protected void handleNoURI(Diagnostic diagnostic, final Context context) + { + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_SelectModelFromWorkspace"), null, false, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + Shell shell = context.getEditor().getSite().getShell(); + + FilteredResourcesSelectionDialog dialog = new FilteredResourcesSelectionDialog(shell, false, ResourcesPlugin.getWorkspace().getRoot(), IResource.FILE); + dialog.setInitialPattern("*.ecore"); + dialog.open(); + + Object[] result = dialog.getResult(); + if (result == null || result.length == 0 || !(result[0] instanceof IFile)) + { + return; + } + + IFile file = (IFile)result[0]; + Model model = (Model)diagnostic.getData().get(0); + model.setURI(URI.createPlatformResourceURI(file.getFullPath().toString(), true)); + } + }); + } + + protected void handlePackageMissing(Diagnostic diagnostic, final Context context) + { + final List<?> data = diagnostic.getData(); + + Resource resource = ((EPackage)data.get(2)).eResource(); + if (resource != null) + { + final URI uri = resource.getURI(); + if (uri != null) + { + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_PackageMissing", uri), null, true, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + Model model = EvolutionFactory.eINSTANCE.createModel(uri); + + Evolution evolution = (Evolution)data.get(0); + evolution.getModels().add(model); + } + }); + } + } + } + + protected void handleNSURINotChanged(Diagnostic diagnostic, Context context) + { + Evolution evolution = (Evolution)diagnostic.getData().get(3); + final int nextVersion = evolution.getNextReleaseVersion(); + + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_SetVersionIntoNamespace", nextVersion), null, true, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + EPackage ePackage = (EPackage)diagnostic.getData().get(0); + String nsURI = ePackage.getNsURI(); + if (!nsURI.endsWith("/")) + { + nsURI += "/"; + } + + Pattern pattern = Pattern.compile("/v[0-9]+/"); + Matcher matcher = pattern.matcher(nsURI); + if (matcher.find()) + { + int start = matcher.start(); + int end = matcher.end(); + String prefix = nsURI.substring(0, start); + String suffix = nsURI.substring(end, nsURI.length() - 1); + + nsURI = prefix + "/v" + nextVersion + "/" + suffix; + } + else + { + nsURI += "v" + nextVersion; + } + + ePackage.setNsURI(nsURI); + } + }); + + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_DisableUniqueNamespaceEnforcement"), null, false, diagnostic.getCode()) + { + @Override + public int getRelevanceForResolution() + { + return -100; + } + + @Override + public void run(Diagnostic diagnostic) + { + Evolution evolution = (Evolution)diagnostic.getData().get(3); + evolution.setUniqueNamespaces(false); + } + }); + } + + protected void handleNoID(Diagnostic diagnostic, final Context context) + { + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_AssignID"), null, true, diagnostic.getCode()) + { + @Override + protected DiagnosticType[] getCompatibleTypes() + { + return new DiagnosticType[] { getType(), new DiagnosticType(EvolutionValidator.DIAGNOSTIC_SOURCE, EvolutionValidator.CODE_ID_WITHOUT_VALUE) }; + } + + @Override + public void run(Diagnostic diagnostic) + { + EModelElement modelElement = (EModelElement)diagnostic.getData().get(0); + IDAnnotation.ensureValue(modelElement); + } + }); + } + + protected void handleIDNotUnique(Diagnostic diagnostic, final Context context) + { + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_RememberID"), null, true, diagnostic.getCode()) + { + @Override + public int getRelevanceForResolution() + { + return 100; + } + + @Override + public void run(Diagnostic diagnostic) + { + EModelElement modelElement = (EModelElement)diagnostic.getData().get(0); + String oldValue = IDAnnotation.getValue(modelElement); + IDAnnotation.setOldValue(modelElement, oldValue); + IDAnnotation.setValue(modelElement, null); + IDAnnotation.ensureValue(modelElement); + } + }); + + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_ReplaceID"), null, true, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + EModelElement modelElement = (EModelElement)diagnostic.getData().get(0); + IDAnnotation.setValue(modelElement, null); + IDAnnotation.ensureValue(modelElement); + } + }); + } + + protected void handleFeaturePathUnknown(Diagnostic diagnostic, Context context) + { + final ElementChange elementChange = (ElementChange)diagnostic.getData().get(0); + final ChangeKind kind = elementChange.getKind(); + + context.add(new EvolutionDiagnosticResolution(null, + getString("_QF_SpecifyFeaturePath", kind.getName().toLowerCase(), ElementHandler.getLabel(elementChange.getNewElement())), null, false, + diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + FeaturePathMigration migration = EvolutionFactory.eINSTANCE.createFeaturePathMigration(); + migration.setDiagnosticID(DiagnosticID.get(diagnostic).getValue()); + migration.setFromClass(((EStructuralFeature)elementChange.getOldElement()).getEContainingClass()); + migration.setToClass(((EStructuralFeature)elementChange.getNewElement()).getEContainingClass()); + + Evolution evolution = (Evolution)elementChange.getNewModelSet(); + evolution.getMigrations().add(migration); + } + }); + } + + protected void handleRelease(Diagnostic diagnostic, final Context context) + { + final EvolutionImpl evolution = (EvolutionImpl)diagnostic.getData().get(0); + final int nextVersion = evolution.getNextReleaseVersion(); + + context.add(new EvolutionDiagnosticResolution(null, getString("_QF_CreateRelease", nextVersion), null, false, diagnostic.getCode()) + { + @Override + public void run(Diagnostic diagnostic) + { + Release release = EvolutionFactory.eINSTANCE.createRelease(); + release.setDate(new Date()); + release.setVersion(nextVersion); + + evolution.getReleases().add(release); + + Collection<EPackage> rootPackages = EcoreUtil.copyAll(evolution.getRootPackages()); + release.getRootPackages().addAll(rootPackages); + + for (EPackage rootPackage : evolution.getRootPackages()) + { + ElementHandler.execute(rootPackage, new ElementRunnable() + { + public void run(EModelElement modelElement) + { + IDAnnotation.setOldValue(modelElement, null); + } + }); + } + + ModelSetChangeImpl change = (ModelSetChangeImpl)evolution.getChange(); + if (change != null) + { + change.reset(); + evolution.setChange(null); + } + } + }); + } + + /** + * @author Eike Stepper + */ + protected static abstract class EvolutionDiagnosticResolution extends BasicDiagnosticResolution.TypedDiagnosticResolution + { + protected EvolutionDiagnosticResolution(Image image, String text, String description, boolean multi, int code) + { + super(image, text, description, multi, EvolutionValidator.DIAGNOSTIC_SOURCE, code); + } + } + + /** + * @author Eike Stepper + */ + public static class Factory extends DiagnosticResolution.Generator.Factory + { + public Factory() + { + } + + @Override + public Generator create(String description) throws ProductCreationException + { + return new DefaultDiagnosticResolutionGenerator(); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolution.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolution.java new file mode 100644 index 0000000000..603b7467e4 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolution.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.presentation.EvolutionEditor; +import org.eclipse.emf.cdo.evolution.presentation.quickfix.DiagnosticResolution.Generator.Context; + +import org.eclipse.net4j.util.container.IPluginContainer; +import org.eclipse.net4j.util.factory.ProductCreationException; + +import org.eclipse.emf.common.util.Diagnostic; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.swt.graphics.Image; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eike Stepper + */ +public abstract class DiagnosticResolution +{ + public static final Diagnostic[] NO_DIAGNOSTICS = {}; + + public abstract Image getImage(); + + public abstract String getText(); + + public abstract String getDescription(); + + public abstract void run(Diagnostic diagnostic); + + public void run(Diagnostic[] diagnostics, IProgressMonitor monitor) + { + for (Diagnostic diagnostic : diagnostics) + { + monitor.subTask(diagnostic.getMessage()); + run(diagnostic); + } + } + + public Diagnostic[] findOtherDiagnostics(Diagnostic[] diagnostics) + { + return NO_DIAGNOSTICS; + } + + public static DiagnosticResolution[] getResolutions(Diagnostic diagnostic, final EvolutionEditor editor) + { + final List<DiagnosticResolution> result = new ArrayList<DiagnosticResolution>(); + Context context = new Generator.Context() + { + public EvolutionEditor getEditor() + { + return editor; + } + + public void add(DiagnosticResolution resolution) + { + result.add(resolution); + } + }; + + for (String factoryType : IPluginContainer.INSTANCE.getFactoryTypes(Generator.Factory.PRODUCT_GROUP)) + { + Generator generator = (Generator)IPluginContainer.INSTANCE.getElement(Generator.Factory.PRODUCT_GROUP, factoryType, null); + generator.getResolutions(diagnostic, context); + } + + return result.toArray(new DiagnosticResolution[result.size()]); + } + + /** + * @author Eike Stepper + */ + public interface Generator + { + public void getResolutions(Diagnostic diagnostic, Context context); + + /** + * @author Eike Stepper + */ + public interface Context + { + public EvolutionEditor getEditor(); + + public void add(DiagnosticResolution resolution); + } + + /** + * @author Eike Stepper + */ + public static abstract class Factory extends org.eclipse.net4j.util.factory.Factory + { + public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.evolution.diagnosticResolutionGenerators"; + + public static final String DEFAULT_TYPE = "default"; + + public Factory() + { + this(DEFAULT_TYPE); + } + + public Factory(String type) + { + super(PRODUCT_GROUP, type); + } + + public abstract Generator create(String description) throws ProductCreationException; + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolutionRelevance.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolutionRelevance.java new file mode 100644 index 0000000000..88f67d482a --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/DiagnosticResolutionRelevance.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +/** + * @author Eike Stepper + */ +public interface DiagnosticResolutionRelevance +{ + public int getRelevanceForResolution(); +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixPage.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixPage.java new file mode 100644 index 0000000000..fb48612ff7 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixPage.java @@ -0,0 +1,408 @@ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.presentation.EvolutionEditor; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.edit.command.ChangeCommand; +import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.statushandlers.StatusManager; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Map; + +/** + * QuickFixPage is a page for the quick fixes of a marker. + * + * @since 3.4 + * + */ +public class QuickFixPage extends WizardPage +{ + private Map<DiagnosticResolution, Collection<Diagnostic>> resolutionsMap; + + private TableViewer resolutionsViewer; + + private CheckboxTableViewer diagnosticsViewer; + + private final Diagnostic[] selectedDiagnostics; + + private AdapterFactoryEditingDomain editingDomain; + + public QuickFixPage(String problemDescription, Diagnostic[] selectedDiagnostics, Map<DiagnosticResolution, Collection<Diagnostic>> resolutionsMap, + AdapterFactoryEditingDomain editingDomain) + { + super("QuickFixPage"); + this.selectedDiagnostics = selectedDiagnostics; + this.resolutionsMap = resolutionsMap; + this.editingDomain = editingDomain; + + setTitle("Quick Fix"); + setMessage(problemDescription); + } + + public void createControl(Composite parent) + { + initializeDialogUnits(parent); + + // Create a new composite as there is the title bar separator to deal with + Composite control = new Composite(parent, SWT.NONE); + control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + setControl(control); + + // PlatformUI.getWorkbench().getHelpSystem().setHelp(control, IWorkbenchHelpContextIds.PROBLEMS_VIEW); + + FormLayout layout = new FormLayout(); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.spacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + control.setLayout(layout); + + Label resolutionsLabel = new Label(control, SWT.NONE); + resolutionsLabel.setText("&Select a fix:"); + resolutionsLabel.setLayoutData(new FormData()); + + createResolutionsList(control); + + FormData listData = new FormData(); + listData.top = new FormAttachment(resolutionsLabel, 0); + listData.left = new FormAttachment(0); + listData.right = new FormAttachment(100, 0); + listData.height = convertHeightInCharsToPixels(10); + resolutionsViewer.getControl().setLayoutData(listData); + + Label title = new Label(control, SWT.NONE); + title.setText("&Problems:"); + FormData labelData = new FormData(); + labelData.top = new FormAttachment(resolutionsViewer.getControl(), 0); + labelData.left = new FormAttachment(0); + title.setLayoutData(labelData); + + createDiagnosticsViewer(control); + + Composite buttons = createTableButtons(control); + FormData buttonData = new FormData(); + buttonData.top = new FormAttachment(title, 0); + buttonData.right = new FormAttachment(100); + buttonData.height = convertHeightInCharsToPixels(10); + buttons.setLayoutData(buttonData); + + FormData tableData = new FormData(); + tableData.top = new FormAttachment(buttons, 0, SWT.TOP); + tableData.left = new FormAttachment(0); + tableData.bottom = new FormAttachment(100); + tableData.right = new FormAttachment(buttons, 0); + tableData.height = convertHeightInCharsToPixels(10); + diagnosticsViewer.getControl().setLayoutData(tableData); + + Dialog.applyDialogFont(control); + + resolutionsViewer.setSelection(new StructuredSelection(resolutionsViewer.getElementAt(0))); + + diagnosticsViewer.setCheckedElements(selectedDiagnostics); + + setPageComplete(diagnosticsViewer.getCheckedElements().length > 0); + } + + private Composite createTableButtons(Composite control) + { + Composite buttonComposite = new Composite(control, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + buttonComposite.setLayout(layout); + + Button selectAll = new Button(buttonComposite, SWT.PUSH); + selectAll.setText("Select &All"); + selectAll.setLayoutData(new GridData(SWT.FILL, SWT.NONE, false, false)); + selectAll.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent arg0) + { + diagnosticsViewer.setAllChecked(true); + setPageComplete(!resolutionsViewer.getStructuredSelection().isEmpty()); + } + }); + + Button deselectAll = new Button(buttonComposite, SWT.PUSH); + deselectAll.setText("&Deselect All"); + deselectAll.setLayoutData(new GridData(SWT.FILL, SWT.NONE, false, false)); + deselectAll.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent arg0) + { + diagnosticsViewer.setAllChecked(false); + setPageComplete(false); + } + }); + + return buttonComposite; + } + + private void createResolutionsList(Composite control) + { + resolutionsViewer = new TableViewer(control, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL); + resolutionsViewer.setContentProvider(new IStructuredContentProvider() + { + public Object[] getElements(Object inputElement) + { + return resolutionsMap.keySet().toArray(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + } + + public void dispose() + { + } + }); + + resolutionsViewer.setLabelProvider(new LabelProvider() + { + @Override + public String getText(Object element) + { + return ((DiagnosticResolution)element).getText(); + } + + @Override + public Image getImage(Object element) + { + return ((DiagnosticResolution)element).getImage(); + } + }); + + resolutionsViewer.setComparator(new ViewerComparator() + { + /** + * This comparator compares the resolutions based on the relevance of the + * resolutions. Any resolution that doesn't implement DiagnosticResolutionRelevance + * will be deemed to have relevance 0 (default value for relevance). If both + * resolutions have the same relevance, then marker resolution label string will + * be used for comparing the resolutions. + * + * @see DiagnosticResolutionRelevance#getRelevanceForResolution() + */ + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + int relevanceMarker1 = e1 instanceof DiagnosticResolutionRelevance ? ((DiagnosticResolutionRelevance)e1).getRelevanceForResolution() : 0; + int relevanceMarker2 = e2 instanceof DiagnosticResolutionRelevance ? ((DiagnosticResolutionRelevance)e2).getRelevanceForResolution() : 0; + if (relevanceMarker1 != relevanceMarker2) + { + return Integer.valueOf(relevanceMarker2).compareTo(Integer.valueOf(relevanceMarker1)); + } + + return ((DiagnosticResolution)e1).getText().compareTo(((DiagnosticResolution)e2).getText()); + } + }); + + resolutionsViewer.addSelectionChangedListener(new ISelectionChangedListener() + { + public void selectionChanged(SelectionChangedEvent event) + { + diagnosticsViewer.refresh(); + setPageComplete(diagnosticsViewer.getCheckedElements().length > 0); + } + }); + + resolutionsViewer.setInput(this); + } + + private void createDiagnosticsViewer(Composite parent) + { + diagnosticsViewer = CheckboxTableViewer.newCheckList(parent, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE); + diagnosticsViewer.setContentProvider(new DiagnosticsContentProvider()); + diagnosticsViewer.setInput(this); + + Table table = diagnosticsViewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + EvolutionEditor.createDiagnosticElementColumn(diagnosticsViewer, editingDomain.getAdapterFactory()); + EvolutionEditor.createDiagnosticResourceColumn(diagnosticsViewer, editingDomain.getAdapterFactory()); + + diagnosticsViewer.addCheckStateListener(new ICheckStateListener() + { + public void checkStateChanged(CheckStateChangedEvent event) + { + if (event.getChecked() == true) + { + setPageComplete(true); + } + else + { + setPageComplete(diagnosticsViewer.getCheckedElements().length > 0); + } + } + }); + + // new OpenAndLinkWithEditorHelper(markersTable) + // { + // { + // setLinkWithEditor(false); + // } + // + // @Override + // protected void activate(ISelection selection) + // { + // open(selection, true); + // } + // + // /** Not supported*/ + // + // @Override + // protected void linkToEditor(ISelection selection) + // { + // } + // + // @Override + // protected void open(ISelection selection, boolean activate) + // { + // if (selection.isEmpty()) + // { + // return; + // } + // Diagnostic marker = (Diagnostic)((IStructuredSelection)selection).getFirstElement(); + // if (marker != null && marker.getResource() instanceof IFile) + // { + // try + // { + // IDE.openEditor(site.getPage(), marker, activate); + // } + // catch (PartInitException e) + // { + // MarkerSupportInternalUtilities.showViewError(e); + // } + // } + // } + // }; + } + + public Diagnostic getSelectedDiagnostic() + { + IStructuredSelection selection = diagnosticsViewer.getStructuredSelection(); + if (!selection.isEmpty()) + { + if (selection.size() == 1) + { + return (Diagnostic)selection.getFirstElement(); + } + } + + return null; + } + + void performFinish(IProgressMonitor monitor) + { + final DiagnosticResolution resolution = getSelectedResolution(); + if (resolution == null) + { + return; + } + + final Object[] checked = diagnosticsViewer.getCheckedElements(); + if (checked.length == 0) + { + return; + } + + try + { + getWizard().getContainer().run(false, true, new IRunnableWithProgress() + { + public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException + { + final Diagnostic[] diagnostics = new Diagnostic[checked.length]; + System.arraycopy(checked, 0, diagnostics, 0, checked.length); + + ChangeCommand command = new ChangeCommand(editingDomain.getResourceSet()) + { + @Override + protected void doExecute() + { + resolution.run(diagnostics, monitor); + } + }; + + editingDomain.getCommandStack().execute(command); + } + }); + } + catch (InvocationTargetException e) + { + StatusManager.getManager().handle(QuickFixWizard.newStatus(IStatus.ERROR, e.getLocalizedMessage(), e)); + } + catch (InterruptedException e) + { + StatusManager.getManager().handle(QuickFixWizard.newStatus(IStatus.ERROR, e.getLocalizedMessage(), e)); + } + } + + private DiagnosticResolution getSelectedResolution() + { + return (DiagnosticResolution)resolutionsViewer.getStructuredSelection().getFirstElement(); + } + + /** + * @author Eike Stepper + */ + private final class DiagnosticsContentProvider implements IStructuredContentProvider + { + public Object[] getElements(Object inputElement) + { + DiagnosticResolution selected = getSelectedResolution(); + if (selected != null && resolutionsMap.containsKey(selected)) + { + return resolutionsMap.get(selected).toArray(); + } + + return DiagnosticResolution.NO_DIAGNOSTICS; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + } + + public void dispose() + { + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixWizard.java b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixWizard.java new file mode 100644 index 0000000000..d9a677846f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.evolution.editor/src/org/eclipse/emf/cdo/evolution/presentation/quickfix/QuickFixWizard.java @@ -0,0 +1,115 @@ +package org.eclipse.emf.cdo.evolution.presentation.quickfix; + +import org.eclipse.emf.cdo.evolution.presentation.EvolutionEditorPlugin; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.ui.statushandlers.StatusManager; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Map; + +/** + * The wizard for quick fixes. + */ +public class QuickFixWizard extends Wizard +{ + private Diagnostic[] selectedDiagnostics; + + private Map<DiagnosticResolution, Collection<Diagnostic>> resolutionsMap; + + private String description; + + private AdapterFactoryEditingDomain editingDomain; + + public QuickFixWizard(String description, Diagnostic[] selectedDiagnostics, Map<DiagnosticResolution, Collection<Diagnostic>> resolutionsMap, + AdapterFactoryEditingDomain editingDomain) + { + this.selectedDiagnostics = selectedDiagnostics; + this.resolutionsMap = resolutionsMap; + this.description = description; + this.editingDomain = editingDomain; + + setNeedsProgressMonitor(true); + setDefaultPageImageDescriptor(ExtendedImageRegistry.INSTANCE + .getImageDescriptor(URI.createPlatformPluginURI(EvolutionEditorPlugin.PLUGIN_ID + "/icons/full/wizban/quick_fix.png", true))); + } + + @Override + public void addPages() + { + super.addPages(); + addPage(new QuickFixPage(description, selectedDiagnostics, resolutionsMap, editingDomain)); + } + + @Override + public boolean performFinish() + { + IRunnableWithProgress finishRunnable = new IRunnableWithProgress() + { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException + { + IWizardPage[] pages = getPages(); + SubMonitor subMonitor = SubMonitor.convert(monitor, "Fixing", 10 * pages.length + 1); + subMonitor.worked(1); + for (IWizardPage page : pages) + { + // Allow for cancel event processing + getShell().getDisplay().readAndDispatch(); + QuickFixPage wizardPage = (QuickFixPage)page; + wizardPage.performFinish(subMonitor.split(10)); + } + } + }; + + try + { + getContainer().run(false, true, finishRunnable); + } + catch (InvocationTargetException e) + { + StatusManager.getManager().handle(newStatus(IStatus.ERROR, e.getLocalizedMessage(), e)); + return false; + } + catch (InterruptedException e) + { + StatusManager.getManager().handle(newStatus(IStatus.ERROR, e.getLocalizedMessage(), e)); + return false; + } + + return true; + } + + public static IStatus newStatus(int severity, String message, Throwable exception) + { + String statusMessage = message; + if (message == null || message.trim().length() == 0) + { + if (exception == null) + { + throw new IllegalArgumentException(); + } + else if (exception.getMessage() == null) + { + statusMessage = exception.toString(); + } + else + { + statusMessage = exception.getMessage(); + } + } + + return new Status(severity, EvolutionEditorPlugin.PLUGIN_ID, severity, statusMessage, exception); + } +} |