diff options
| author | pguilet | 2017-02-10 16:02:22 +0000 |
|---|---|---|
| committer | pguilet | 2017-03-24 14:17:53 +0000 |
| commit | 071c53c1e669f700d799fd5fca9dd7ceac968779 (patch) | |
| tree | 24f75f3d7c59d156bc3f96688f330722c0a0aaf7 | |
| parent | 47ed885a5666d0b8c1e597eee865dc0cfbe0ce53 (diff) | |
| download | org.eclipse.sirius-071c53c1e669f700d799fd5fca9dd7ceac968779.tar.gz org.eclipse.sirius-071c53c1e669f700d799fd5fca9dd7ceac968779.tar.xz org.eclipse.sirius-071c53c1e669f700d799fd5fca9dd7ceac968779.zip | |
[512104] Fix Sirius table editor not working after external aird changes
- Update editors' tree viewer's components with new DRepresentation
replacing the used one when manual aird modification is done so they can
work after.
- Add tests.
Bug: 512104
Change-Id: If4a865c659fd0bac98f1223ed680db3268d5c00a
Signed-off-by: pguilet <pierre.guilet@obeo.fr>
13 files changed, 631 insertions, 135 deletions
diff --git a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/AbstractDTableEditor.java b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/AbstractDTableEditor.java index 7dd977733b..3df862f271 100644 --- a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/AbstractDTableEditor.java +++ b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/AbstractDTableEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2008, 2017 THALES GLOBAL SERVICES 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 @@ -111,10 +111,9 @@ public abstract class AbstractDTableEditor extends AbstractDTreeEditor implement if (isDeleted(getEditorInput())) { if (isSaveAsAllowed()) { /* - * 1GEUSSR: ITPUI:ALL - User should never loose changes made in - * the editors. Changed Behavior to make sure that if called - * inside a regular save (because of deletion of input element) - * there is a way to report back to the caller. + * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. Changed Behavior to make + * sure that if called inside a regular save (because of deletion of input element) there is a way to + * report back to the caller. */ performSaveAs(progressMonitor); } else { @@ -286,9 +285,8 @@ public abstract class AbstractDTableEditor extends AbstractDTreeEditor implement } /** - * Overridden to update the UI part when the {@link DTable} model is changed - * outside of a EMF Command (which notify DTableContentAdapter) in case of - * collab model. + * Overridden to update the UI part when the {@link DTable} model is changed outside of a EMF Command (which notify + * DTableContentAdapter) in case of collab model. * * {@inheritDoc} */ @@ -351,10 +349,9 @@ public abstract class AbstractDTableEditor extends AbstractDTreeEditor implement * @param uri * the URI to resolve. * @param loadOnDemand - * whether to create and load the resource, if it doesn't already - * exists. - * @return the DTable resource resolved by the URI, or <code>null</code> if - * there isn't one and it's not being demand loaded. + * whether to create and load the resource, if it doesn't already exists. + * @return the DTable resource resolved by the URI, or <code>null</code> if there isn't one and it's not being + * demand loaded. */ private DTable getDTable(final URI uri, final boolean loadOnDemand) { DTable result = null; @@ -415,8 +412,7 @@ public abstract class AbstractDTableEditor extends AbstractDTreeEditor implement } /** - * Sets the cursor and selection state for an editor to reveal the position - * of the given marker. + * Sets the cursor and selection state for an editor to reveal the position of the given marker. * * @param marker * the marker to go to @@ -498,4 +494,16 @@ public abstract class AbstractDTableEditor extends AbstractDTreeEditor implement refreshAtOpeningActivator = null; } } + + @Override + protected void updateEditorAfterAirdResourceReload() { + // We update all components that keeps Aird proxified element after an + // Aird resource reload. + treeViewerManager.updateDRepresentation(getTableModel()); + getSite().getPage().removePartListener(refreshAtOpeningActivator); + refreshAtOpeningActivator = new RefreshAtOpeningActivator(session, this); + getSite().getPage().addPartListener(refreshAtOpeningActivator); + treeViewerManager.getTreeViewer().refresh(); + } + } diff --git a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableMenuListener.java b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableMenuListener.java index 14dd24750b..2f622d2353 100644 --- a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableMenuListener.java +++ b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableMenuListener.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 THALES GLOBAL SERVICES and others. + * Copyright (c) 2007, 2017 THALES GLOBAL SERVICES 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 @@ -115,7 +115,7 @@ public class DTableMenuListener implements IMenuListener { private final AdapterFactory adapterFactory; - private final DTable dTable; + private DTable dTable; private final DTableViewerManager treeViewManager; @@ -155,15 +155,11 @@ public class DTableMenuListener implements IMenuListener { * @param treeViewManager * The manager of the TreeView * @param mappingToCreateActions - * A map which associates {@link TableMapping} with the - * corresponding list of {@link AbstractToolAction} ( - * {@link org.eclipse.sirius.table.ui.tools.internal.editor.action.CreateLineAction} - * or - * {@link org.eclipse.sirius.table.ui.tools.internal.editor.action.CreateTargetColumnAction} - * ) + * A map which associates {@link TableMapping} with the corresponding list of {@link AbstractToolAction} + * ( {@link org.eclipse.sirius.table.ui.tools.internal.editor.action.CreateLineAction} or + * {@link org.eclipse.sirius.table.ui.tools.internal.editor.action.CreateTargetColumnAction} ) * @param mappingToDeleteColumnActions - * A map which associates {@link TableMapping} with the - * corresponding + * A map which associates {@link TableMapping} with the corresponding * {@link org.eclipse.sirius.table.ui.tools.internal.editor.action.DeleteTargetColumnAction} * @param createActionsForTable * A list of the actions for create lines under the table. @@ -615,15 +611,14 @@ public class DTableMenuListener implements IMenuListener { } /** - * Tests whether a representation description belongs to a viewpoint which - * is currently active in the session. + * Tests whether a representation description belongs to a viewpoint which is currently active in the session. * * @param session * the current session. * @param representationDescription * the representation description to check. - * @return <code>true</code> if the representation description belongs to a - * viewpoint which is currently active in the session. + * @return <code>true</code> if the representation description belongs to a viewpoint which is currently active in + * the session. */ private boolean isFromActiveViewpoint(final Session session, final RepresentationDescription representationDescription) { final Viewpoint vp = ViewpointRegistry.getInstance().getViewpoint(representationDescription); @@ -631,15 +626,13 @@ public class DTableMenuListener implements IMenuListener { } /** - * Tests whether a representation belongs to a viewpoint which is currently - * active in the session. + * Tests whether a representation belongs to a viewpoint which is currently active in the session. * * @param session * the current session. * @param representation * the representation to check. - * @return <code>true</code> if the representation belongs to a viewpoint - * which is currently active in the session. + * @return <code>true</code> if the representation belongs to a viewpoint which is currently active in the session. */ private boolean isFromActiveViewpoint(final Session session, final DRepresentation representation) { final RepresentationDescription description = DialectManager.INSTANCE.getDescription(representation); @@ -669,4 +662,9 @@ public class DTableMenuListener implements IMenuListener { public void setCreateActionsForTable(final List<AbstractToolAction> createActionsForTable) { this.createActionsForTable = createActionsForTable; } + + public void setTable(DTable newDRepresentation) { + this.dTable = newDRepresentation; + + } } diff --git a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableViewerManager.java b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableViewerManager.java index 3a3532ce3f..1395d7d836 100644 --- a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableViewerManager.java +++ b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/DTableViewerManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2008, 2017 THALES GLOBAL SERVICES 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 @@ -74,6 +74,7 @@ import org.eclipse.sirius.ui.tools.internal.editor.DTableTreeFocusListener; import org.eclipse.sirius.ui.tools.internal.editor.DescriptionFileChangedNotifier; import org.eclipse.sirius.ui.tools.internal.editor.SelectDRepresentationElementsListener; import org.eclipse.sirius.ui.tools.internal.views.common.navigator.adapters.ModelDragTargetAdapter; +import org.eclipse.sirius.viewpoint.DRepresentation; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.ByteArrayTransfer; import org.eclipse.swt.dnd.DND; @@ -157,6 +158,11 @@ public class DTableViewerManager extends AbstractDTableViewerManager { } /** + * True if the dRepresentation has just been replaced. + */ + protected boolean dRepresentationReplaced; + + /** * the current active column. */ private int activeColumn = -1; @@ -179,6 +185,10 @@ public class DTableViewerManager extends AbstractDTableViewerManager { private SelectDRepresentationElementsListener selectTableElementsListener; + private TreeColumnLayout treeLayout; + + private Composite composite; + /** * The constructor. * @@ -212,49 +222,76 @@ public class DTableViewerManager extends AbstractDTableViewerManager { /** * Create the TreeViewer. * - * Problem for action on column header : - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=23103 + * Problem for action on column header : https://bugs.eclipse.org/bugs/show_bug.cgi?id=23103 * - * @param composite + * @param theComposite * the parent composite */ @Override - protected void createTreeViewer(final Composite composite) { + protected void createTreeViewer(final Composite theComposite) { + this.composite = theComposite; // Create a composite to hold the children final GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.FILL_BOTH); - composite.setLayoutData(gridData); - final TreeColumnLayout treeLayout = new TreeColumnLayout(); - composite.setLayout(treeLayout); + theComposite.setLayoutData(gridData); + treeLayout = new TreeColumnLayout(); + theComposite.setLayout(treeLayout); // Create and setup the TreeViewer final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI; - treeViewer = new DTableTreeViewer(composite, style, this); + treeViewer = new DTableTreeViewer(theComposite, style, this); + treeViewer.addTreeListener(tableViewerListener); + initializeDragSupport(); + treeViewer.setUseHashlookup(true); // Add a focus listener to deactivate the EMF actions on the Tree treeViewer.getTree().addFocusListener(new DTableTreeFocusListener(treeEditor, treeViewer.getTree())); - initializeDragSupport(); + descriptionFileChangedNotifier = new DescriptionFileChangedNotifier(this); + dTableContentProvider = new DTableContentProvider(); + treeViewer.setContentProvider(dTableContentProvider); + ColumnViewerToolTipSupport.enableFor(treeViewer); + treeViewer.getTree().setLinesVisible(true); + treeViewer.getTree().setHeaderVisible(true); + // Manage height of the lines, selected colors, + triggerCustomDrawingTreeItems(); + // Create a new CellFocusManager + final TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(treeViewer, new FocusCellOwnerDrawHighlighter(treeViewer)); + // Create a TreeViewerEditor with focusable cell + TreeViewerEditor.create(treeViewer, focusCellManager, new DTableColumnViewerEditorActivationStrategy(treeViewer), + ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); + initializeKeyBindingSupport(); + triggerColumnSelectedColumn(); + initializeColumnsAndComponentsRelatedToDRepresentation(treeLayout); + } + + /** + * Initialize the columns and everything initialized according to DRepresentation. + * + * @param theTreeLayout + * the tree layout used to layout the columns. + */ + private void initializeColumnsAndComponentsRelatedToDRepresentation(final TreeColumnLayout theTreeLayout) { + sortListener = new DLinesSorter(getEditingDomain(), getEditor().getTableModel()); // 1st column with line labels - TreeViewerColumn headerTreeColumn = addFirstColumn(treeLayout); + TreeViewerColumn headerTreeColumn = addFirstColumn(theTreeLayout); // Next columns int index = 1; for (final DColumn column : ((DTable) dRepresentation).getColumns()) { addNewColumn(column, index++); } - treeViewer.setUseHashlookup(true); + // TableUIUpdater must be called before {@link // SelectDRepresentationElementsListener} to have TreeItem created tableUIUpdater = new TableUIUpdater(this, dRepresentation); + + if (selectTableElementsListener != null) { + selectTableElementsListener.dispose(); + } selectTableElementsListener = new SelectDRepresentationElementsListener(treeEditor, true); - descriptionFileChangedNotifier = new DescriptionFileChangedNotifier(this); - dTableContentProvider = new DTableContentProvider(); - treeViewer.setContentProvider(dTableContentProvider); + // The input for the table viewer is the instance of DTable treeViewer.setInput(dRepresentation); - ColumnViewerToolTipSupport.enableFor(treeViewer); - treeViewer.getTree().setLinesVisible(true); - treeViewer.getTree().setHeaderVisible(true); + fillMenu(); - triggerColumnSelectedColumn(); // Expands the line according to the model treeViewer.setExpandedElements(TableHelper.getExpandedLines((DTable) dRepresentation).toArray()); @@ -267,22 +304,14 @@ public class DTableViewerManager extends AbstractDTableViewerManager { treeViewer.getTree().getColumn(i).pack(); } } - treeViewer.addTreeListener(tableViewerListener); - // Manage height of the lines, selected colors, - triggerCustomDrawingTreeItems(); - // Create a new CellFocusManager - final TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(treeViewer, new FocusCellOwnerDrawHighlighter(treeViewer)); - // Create a TreeViewerEditor with focusable cell - TreeViewerEditor.create(treeViewer, focusCellManager, new DTableColumnViewerEditorActivationStrategy(treeViewer), - ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); // Set after the setInput to avoid layout call it several time for // nothing at opening headerTreeColumn.getColumn().addControlListener(tableViewerListener); - initializeKeyBindingSupport(); + } - private TreeViewerColumn addFirstColumn(TreeColumnLayout treeLayout) { + private TreeViewerColumn addFirstColumn(TreeColumnLayout theTreeLayout) { DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.ADD_SWT_COLUMN_KEY); final TreeViewerColumn headerTreeColumn = new TreeViewerColumn(treeViewer, SWT.CENTER, 0); DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.SET_COLUMN_NAME_KEY); @@ -306,12 +335,12 @@ public class DTableViewerManager extends AbstractDTableViewerManager { headerTreeColumn.setLabelProvider(lineheaderColumnLabelProvider); int headerColumnWidth = ((DTable) dRepresentation).getHeaderColumnWidth(); if (headerColumnWidth != 0) { - treeLayout.setColumnData(headerTreeColumn.getColumn(), new ColumnPixelData(headerColumnWidth)); + theTreeLayout.setColumnData(headerTreeColumn.getColumn(), new ColumnPixelData(headerColumnWidth)); if (headerTreeColumn.getColumn().getWidth() != headerColumnWidth) { headerTreeColumn.getColumn().setWidth(headerColumnWidth); } } else { - treeLayout.setColumnData(headerTreeColumn.getColumn(), new ColumnWeightData(1)); + theTreeLayout.setColumnData(headerTreeColumn.getColumn(), new ColumnWeightData(1)); if (IS_GTK_OS) { // Do not launch treeViewerColumn.getColumn().pack() here // for windows because the size is computed only with the @@ -358,29 +387,26 @@ public class DTableViewerManager extends AbstractDTableViewerManager { } /** - * Initialize a cache and add, if needed, the contextual menu for the table. - * <BR> - * Cached the actions of creation and deletion in order to increase - * performance and not calculate it on each contextual menu.<BR> - * Problem for action on column header : - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=23103 <BR> + * Initialize a cache and add, if needed, the contextual menu for the table. <BR> + * Cached the actions of creation and deletion in order to increase performance and not calculate it on each + * contextual menu.<BR> + * Problem for action on column header : https://bugs.eclipse.org/bugs/show_bug.cgi?id=23103 <BR> */ @Override public void fillMenu() { - if (descriptionFileChanged) { + if (descriptionFileChanged || dRepresentationReplaced) { descriptionFileChanged = false; + final Map<TableMapping, DeleteTargetColumnAction> mappingToDeleteActions = Maps.newHashMap(); final Map<TableMapping, List<AbstractToolAction>> mappingToCreateActions = Maps.newHashMap(); final List<AbstractToolAction> createActionsForTable = Lists.newArrayList(); calculateAvailableMenus(mappingToDeleteActions, mappingToCreateActions, createActionsForTable); mgr.setRemoveAllWhenShown(true); - if (actualMenuListener != null) { - mgr.removeAll(); - actualMenuListener.setMappingToCreateActions(mappingToCreateActions); - actualMenuListener.setMappingToDeleteActions(mappingToDeleteActions); - actualMenuListener.setCreateActionsForTable(createActionsForTable); - } else { + if (dRepresentationReplaced || actualMenuListener == null) { + if (dRepresentationReplaced) { + mgr.removeMenuListener(actualMenuListener); + } actualMenuListener = new DTableMenuListener((DTable) dRepresentation, this, mappingToCreateActions, mappingToDeleteActions, createActionsForTable); mgr.addMenuListener(actualMenuListener); @@ -388,23 +414,27 @@ public class DTableViewerManager extends AbstractDTableViewerManager { treeViewer.getControl().setMenu(menu); // Add this line to have others contextual menus treeEditor.getSite().registerContextMenu(mgr, treeViewer); + } else { + mgr.removeAll(); + actualMenuListener.setMappingToCreateActions(mappingToCreateActions); + actualMenuListener.setMappingToDeleteActions(mappingToDeleteActions); + actualMenuListener.setCreateActionsForTable(createActionsForTable); } getCreateLineMenu().update(createActionsForTable); getCreateTargetColumnMenu().update(createActionsForTable); + dRepresentationReplaced = false; } } /** - * Create the menus according to the {@link TableMapping} and the associated - * {@link CreateTool} and {@link DeleteTool}. + * Create the menus according to the {@link TableMapping} and the associated {@link CreateTool} and + * {@link DeleteTool}. * * @param mappingToDeleteActions - * A map which associates {@link TableMapping} with the - * corresponding {@link DeleteTargetColumnAction} + * A map which associates {@link TableMapping} with the corresponding {@link DeleteTargetColumnAction} * @param mappingToCreateActions - * A map which associates {@link TableMapping} with the - * corresponding list of {@link AbstractToolAction} ( - * {@link CreateLineAction} or {@link CreateTargetColumnAction}) + * A map which associates {@link TableMapping} with the corresponding list of {@link AbstractToolAction} + * ( {@link CreateLineAction} or {@link CreateTargetColumnAction}) * @param createActionsForTable * A list of the actions for create lines under the table. */ @@ -441,18 +471,16 @@ public class DTableViewerManager extends AbstractDTableViewerManager { } /** - * Create the menus according to the {@link ElementColumnMapping} and the - * associated {@link CreateTool} and {@link DeleteTool}. + * Create the menus according to the {@link ElementColumnMapping} and the associated {@link CreateTool} and + * {@link DeleteTool}. * * @param columnMappings * List of {@link ElementColumnMapping} * @param mappingToDeleteActions - * A map which associates {@link TableMapping} with the - * corresponding {@link DeleteTargetColumnAction} + * A map which associates {@link TableMapping} with the corresponding {@link DeleteTargetColumnAction} * @param mappingToCreateActions - * A map which associates {@link TableMapping} with the - * corresponding list of {@link AbstractToolAction} ( - * {@link CreateLineAction} or {@link CreateTargetColumnAction}) + * A map which associates {@link TableMapping} with the corresponding list of {@link AbstractToolAction} + * ( {@link CreateLineAction} or {@link CreateTargetColumnAction}) */ private void calculateAvailableMenusForColumn(final EList<ElementColumnMapping> columnMappings, final Map<TableMapping, DeleteTargetColumnAction> mappingToDeleteActions, final Map<TableMapping, List<AbstractToolAction>> mappingToCreateActions) { @@ -476,15 +504,14 @@ public class DTableViewerManager extends AbstractDTableViewerManager { } /** - * Create the menus according to the {@link LineMapping} and the associated - * {@link CreateTool} and {@link DeleteTool}. + * Create the menus according to the {@link LineMapping} and the associated {@link CreateTool} and + * {@link DeleteTool}. * * @param lineMappings * List of {@link LineMapping} * @param mappingToCreateActions - * A map which associates {@link TableMapping} with the - * corresponding list of {@link AbstractToolAction} ( - * {@link CreateLineAction} or {@link CreateTargetColumnAction}) + * A map which associates {@link TableMapping} with the corresponding list of {@link AbstractToolAction} + * ( {@link CreateLineAction} or {@link CreateTargetColumnAction}) */ private void calculateAvailableMenusForLine(final EList<LineMapping> lineMappings, final Map<TableMapping, List<AbstractToolAction>> mappingToCreateActions, final List<LineMapping> processedLineMappings) { @@ -516,8 +543,7 @@ public class DTableViewerManager extends AbstractDTableViewerManager { } /** - * Add a listener on the tree to listen the mouseDouwn or the key left-right - * arrows and store the activeColumn. + * Add a listener on the tree to listen the mouseDouwn or the key left-right arrows and store the activeColumn. */ protected void triggerColumnSelectedColumn() { treeViewer.getTree().addMouseListener(new MouseAdapter() { @@ -611,8 +637,7 @@ public class DTableViewerManager extends AbstractDTableViewerManager { * @param index * the index at which to place the newly created column * @param changeInput - * true if we must change the input of the SWT tree to null - * before adding the SWT column, false otherwise + * true if we must change the input of the SWT tree to null before adding the SWT column, false otherwise */ public void addNewColumn(final DColumn newColumn, final int index, final boolean changeInput) { DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.ADD_SWT_COLUMN_KEY); @@ -750,4 +775,20 @@ public class DTableViewerManager extends AbstractDTableViewerManager { createTargetColumnMenu = null; } + @Override + public void updateDRepresentation(DRepresentation newDRepresentation) { + this.dRepresentation = newDRepresentation; + tableViewerListener.resetDTable(); + + getTreeViewer().getTree().removeAll(); + getTreeViewer().getTree().clearAll(true); + while (getTreeViewer().getTree().getColumnCount() > 0) { + getTreeViewer().getTree().getColumns()[0].dispose(); + } + treeLayout = new TreeColumnLayout(); + composite.setLayout(treeLayout); + dRepresentationReplaced = true; + initializeColumnsAndComponentsRelatedToDRepresentation(treeLayout); + + } } diff --git a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/listeners/DTableViewerListener.java b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/listeners/DTableViewerListener.java index 626cfb61d5..78caf321c6 100644 --- a/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/listeners/DTableViewerListener.java +++ b/plugins/org.eclipse.sirius.table.ui/src/org/eclipse/sirius/table/ui/tools/internal/editor/listeners/DTableViewerListener.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2015 THALES GLOBAL SERVICES. + * Copyright (c) 2011, 2017 THALES GLOBAL SERVICES. * 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 @@ -36,9 +36,8 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.TreeColumn; /** - * A {@link ITreeViewerListener} and {@link ControlListener} to update the - * DTable model when a SWT TreeItem is collapsed/expanded and - * {@link TreeColumn#getWidth()} change. + * A {@link ITreeViewerListener} and {@link ControlListener} to update the DTable model when a SWT TreeItem is + * collapsed/expanded and {@link TreeColumn#getWidth()} change. * * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a> */ @@ -150,4 +149,12 @@ public class DTableViewerListener implements ITreeViewerListener, ControlListene } } + /** + * Replace the current DTable used with the given one. + * + */ + public void resetDTable() { + this.dTable = (DTable) this.dTableViewerManager.getEditor().getRepresentation(); + } + } diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.aird b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.aird new file mode 100644 index 0000000000..8f22f5ffb3 --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.aird @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:description="http://www.eclipse.org/sirius/description/1.1.0" xmlns:description_1="http://www.eclipse.org/sirius/tree/description/1.0.0" xmlns:description_2="http://www.eclipse.org/sirius/table/description/1.1.0" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:table="http://www.eclipse.org/sirius/table/1.1.0" xmlns:tree="http://www.eclipse.org/sirius/tree/1.0.0" xmlns:viewpoint="http://www.eclipse.org/sirius/1.1.0" xsi:schemaLocation="http://www.eclipse.org/sirius/description/1.1.0 http://www.eclipse.org/sirius/1.1.0#//description http://www.eclipse.org/sirius/tree/description/1.0.0 http://www.eclipse.org/sirius/tree/1.0.0#//description http://www.eclipse.org/sirius/table/description/1.1.0 http://www.eclipse.org/sirius/table/1.1.0#//description"> + <viewpoint:DAnalysis xmi:id="_59Je0PIJEea1GeqoRSXufw" selectedViews="_BJd7kPIKEeaCXtca9wOvKA" version="11.1.0.201608251200"> + <semanticResources>manualAird.ecore</semanticResources> + <ownedViews xmi:type="viewpoint:DView" xmi:id="_BJd7kPIKEeaCXtca9wOvKA"> + <viewpoint xmi:type="description:Viewpoint" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']"/> + <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" xmi:id="_9qLDwPLFEeaQMeHKkdbtDQ" name="manualAirdTree" representation="_9qLDwfLFEeaQMeHKkdbtDQ"> + <description xmi:type="description_1:TreeDescription" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']"/> + <target xmi:type="ecore:EPackage" href="manualAird.ecore#/"/> + </ownedRepresentationDescriptors> + <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" xmi:id="_-Rh-sPLFEeaQMeHKkdbtDQ" name="manualAirdTable" representation="_-RilwPLFEeaQMeHKkdbtDQ"> + <description xmi:type="description_2:EditionTableDescription" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']"/> + <target xmi:type="ecore:EPackage" href="manualAird.ecore#/"/> + </ownedRepresentationDescriptors> + </ownedViews> + </viewpoint:DAnalysis> + <tree:DTree xmi:id="_9qLDwfLFEeaQMeHKkdbtDQ" name="manualAirdTree"> + <target xmi:type="ecore:EPackage" href="manualAird.ecore#/"/> + <ownedTreeItems xmi:type="tree:DTreeItem" xmi:id="_9qLDwvLFEeaQMeHKkdbtDQ" name="C1"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <ownedStyle xmi:type="tree:TreeItemStyle" xmi:id="_9qLDw_LFEeaQMeHKkdbtDQ"/> + <actualMapping xmi:type="description_1:TreeItemMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']/@subItemMappings[name='eclass2']"/> + </ownedTreeItems> + <ownedTreeItems xmi:type="tree:DTreeItem" xmi:id="_9qLDxPLFEeaQMeHKkdbtDQ" name="C2"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <ownedStyle xmi:type="tree:TreeItemStyle" xmi:id="_9qLDxfLFEeaQMeHKkdbtDQ"/> + <actualMapping xmi:type="description_1:TreeItemMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']/@subItemMappings[name='eclass2']"/> + </ownedTreeItems> + <ownedTreeItems xmi:type="tree:DTreeItem" xmi:id="_9qLDxvLFEeaQMeHKkdbtDQ" name="C3"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <ownedStyle xmi:type="tree:TreeItemStyle" xmi:id="_9qLDx_LFEeaQMeHKkdbtDQ"/> + <actualMapping xmi:type="description_1:TreeItemMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']/@subItemMappings[name='eclass2']"/> + </ownedTreeItems> + <description xmi:type="description_1:TreeDescription" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']"/> + </tree:DTree> + <table:DTable xmi:id="_-RilwPLFEeaQMeHKkdbtDQ" name="manualAirdTable" headerColumnWidth="59"> + <target xmi:type="ecore:EPackage" href="manualAird.ecore#/"/> + <lines xmi:type="table:DLine" xmi:id="_-RilwfLFEeaQMeHKkdbtDQ" label="C1"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <originMapping xmi:type="description_2:LineMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']/@ownedLineMappings[name='Classes']"/> + <cells xmi:type="table:DCell" xmi:id="_-RilwvLFEeaQMeHKkdbtDQ" label="true" column="_-RilyvLFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + </cells> + <cells xmi:type="table:DCell" xmi:id="_-Rilw_LFEeaQMeHKkdbtDQ" label="DC1" column="_-Rily_LFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C1"/> + </cells> + </lines> + <lines xmi:type="table:DLine" xmi:id="_-RilxPLFEeaQMeHKkdbtDQ" label="C2"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <originMapping xmi:type="description_2:LineMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']/@ownedLineMappings[name='Classes']"/> + <cells xmi:type="table:DCell" xmi:id="_-RilxfLFEeaQMeHKkdbtDQ" label="false" column="_-RilyvLFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + </cells> + <cells xmi:type="table:DCell" xmi:id="_-RilxvLFEeaQMeHKkdbtDQ" label="DC2" column="_-Rily_LFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C2"/> + </cells> + </lines> + <lines xmi:type="table:DLine" xmi:id="_-Rilx_LFEeaQMeHKkdbtDQ" label="C3"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <originMapping xmi:type="description_2:LineMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']/@ownedLineMappings[name='Classes']"/> + <cells xmi:type="table:DCell" xmi:id="_-RilyPLFEeaQMeHKkdbtDQ" label="false" column="_-RilyvLFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + </cells> + <cells xmi:type="table:DCell" xmi:id="_-RilyfLFEeaQMeHKkdbtDQ" label="DC3" column="_-Rily_LFEeaQMeHKkdbtDQ"> + <target xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + <semanticElements xmi:type="ecore:EClass" href="manualAird.ecore#//C3"/> + </cells> + </lines> + <columns xmi:type="table:DFeatureColumn" xmi:id="_-RilyvLFEeaQMeHKkdbtDQ" label="Is Abstract?" cells="_-RilwvLFEeaQMeHKkdbtDQ _-RilxfLFEeaQMeHKkdbtDQ _-RilyPLFEeaQMeHKkdbtDQ" width="75" featureName="abstract"> + <originMapping xmi:type="description_2:FeatureColumnMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']/@ownedColumnMappings[name='IsAbstractColumn']"/> + </columns> + <columns xmi:type="table:DFeatureColumn" xmi:id="_-Rily_LFEeaQMeHKkdbtDQ" label="Label" cells="_-Rilw_LFEeaQMeHKkdbtDQ _-RilxvLFEeaQMeHKkdbtDQ _-RilyfLFEeaQMeHKkdbtDQ" width="43" featureName="name"> + <originMapping xmi:type="description_2:FeatureColumnMapping" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']/@ownedColumnMappings[name='Class%20label']"/> + </columns> + <description xmi:type="description_2:EditionTableDescription" href="manualAird.odesign#//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTable']"/> + </table:DTable> +</xmi:XMI> diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.ecore b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.ecore new file mode 100644 index 0000000000..b49eda855b --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.ecore @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="root"> + <eClassifiers xsi:type="ecore:EClass" name="C1" abstract="true"/> + <eClassifiers xsi:type="ecore:EClass" name="C2"/> + <eClassifiers xsi:type="ecore:EClass" name="C3"/> +</ecore:EPackage> diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.odesign b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.odesign new file mode 100644 index 0000000000..02ab416438 --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/refresh/manualAirdModification/manualAird.odesign @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<description:Group xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:description="http://www.eclipse.org/sirius/description/1.1.0" xmlns:description_1="http://www.eclipse.org/sirius/table/description/1.1.0" xmlns:description_2="http://www.eclipse.org/sirius/tree/description/1.0.0" xmlns:tool="http://www.eclipse.org/sirius/description/tool/1.1.0" name="manualAird" version="11.1.1.201610211630"> + <ownedViewpoints name="manualAird" modelFileExtension="ecore"> + <ownedRepresentations xsi:type="description_1:EditionTableDescription" name="manualAirdTable" domainClass="EPackage"> + <ownedLineMappings name="Classes" domainClass="EClass" semanticCandidatesExpression="feature:eClassifiers"/> + <ownedColumnMappings name="IsAbstractColumn" headerLabelExpression="Is Abstract?" featureName="abstract" labelExpression="feature:abstract"/> + <ownedColumnMappings name="Class label" headerLabelExpression="Label" featureName="name" labelExpression="aql:'D'+self.name"> + <directEdit> + <variables name="element" documentation="The semantic currently edited element."/> + <variables name="lineSemantic" documentation="The semantic element corresponding to the line."/> + <variables name="root" documentation="The semantic root element of the table."/> + <firstModelOperation xsi:type="tool:ChangeContext" browseExpression="var:element"> + <subModelOperations xsi:type="tool:SetValue" featureName="name" valueExpression="var:arg0"/> + </firstModelOperation> + <mask mask="{0}"/> + </directEdit> + </ownedColumnMappings> + </ownedRepresentations> + <ownedRepresentations xsi:type="description_2:TreeDescription" name="manualAirdTree" domainClass="EPackage"> + <subItemMappings name="eclass2" domainClass="ecore.EClass" semanticCandidatesExpression="feature:eAllContents"> + <defaultStyle> + <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/> + <backgroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/> + </defaultStyle> + <directEdit name="directEdit" mapping="//@ownedViewpoints[name='manualAird']/@ownedRepresentations[name='manualAirdTree']/@subItemMappings[name='eclass2']"> + <firstModelOperation xsi:type="tool:ChangeContext" browseExpression="var:element"> + <subModelOperations xsi:type="tool:SetValue" featureName="name" valueExpression="var:arg0"/> + </firstModelOperation> + <mask mask="{0}"/> + <element name="element"/> + <root name="root"/> + </directEdit> + </subItemMappings> + </ownedRepresentations> + </ownedViewpoints> +</description:Group> diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/ManualAirdModificationTest.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/ManualAirdModificationTest.java new file mode 100644 index 0000000000..edfea0214e --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/ManualAirdModificationTest.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tests.swtbot; + +import static org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable.syncExec; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Optional; +import java.util.stream.Stream; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.business.api.session.SessionStatus; +import org.eclipse.sirius.table.metamodel.table.DTable; +import org.eclipse.sirius.tests.swtbot.support.api.AbstractSiriusSwtBotGefTestCase; +import org.eclipse.sirius.tests.swtbot.support.api.business.UIResource; +import org.eclipse.sirius.tests.swtbot.support.utils.SWTBotUtils; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; +import org.eclipse.swtbot.swt.finder.SWTBot; +import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; +import org.eclipse.swtbot.swt.finder.results.IntResult; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; + +/** + * Tests behavior of table and tree editors when the aird is manually modified + * whereas editors are already opened. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +public class ManualAirdModificationTest extends AbstractSiriusSwtBotGefTestCase { + + private static final String PATH = "data/unit/refresh/manualAirdModification/"; + + private static final String SEMANTIC_RESOURCE_NAME = "manualAird.ecore"; + + private static final String REPRESENTATIONS_RESOURCE_NAME = "manualAird.aird"; + + private static final String MODELER_RESOURCE_NAME = "manualAird.odesign"; + + private SWTBotTree tableTree; + + private SWTBotEditor tableEditor; + + private SWTBotEditor treeEditor; + + private Session session; + + private URI airdResourceUri; + + @Override + protected void onSetUpAfterOpeningDesignerPerspective() throws Exception { + sessionAirdResource = new UIResource(designerProject, "/", REPRESENTATIONS_RESOURCE_NAME); + localSession = designerPerspective.openSessionFromFile(sessionAirdResource, true); + session = localSession.getOpenedSession(); + + tableEditor = openRepresentation(localSession.getOpenedSession(), "manualAirdTable", "manualAirdTable", DTable.class); + tableTree = tableEditor.bot().tree(); + + treeEditor = openRepresentation(localSession.getOpenedSession(), "manualAirdTree", "manualAirdTree", DTree.class); + + airdResourceUri = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(sessionAirdResource.getFullPath())).getRawLocationURI(); + + } + + @Override + protected void onSetUpBeforeClosingWelcomePage() throws Exception { + copyFileToTestProject(Activator.PLUGIN_ID, PATH, SEMANTIC_RESOURCE_NAME, REPRESENTATIONS_RESOURCE_NAME, MODELER_RESOURCE_NAME); + } + + /** + * Test that modifications made outside of the session does not break + * current opened table and tree editors. + * + * @throws IOException + * if a problem occurs when modifying representations file + * outside of the session. + * @throws CoreException + * if a problem occurs when refreshing workspace project. + */ + public void testManualAirdModificationBehavior() throws IOException, CoreException { + // check original header column width + assertEquals("The original table header column width is not the expected one.", (Integer) 59, syncExec(new IntResult() { + @Override + public Integer run() { + return tableTree.widget.getColumns()[0].getWidth(); + } + })); + // We replace the header column width from 59 to 100 in the aird. + modifyRepresentationsFileOutsideOfTheSession("headerColumnWidth=\"59\"", "headerColumnWidth=\"100\""); + + // refresh workspace projects + ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName()).refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); + + SWTBotUtils.waitAllUiEvents(); + tableEditor.show(); + SWTBotUtils.waitAllUiEvents(); + + // check original header column width + assertEquals("The table header column width has not been updated after modification of representations file outside of the session.", (Integer) 100, syncExec(new IntResult() { + @Override + public Integer run() { + return tableTree.widget.getColumns()[0].getWidth(); + } + })); + + assertEquals("The session should not be dirty.", SessionStatus.SYNC, session.getStatus()); + + // We check property view is still linked to table selection + changeNameByUsingPropertyView(tableEditor, "C3", "C4"); + tableEditor.setFocus(); + assertEquals("The session should be dirty.", SessionStatus.DIRTY, session.getStatus()); + + // We check direct edit tool works for the table + directEditLabel(tableEditor, "C2", 'E'); + treeEditor.show(); + try { + treeEditor.bot().tree().getTreeItem("C4"); + } catch (WidgetNotFoundException e) { + fail("Tree cell has not been updated grapically."); + } + try { + treeEditor.bot().tree().getTreeItem("E"); + } catch (WidgetNotFoundException e) { + fail("Tree cell has not been updated grapically."); + } + session.save(new NullProgressMonitor()); + assertEquals("The session should not be dirty.", SessionStatus.SYNC, session.getStatus()); + + // We check property view is still linked to tree selection + changeNameByUsingPropertyView(treeEditor, "C1", "C7"); + treeEditor.setFocus(); + assertEquals("The session should be dirty.", SessionStatus.DIRTY, session.getStatus()); + + // We check direct edit tool works for the tree + directEditLabel(treeEditor, "E", 'F'); + tableEditor.show(); + treeEditor.show(); + + try { + treeEditor.bot().tree().getTreeItem("F"); + } catch (WidgetNotFoundException e) { + fail("Tree cell has not been updated grapically."); + } + try { + treeEditor.bot().tree().getTreeItem("C7"); + } catch (WidgetNotFoundException e) { + fail("Tree cell has not been updated grapically."); + } + } + + /** + * Replace the value in the aird matching the given reg exp oldValue by the + * new value. + * + * @param newValue + * the value used to replace mathing value in the aird. + * @param oldValue + * the reg exp used to find content in aird that will be replaced + * by the new value. + * @throws IOException + * if any problem occurs when modifying the aird. + * + */ + protected void modifyRepresentationsFileOutsideOfTheSession(String oldValue, String newValue) throws IOException { + java.nio.file.Path representationsFilePath = Paths.get(airdResourceUri); + // Read the content of the file + Optional<String> newContent = Optional.empty(); + try (BufferedReader br = Files.newBufferedReader(representationsFilePath)) { + // Replace the content + Stream<String> newContentStream = br.lines().map(line -> line.replace(oldValue, newValue)); + newContent = newContentStream.reduce((concatenatedLines, lineToConcat) -> concatenatedLines.concat(lineToConcat)); + } + if (newContent.isPresent()) { + // Write the new content + try (BufferedWriter bw = Files.newBufferedWriter(representationsFilePath, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) { + bw.write(newContent.get()); + } + } + } + + /** + * Direct edit the text cell with the given old value and replace the + * content with the given char. + * + * @param editor + * editor containing the text cell to edit. + * @param oldValue + * the value that should be changed. + * @param newChar + * the new value. + */ + protected void directEditLabel(SWTBotEditor editor, String oldValue, char newChar) { + SWTBotTreeItem tableItem = editor.bot().tree().getTreeItem(oldValue); + tableItem.select(); + tableItem.click(2); + SWTBotUtils.directEditWithKeyboard(tableTree.widget, newChar + ""); + } + + /** + * Change the value of the cell text containing the old value to the new one + * by clicking on it on the given editor and modifying it using the + * properties view. This tests that properties views are linked to editor + * selections. + * + * @param editor + * editor used to do the modification + * @param oldValue + * the EClass name old value to update + * @param newValue + * the EClass name new value. + */ + protected void changeNameByUsingPropertyView(SWTBotEditor editor, String oldValue, String newValue) { + editor.bot().tree().select(oldValue); + SWTBotUtils.waitAllUiEvents(); + bot.viewByTitle("Properties").setFocus(); + SWTBot propertiesBot = bot.viewByTitle("Properties").bot(); + try { + SWTBotTreeItem treeItem = propertiesBot.tree().getTreeItem(oldValue).getNode("Name"); + treeItem.select(); + treeItem.click(); + SWTBotText propertyText = propertiesBot.text(oldValue); + propertyText.setText(newValue); + } catch (WidgetNotFoundException e) { + fail("The properties view is not linked anymore to editor selection."); + } + } + +} diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java index f64de73bc4..25da22f11b 100644 --- a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java +++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2016 THALES GLOBAL SERVICES. + * Copyright (c) 2010, 2017 THALES GLOBAL SERVICES. * 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 @@ -162,6 +162,7 @@ public class AllTestSuite extends TestCase { suite.addTestSuite(EdgeLabelsMoveFromEdgeMoveTest.class); suite.addTestSuite(OpeningContextTest.class); suite.addTestSuite(NodeWithDecoratorSelectionTest.class); + suite.addTestSuite(ManualAirdModificationTest.class); } /** diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java index 23d43d61e0..552ef66f18 100644 --- a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2010, 2017 THALES GLOBAL SERVICES 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 @@ -248,9 +248,8 @@ public class DTreeEditor extends AbstractDTreeEditor implements org.eclipse.siri } /** - * Overridden to update the UI part when the {@link DTree} model is changed - * outside of a EMF Command (which notify DTreeContentAdapter) in case of - * collab model. + * Overridden to update the UI part when the {@link DTree} model is changed outside of a EMF Command (which notify + * DTreeContentAdapter) in case of collab model. * * {@inheritDoc} */ @@ -320,10 +319,9 @@ public class DTreeEditor extends AbstractDTreeEditor implements org.eclipse.siri * @param uri * the URI to resolve. * @param loadOnDemand - * whether to create and load the resource, if it doesn't already - * exists. - * @return the DTree resource resolved by the URI, or <code>null</code> if - * there isn't one and it's not being demand loaded. + * whether to create and load the resource, if it doesn't already exists. + * @return the DTree resource resolved by the URI, or <code>null</code> if there isn't one and it's not being demand + * loaded. */ private DTree getDTree(final URI uri, final boolean loadOnDemand) { DTree result = null; @@ -378,8 +376,7 @@ public class DTreeEditor extends AbstractDTreeEditor implements org.eclipse.siri } /** - * Sets the cursor and selection state for an editor to reveal the position - * of the given marker. + * Sets the cursor and selection state for an editor to reveal the position of the given marker. * * @param marker * the marker to go to @@ -494,4 +491,17 @@ public class DTreeEditor extends AbstractDTreeEditor implements org.eclipse.siri } return initialTitleImage; } + + @Override + protected void updateEditorAfterAirdResourceReload() { + // We update all components that keep Aird proxified element after an + // Aird resource reload. + treeViewerManager.updateDRepresentation(getTreeModel()); + getSite().getPage().removePartListener(refreshAtOpeningActivator); + refreshAtOpeningActivator = new RefreshAtOpeningActivator(this); + getSite().getPage().addPartListener(refreshAtOpeningActivator); + treeViewerManager.getTreeViewer().refresh(); + + } + } diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java index d021f20141..3c042c7ab4 100644 --- a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2010, 2017 THALES GLOBAL SERVICES 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 @@ -67,6 +67,7 @@ import org.eclipse.sirius.ui.tools.internal.editor.DTableTreeFocusListener; import org.eclipse.sirius.ui.tools.internal.editor.DescriptionFileChangedNotifier; import org.eclipse.sirius.ui.tools.internal.editor.SelectDRepresentationElementsListener; import org.eclipse.sirius.ui.tools.internal.views.common.navigator.adapters.ModelDragTargetAdapter; +import org.eclipse.sirius.viewpoint.DRepresentation; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.ByteArrayTransfer; import org.eclipse.swt.dnd.DND; @@ -116,6 +117,10 @@ public class DTreeViewerManager extends AbstractDTableViewerManager { private SelectDRepresentationElementsListener selectTableElementsListener; + private TreeColumnLayout treeLayout; + + private Composite composite; + /** * The constructor. * @@ -152,12 +157,13 @@ public class DTreeViewerManager extends AbstractDTableViewerManager { * the Container of the TreeViewer to create */ @Override - protected void createTreeViewer(final Composite composite) { + protected void createTreeViewer(final Composite theComposite) { + this.composite = theComposite; // Create a composite to hold the children final GridData gridData = new GridData(GridData.FILL_BOTH); composite.setLayoutData(gridData); - final TreeColumnLayout treeLayout = new TreeColumnLayout(); + treeLayout = new TreeColumnLayout(); composite.setLayout(treeLayout); // Create and setup the TreeViewer @@ -461,4 +467,22 @@ public class DTreeViewerManager extends AbstractDTableViewerManager { createTreeItemMenu.dispose(); } + @Override + public void updateDRepresentation(DRepresentation newDRepresentation) { + this.dRepresentation = newDRepresentation; + treeUIUpdater.dispose(); + treeUIUpdater = new TreeUIUpdater((DTreeViewer) treeViewer, dRepresentation); + + getTreeViewer().getTree().removeAll(); + getTreeViewer().getTree().clearAll(true); + + treeLayout = new TreeColumnLayout(); + composite.setLayout(treeLayout); + + treeViewer.setInput(dRepresentation); + + // Expands the line according to the model + treeViewer.setExpandedElements(TreeHelper.getExpandedItems((DTree) dRepresentation).toArray()); + } + } diff --git a/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTableViewerManager.java b/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTableViewerManager.java index d4d7f5eedc..62ee0653b9 100644 --- a/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTableViewerManager.java +++ b/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTableViewerManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2010, 2017 THALES GLOBAL SERVICES 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 @@ -62,7 +62,7 @@ public abstract class AbstractDTableViewerManager { /** * the model editing by this Viewer. */ - protected final DRepresentation dRepresentation; + protected DRepresentation dRepresentation; /** * The model accessor. @@ -148,7 +148,8 @@ public abstract class AbstractDTableViewerManager { protected abstract void createTreeViewer(Composite composite); /** - * Initialize a cache and add, if needed, the contextual menu for the table. <BR> + * Initialize a cache and add, if needed, the contextual menu for the table. + * <BR> * Cached the actions of creation and deletion in order to increase * performance and not calculate it on each contextual menu.<BR> * Problem for action on column header : @@ -230,4 +231,13 @@ public abstract class AbstractDTableViewerManager { descriptionFileChanged = modified; } + /** + * Update this viewer manager representation with the new given + * {@link DRepresentation}. It replaces all references to the old used one. + * + * @param newDRepresentation + * the representation that will replace the current one used. + */ + public abstract void updateDRepresentation(final DRepresentation newDRepresentation); + } diff --git a/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTreeEditor.java b/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTreeEditor.java index 26a22d6ea3..7b1d82c547 100644 --- a/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTreeEditor.java +++ b/plugins/org.eclipse.sirius.ui/src/org/eclipse/sirius/ui/tools/internal/editor/AbstractDTreeEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 THALES GLOBAL SERVICES and others. + * Copyright (c) 2008, 2017 THALES GLOBAL SERVICES 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 @@ -433,22 +433,11 @@ public abstract class AbstractDTreeEditor extends EditorPart @Override public void setFocus() { if (treeViewerManager != null) { - /* - * A regression in Kepler can cause an NPE inside the - * treeViewerManager.getControl().setFocus() below. The guard - * condition is a workaround, which seems to fix the problem (or at - * least the symptom) in our tests. See - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=378846#c16 - */ - AbstractDTreeViewer viewer = treeViewerManager.getTreeViewer(); - if (viewer != null && viewer.getTree() != null && viewer.getTree().getTopItem() != null) { - treeViewerManager.getControl().setFocus(); - } - setEclipseWindowTitle(); - // Resolve proxy model after aird reload. DRepresentation representation = getRepresentation(); + boolean representationProxyDetected = false; if (representation != null && representation.eIsProxy() && session != null) { + representationProxyDetected = true; IEditorInput editorInput = getEditorInput(); if (editorInput instanceof URIEditorInput) { URIEditorInput sessionEditorInput = (URIEditorInput) editorInput; @@ -475,12 +464,36 @@ public abstract class AbstractDTreeEditor extends EditorPart } checkSemanticAssociation(); + + if (representationProxyDetected) { + updateEditorAfterAirdResourceReload(); + } + /* + * A regression in Kepler can cause an NPE inside the + * treeViewerManager.getControl().setFocus() below. The guard + * condition is a workaround, which seems to fix the problem (or at + * least the symptom) in our tests. See + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=378846#c16 + */ + AbstractDTreeViewer viewer = treeViewerManager.getTreeViewer(); + if (viewer != null && viewer.getTree() != null && viewer.getTree().getTopItem() != null) { + treeViewerManager.getControl().setFocus(); + } + setEclipseWindowTitle(); + } else if (control != null) { control.setFocus(); } } /** + * Update all needed editor elements after an Aird resource reload like + * {@link Tree} or {@link AbstractDTableViewerManager} referencing previous + * Aird elements as proxies. + */ + protected abstract void updateEditorAfterAirdResourceReload(); + + /** * Retrieve and set the representation from the given URI. * * @param uri @@ -491,7 +504,10 @@ public abstract class AbstractDTreeEditor extends EditorPart */ protected abstract void setRepresentation(URI uri, boolean loadOnDemand); - private void checkSemanticAssociation() { + /** + * Close this editor if root element has been removed. + */ + protected void checkSemanticAssociation() { DRepresentation representation = getRepresentation(); boolean shouldClose = representation == null || representation.eResource() == null; if (!shouldClose && representation instanceof DSemanticDecorator) { |
