/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.tableeditor.cases; import java.util.Collection; import java.util.List; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.tools.services.IDirtyProviderService; import org.eclipse.e4.ui.di.Persist; import org.eclipse.e4.ui.di.UIEventTopic; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry; import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; import org.eclipse.nebula.widgets.nattable.data.IDataProvider; import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree.GlazedListTreeData; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree.GlazedListTreeRowModel; import org.eclipse.nebula.widgets.nattable.grid.cell.AlternatingRowConfigLabelAccumulator; import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer; import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer; import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer; import org.eclipse.nebula.widgets.nattable.hover.HoverLayer; import org.eclipse.nebula.widgets.nattable.layer.DataLayer; import org.eclipse.nebula.widgets.nattable.layer.ILayer; import org.eclipse.nebula.widgets.nattable.selection.EditTraversalStrategy; import org.eclipse.nebula.widgets.nattable.selection.ITraversalStrategy; import org.eclipse.nebula.widgets.nattable.selection.MoveCellSelectionCommandHandler; import org.eclipse.nebula.widgets.nattable.selection.RowSelectionProvider; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; import org.eclipse.nebula.widgets.nattable.sort.ISortModel; import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer; import org.eclipse.nebula.widgets.nattable.tree.ITreeRowModel; import org.eclipse.nebula.widgets.nattable.tree.TreeLayer; import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IEditorSite; import org.osgi.service.event.Event; import org.robotframework.ide.eclipse.main.plugin.RedPlugin; import org.robotframework.ide.eclipse.main.plugin.RedPreferences; import org.robotframework.ide.eclipse.main.plugin.RedPreferences.CellWrappingStrategy; import org.robotframework.ide.eclipse.main.plugin.assist.RedSettingProposals.SettingTarget; import org.robotframework.ide.eclipse.main.plugin.hyperlink.TableHyperlinksSupport; import org.robotframework.ide.eclipse.main.plugin.hyperlink.detectors.ITableHyperlinksDetector; import org.robotframework.ide.eclipse.main.plugin.hyperlink.detectors.TableHyperlinksToKeywordsDetector; import org.robotframework.ide.eclipse.main.plugin.hyperlink.detectors.TableHyperlinksToVariablesDetector; import org.robotframework.ide.eclipse.main.plugin.model.RobotCase; import org.robotframework.ide.eclipse.main.plugin.model.RobotCasesSection; import org.robotframework.ide.eclipse.main.plugin.model.RobotElement; import org.robotframework.ide.eclipse.main.plugin.model.RobotElementChange; import org.robotframework.ide.eclipse.main.plugin.model.RobotElementChange.Kind; import org.robotframework.ide.eclipse.main.plugin.model.RobotFileInternalElement; import org.robotframework.ide.eclipse.main.plugin.model.RobotKeywordCall; import org.robotframework.ide.eclipse.main.plugin.model.RobotModelEvents; import org.robotframework.ide.eclipse.main.plugin.model.RobotSuiteFile; import org.robotframework.ide.eclipse.main.plugin.model.RobotSuiteFileSection; import org.robotframework.ide.eclipse.main.plugin.model.cmd.CreateFreshKeywordCallCommand; import org.robotframework.ide.eclipse.main.plugin.model.cmd.cases.CreateFreshCaseCommand; import org.robotframework.ide.eclipse.main.plugin.tableeditor.AddingToken; import org.robotframework.ide.eclipse.main.plugin.tableeditor.FilterSwitchRequest; import org.robotframework.ide.eclipse.main.plugin.tableeditor.HeaderFilterMatchesCollection; import org.robotframework.ide.eclipse.main.plugin.tableeditor.HeaderFilterMatchesCollector; import org.robotframework.ide.eclipse.main.plugin.tableeditor.ISectionFormFragment; import org.robotframework.ide.eclipse.main.plugin.tableeditor.MarkersLabelAccumulator; import org.robotframework.ide.eclipse.main.plugin.tableeditor.MarkersSelectionLayerPainter; import org.robotframework.ide.eclipse.main.plugin.tableeditor.RobotEditorCommandsStack; import org.robotframework.ide.eclipse.main.plugin.tableeditor.RobotEditorSources; import org.robotframework.ide.eclipse.main.plugin.tableeditor.RobotSuiteEditorEvents; import org.robotframework.ide.eclipse.main.plugin.tableeditor.SelectionLayerAccessor; import org.robotframework.ide.eclipse.main.plugin.tableeditor.SuiteFileMarkersContainer; import org.robotframework.ide.eclipse.main.plugin.tableeditor.TableThemes; import org.robotframework.ide.eclipse.main.plugin.tableeditor.TableThemes.TableTheme; import org.robotframework.ide.eclipse.main.plugin.tableeditor.TreeLayerAccessor; import org.robotframework.ide.eclipse.main.plugin.tableeditor.cases.CasesMatchesCollection.CasesFilter; import org.robotframework.ide.eclipse.main.plugin.tableeditor.code.CodeTableContentTooltip; import org.robotframework.ide.eclipse.main.plugin.tableeditor.code.CodeTableEditableRule; import org.robotframework.ide.eclipse.main.plugin.tableeditor.code.CodeTableSortingConfiguration; import org.robotframework.red.nattable.AddingElementLabelAccumulator; import org.robotframework.red.nattable.AssistanceLabelAccumulator; import org.robotframework.red.nattable.NewElementsCreator; import org.robotframework.red.nattable.RedColumnHeaderDataProvider; import org.robotframework.red.nattable.RedNattableDataProvidersFactory; import org.robotframework.red.nattable.RedNattableLayersFactory; import org.robotframework.red.nattable.TableCellsStrings; import org.robotframework.red.nattable.configs.AddingElementStyleConfiguration; import org.robotframework.red.nattable.configs.AlternatingRowsStyleConfiguration; import org.robotframework.red.nattable.configs.ColumnHeaderStyleConfiguration; import org.robotframework.red.nattable.configs.GeneralTableStyleConfiguration; import org.robotframework.red.nattable.configs.HeaderSortConfiguration; import org.robotframework.red.nattable.configs.HoveredCellStyleConfiguration; import org.robotframework.red.nattable.configs.RedTableEditConfiguration; import org.robotframework.red.nattable.configs.RedTableResizableRowsBindingsConfiguration; import org.robotframework.red.nattable.configs.RowHeaderStyleConfiguration; import org.robotframework.red.nattable.configs.SelectionStyleConfiguration; import org.robotframework.red.nattable.configs.TableMatchesSupplierRegistryConfiguration; import org.robotframework.red.nattable.configs.TableMenuConfiguration; import org.robotframework.red.nattable.configs.TableStringsPositionsRegistryConfiguration; import org.robotframework.red.nattable.edit.CellEditorCloser; import org.robotframework.red.nattable.painter.RedNatGridLayerPainter; import org.robotframework.red.nattable.painter.RedTableTextPainter; import org.robotframework.services.event.Events; import com.google.common.base.Function; import com.google.common.base.Predicates; @SuppressWarnings("restriction") public class CasesEditorFormFragment implements ISectionFormFragment { @Inject private IEventBroker eventBroker; @Inject private IEditorSite site; @Inject @Named(RobotEditorSources.SUITE_FILE_MODEL) private RobotSuiteFile fileModel; @Inject private SuiteFileMarkersContainer markersContainer; @Inject private RobotEditorCommandsStack commandsStack; @Inject private IDirtyProviderService dirtyProviderService; private HeaderFilterMatchesCollection matches; private NatTable table; private ISortModel sortModel; private CasesDataProvider dataProvider; private RowSelectionProvider<Object> selectionProvider; private SelectionLayerAccessor selectionLayerAccessor; private TreeLayerAccessor treeLayerAccessor; private TableHyperlinksSupport detector; public ISelectionProvider getSelectionProvider() { return selectionProvider; } public SelectionLayerAccessor getSelectionLayerAccessor() { return selectionLayerAccessor; } public TreeLayerAccessor getTreeLayerAccessor() { return treeLayerAccessor; } public NatTable getTable() { return table; } @Override public void initialize(final Composite parent) { setupNatTable(parent); } private void setupNatTable(final Composite parent) { final TableTheme theme = TableThemes.getTheme(parent.getBackground().getRGB()); final ConfigRegistry configRegistry = new ConfigRegistry(); final RedNattableDataProvidersFactory dataProvidersFactory = new RedNattableDataProvidersFactory(); final RedNattableLayersFactory factory = new RedNattableLayersFactory(); // data providers dataProvider = new CasesDataProvider(commandsStack, getSection()); final IDataProvider columnHeaderDataProvider = new CasesColumnHeaderDataProvider(); final IDataProvider rowHeaderDataProvider = dataProvidersFactory.createRowHeaderDataProvider(dataProvider); // body layers final DataLayer bodyDataLayer = factory.createDataLayer(dataProvider, new AssistanceLabelAccumulator(dataProvider, Predicates.alwaysTrue(), rowObject -> rowObject instanceof RobotKeywordCall), new AlternatingRowConfigLabelAccumulator(), new AddingElementLabelAccumulator(dataProvider), new CasesElementsLabelAccumulator(dataProvider)); final GlazedListsEventLayer<Object> glazedListsEventLayer = new GlazedListsEventLayer<>(bodyDataLayer, dataProvider.getTreeList()); final GlazedListTreeData<Object> treeData = new GlazedListTreeData<>(dataProvider.getTreeList()); final ITreeRowModel<Object> treeRowModel = new GlazedListTreeRowModel<>(treeData); final HoverLayer bodyHoverLayer = factory.createHoverLayer(glazedListsEventLayer); final SelectionLayer bodySelectionLayer = factory.createSelectionLayer(theme, bodyHoverLayer); final TreeLayer treeLayer = factory.createTreeLayer(bodySelectionLayer, treeRowModel); final ViewportLayer bodyViewportLayer = factory.createViewportLayer(treeLayer); // column header layers final DataLayer columnHeaderDataLayer = factory.createColumnHeaderDataLayer(columnHeaderDataProvider); final ColumnHeaderLayer columnHeaderLayer = factory.createColumnHeaderLayer(columnHeaderDataLayer, bodySelectionLayer, bodyViewportLayer); sortModel = new GlazedListsSortModel<>(dataProvider.getSortedList(), dataProvider.getPropertyAccessor(), configRegistry, columnHeaderDataLayer); dataProvider.getTreeFormat().setSortModel(sortModel); final SortHeaderLayer<Object> columnHeaderSortingLayer = factory .createSortingColumnHeaderLayer(columnHeaderLayer, sortModel); // row header layers final RowHeaderLayer rowHeaderLayer = factory.createRowsHeaderLayer(bodySelectionLayer, bodyViewportLayer, rowHeaderDataProvider, new MarkersSelectionLayerPainter(), new MarkersLabelAccumulator(markersContainer, dataProvider)); // corner layer final ILayer cornerLayer = factory.createCornerLayer(columnHeaderDataProvider, columnHeaderSortingLayer, rowHeaderDataProvider, rowHeaderLayer); // combined grid layer final GridLayer gridLayer = factory.createGridLayer(bodyViewportLayer, columnHeaderSortingLayer, rowHeaderLayer, cornerLayer); final boolean wrapCellContent = hasWrappedCells(); if (wrapCellContent) { gridLayer.addConfiguration(new RedTableResizableRowsBindingsConfiguration()); } gridLayer.addConfiguration(new RedTableEditConfiguration<>(newElementsCreator(), CodeTableEditableRule.createEditableRule(fileModel), wrapCellContent)); gridLayer.addConfiguration(new CasesTableEditConfiguration(fileModel, dataProvider, wrapCellContent)); table = createTable(parent, theme, factory, gridLayer, bodyDataLayer, configRegistry); bodyViewportLayer.registerCommandHandler(new MoveCellSelectionCommandHandler(bodySelectionLayer, new EditTraversalStrategy(ITraversalStrategy.TABLE_CYCLE_TRAVERSAL_STRATEGY, table), new EditTraversalStrategy(ITraversalStrategy.AXIS_CYCLE_TRAVERSAL_STRATEGY, table))); selectionProvider = new RowSelectionProvider<>(bodySelectionLayer, dataProvider, false); selectionLayerAccessor = new SelectionLayerAccessor(dataProvider, bodySelectionLayer, selectionProvider); treeLayerAccessor = new TreeLayerAccessor(treeLayer); new CodeTableContentTooltip(table, markersContainer, dataProvider, SettingTarget.TEST_CASE); } private NatTable createTable(final Composite parent, final TableTheme theme, final RedNattableLayersFactory factory, final GridLayer gridLayer, final DataLayer dataLayer, final ConfigRegistry configRegistry) { final int style = SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.DOUBLE_BUFFERED | SWT.V_SCROLL | SWT.H_SCROLL; final NatTable table = new NatTable(parent, style, gridLayer, false); table.setConfigRegistry(configRegistry); table.setLayerPainter( new RedNatGridLayerPainter(table, theme.getGridBorderColor(), theme.getHeadersBackground(), theme.getHeadersUnderlineColor(), 2, RedNattableLayersFactory.ROW_HEIGHT)); table.setBackground(theme.getBodyBackgroundOddRowBackground()); table.setForeground(parent.getForeground()); // calculate columns width table.addListener(SWT.Paint, factory.getColumnsWidthCalculatingPaintListener(table, dataProvider, dataLayer, 270, 200)); addCustomStyling(table, theme); // find matches configuration table.addConfiguration(new TableMatchesSupplierRegistryConfiguration(() -> matches)); // hyperlinks configuration final TableCellsStrings tableStrings = new TableCellsStrings(); table.addConfiguration(new TableStringsPositionsRegistryConfiguration(tableStrings)); detector = TableHyperlinksSupport.enableHyperlinksInTable(table, tableStrings); detector.addDetectors(new TableHyperlinksToVariablesDetector(dataProvider), new TableHyperlinksToKeywordsDetector(dataProvider)); // sorting table.addConfiguration(new HeaderSortConfiguration()); table.addConfiguration(new CodeTableSortingConfiguration(dataProvider)); // popup menus table.addConfiguration(new CasesTableMenuConfiguration(site, table, selectionProvider)); table.configure(); GridDataFactory.fillDefaults().grab(true, true).applyTo(table); return table; } private void addCustomStyling(final NatTable table, final TableTheme theme) { final boolean wrapCells = hasWrappedCells(); table.addConfiguration(new GeneralTableStyleConfiguration(theme, new RedTableTextPainter(wrapCells))); table.addConfiguration(new HoveredCellStyleConfiguration(theme)); table.addConfiguration(new ColumnHeaderStyleConfiguration(theme)); table.addConfiguration(new RowHeaderStyleConfiguration(theme)); table.addConfiguration(new AlternatingRowsStyleConfiguration(theme)); table.addConfiguration(new CasesElementsStyleConfiguration(theme, fileModel.isEditable(), wrapCells)); table.addConfiguration(new SelectionStyleConfiguration(theme, table.getFont())); table.addConfiguration(new AddingElementStyleConfiguration(theme, fileModel.isEditable())); } private boolean hasWrappedCells() { final RedPreferences preferences = RedPlugin.getDefault().getPreferences(); return preferences.getCellWrappingStrategy() == CellWrappingStrategy.WRAP; } @Override public void setFocus() { table.setFocus(); } public void aboutToChangeToOtherPage() { CellEditorCloser.closeForcibly(table); } @Persist public void onSave() { CellEditorCloser.closeForcibly(table); } private void setDirty() { dirtyProviderService.setDirtyState(true); } private RobotCasesSection getSection() { return fileModel.findSection(RobotCasesSection.class).orElse(null); } public void revealElement(final RobotElement element, final boolean focus) { if (dataProvider.isFilterSet() && !dataProvider.isProvided(element)) { final String topic = RobotSuiteEditorEvents.FORM_FILTER_SWITCH_REQUEST_TOPIC + "/" + RobotCasesSection.SECTION_NAME.replaceAll(" ", "_"); eventBroker.send(topic, new FilterSwitchRequest(RobotCasesSection.SECTION_NAME.replaceAll(" ", "_"), "")); } CellEditorCloser.closeForcibly(table); if (focus) { table.setFocus(); } selectionProvider.setSelection(new StructuredSelection(new Object[] { element })); } public void clearSettingsSelection() { selectionProvider.setSelection(StructuredSelection.EMPTY); } private NewElementsCreator<RobotElement> newElementsCreator() { return new NewElementsCreator<RobotElement>() { @Override public RobotElement createNew(final int addingTokenRowIndex) { final RobotElement createdElement; final AddingToken token = (AddingToken) dataProvider.getRowObject(addingTokenRowIndex); if (token.isNested()) { final RobotCase testCase = (RobotCase) token.getParent(); commandsStack.execute(new CreateFreshKeywordCallCommand(testCase)); createdElement = testCase.getChildren().get(testCase.getChildren().size() - 1); } else { final RobotCasesSection section = dataProvider.getInput(); commandsStack.execute(new CreateFreshCaseCommand(section)); createdElement = section.getChildren().get(section.getChildren().size() - 1); } return createdElement; } }; } @Override public HeaderFilterMatchesCollection collectMatches(final String filter) { final CasesMatchesCollection casesMatches = new CasesMatchesCollection(); casesMatches.collect(dataProvider.getInput(), filter); return casesMatches; } public List<ITableHyperlinksDetector> getDetectors() { return detector.getDetectors(); } @Inject @Optional private void whenUserRequestedFilteringEnabled(@UIEventTopic(RobotSuiteEditorEvents.SECTION_FILTERING_ENABLED_TOPIC + "/Test_Cases") final HeaderFilterMatchesCollection matches) { if (matches.getCollectors().contains(this)) { this.matches = matches; dataProvider.setFilter(new CasesFilter(matches)); table.refresh(); } } @Inject @Optional private void whenUserRequestedFilteringDisabled( @UIEventTopic(RobotSuiteEditorEvents.SECTION_FILTERING_DISABLED_TOPIC + "/Test_Cases") final Collection<HeaderFilterMatchesCollector> collectors) { if (collectors.contains(this)) { this.matches = null; dataProvider.setFilter(null); table.refresh(); } } @Inject @Optional private void whenCaseIsAdded(@UIEventTopic(RobotModelEvents.ROBOT_CASE_ADDED) final Event event) { final RobotCasesSection section = Events.get(event, IEventBroker.DATA, RobotCasesSection.class); if (section != null && section.getSuiteFile() == fileModel) { sortModel.clear(); RobotCase testCase = Events.get(event, RobotModelEvents.ADDITIONAL_DATA, RobotCase.class); if (testCase == null) { final List<?> keywords = Events.get(event, RobotModelEvents.ADDITIONAL_DATA, List.class); testCase = (RobotCase) keywords.get(keywords.size() - 1); } selectionLayerAccessor.selectElementInFirstCellAfterOperation(testCase, tableInputIsReplaced()); } } @Inject @Optional private void whenCaseIsRemoved( @UIEventTopic(RobotModelEvents.ROBOT_CASE_REMOVED) final RobotSuiteFileSection section) { if (section.getSuiteFile() == fileModel) { selectionLayerAccessor.preserveSelectionWhen(tableInputIsReplaced(), new Function<PositionCoordinate, PositionCoordinate>() { @Override public PositionCoordinate apply(final PositionCoordinate coordinate) { if (section.getChildren().isEmpty()) { return null; } else if (dataProvider.getRowObject(coordinate.getRowPosition()) instanceof AddingToken) { final RobotFileInternalElement lastCase = section.getChildren() .get(section.getChildren().size() - 1); return new PositionCoordinate(coordinate.getLayer(), coordinate.getColumnPosition(), dataProvider.indexOfRowObject(lastCase)); } return coordinate; } }); } } @Inject @Optional private void whenCaseIsMoved(@UIEventTopic(RobotModelEvents.ROBOT_CASE_MOVED) final RobotSuiteFileSection section) { if (section.getSuiteFile() == fileModel) { sortModel.clear(); selectionLayerAccessor.preserveElementSelectionWhen(tableInputIsReplaced()); } } @Inject @Optional private void whenKeywordCallIsAdded(@UIEventTopic(RobotModelEvents.ROBOT_KEYWORD_CALL_ADDED) final Event event) { final RobotCase testCase = Events.get(event, IEventBroker.DATA, RobotCase.class); final RobotKeywordCall keywordCall = Events.get(event, RobotModelEvents.ADDITIONAL_DATA, RobotKeywordCall.class); if (testCase != null && testCase.getSuiteFile() == fileModel) { sortModel.clear(); if (keywordCall != null) { selectionLayerAccessor.selectElementInFirstCellAfterOperation(keywordCall, tableInputIsReplaced()); } else { final List<?> calls = Events.get(event, RobotModelEvents.ADDITIONAL_DATA, List.class); final RobotKeywordCall lastCall = (RobotKeywordCall) calls.get(calls.size() - 1); selectionLayerAccessor.selectElementInFirstCellAfterOperation(lastCall, tableInputIsReplaced()); } } } @Inject @Optional private void whenKeywordCallIsRemoved( @UIEventTopic(RobotModelEvents.ROBOT_KEYWORD_CALL_REMOVED) final RobotCase testCase) { if (testCase.getSuiteFile() == fileModel) { selectionLayerAccessor.preserveSelectionWhen(tableInputIsReplaced(), new Function<PositionCoordinate, PositionCoordinate>() { @Override public PositionCoordinate apply(final PositionCoordinate coordinate) { if (testCase.getChildren().isEmpty()) { return new PositionCoordinate(coordinate.getLayer(), coordinate.getColumnPosition(), dataProvider.indexOfRowObject(testCase)); } else if (dataProvider.getRowObject(coordinate.getRowPosition()) instanceof AddingToken) { return new PositionCoordinate(coordinate.getLayer(), coordinate.getColumnPosition(), coordinate.getRowPosition() - 1); } return coordinate; } }); } } @Inject @Optional private void whenKeywordCallIsMoved( @UIEventTopic(RobotModelEvents.ROBOT_KEYWORD_CALL_MOVED) final RobotCase testCase) { if (testCase.getSuiteFile() == fileModel) { sortModel.clear(); selectionLayerAccessor.preserveElementSelectionWhen(tableInputIsReplaced()); } } @Inject @Optional private void whenKeywordCallIsConverted( @UIEventTopic(RobotModelEvents.ROBOT_KEYWORD_CALL_CONVERTED) final Event event) { final RobotCase testCase = Events.get(event, IEventBroker.DATA, RobotCase.class); final RobotKeywordCall call = Events.get(event, RobotModelEvents.ADDITIONAL_DATA, RobotKeywordCall.class); if (testCase != null && testCase.getSuiteFile() == fileModel) { sortModel.clear(); selectionLayerAccessor.selectElementPreservingSelectedColumnsAfterOperation(call, tableInputIsReplaced()); } } private Runnable tableInputIsReplaced() { return new Runnable() { @Override public void run() { final int lastSelectedRowPosition = selectionLayerAccessor.getLastSelectedRowPosition(); final int rowCountBeforeChange = dataProvider.getSortedList().size(); final List<Integer> expandedRowIndexes = treeLayerAccessor .expandCollapsedRowsBeforeRowCountChange(rowCountBeforeChange); dataProvider.setInput(getSection()); table.refresh(); setDirty(); final int rowCountChange = dataProvider.getSortedList().size() - rowCountBeforeChange; treeLayerAccessor.collapseRowsAfterRowCountChange(expandedRowIndexes, lastSelectedRowPosition, rowCountChange); } }; } @Inject @Optional private void whenCaseDetailIsChanged( @UIEventTopic(RobotModelEvents.ROBOT_CASE_DETAIL_CHANGE_ALL) final RobotCase testCase) { if (testCase.getSuiteFile() == fileModel) { table.update(); table.refresh(); setDirty(); } } @Inject @Optional private void whenKeywordCallDetailIsChanged( @UIEventTopic(RobotModelEvents.ROBOT_KEYWORD_CALL_DETAIL_CHANGE_ALL) final RobotKeywordCall keywordCall) { if (keywordCall.getParent() instanceof RobotCase && keywordCall.getSuiteFile() == fileModel) { table.update(); table.refresh(); setDirty(); } } @Inject @Optional private void whenSectionIsCreated( @UIEventTopic(RobotModelEvents.ROBOT_SUITE_SECTION_ADDED) final RobotSuiteFile file) { if (file == fileModel && dataProvider.getInput() == null) { dataProvider.setInput(getSection()); table.refresh(); setDirty(); } } @Inject @Optional private void whenSectionIsRemoved( @UIEventTopic(RobotModelEvents.ROBOT_SUITE_SECTION_REMOVED) final RobotSuiteFile file) { if (file == fileModel && dataProvider.getInput() != null) { final ICellEditor activeCellEditor = table.getActiveCellEditor(); if (activeCellEditor != null && !activeCellEditor.isClosed()) { activeCellEditor.close(); } dataProvider.setInput(getSection()); selectionLayerAccessor.clear(); table.refresh(); setDirty(); } } @Inject @Optional private void whenFileChangedExternally( @UIEventTopic(RobotModelEvents.EXTERNAL_MODEL_CHANGE) final RobotElementChange change) { if (change.getKind() == Kind.CHANGED) { final RobotSuiteFile suite = change.getElement() instanceof RobotSuiteFile ? (RobotSuiteFile) change.getElement() : null; if (suite == fileModel) { dataProvider.setInput(getSection()); table.refresh(); } } } @Inject @Optional private void whenReconcilationWasDone( @UIEventTopic(RobotModelEvents.REPARSING_DONE) final RobotSuiteFile fileModel) { if (fileModel == this.fileModel) { commandsStack.clear(); dataProvider.setInput(getSection()); table.refresh(); } } @Inject @Optional private void whenMarkersContainerWasReloaded( @UIEventTopic(RobotModelEvents.MARKERS_CACHE_RELOADED) final RobotSuiteFile fileModel) { if (fileModel == this.fileModel) { table.refresh(); } } private class CasesColumnHeaderDataProvider extends RedColumnHeaderDataProvider { public CasesColumnHeaderDataProvider() { super(dataProvider); } @Override public Object getDataValue(final int columnIndex, final int rowIndex) { return ""; } } private static class CasesTableMenuConfiguration extends TableMenuConfiguration { public CasesTableMenuConfiguration(final IEditorSite site, final NatTable table, final ISelectionProvider selectionProvider) { super(site, table, selectionProvider, "org.robotframework.ide.eclipse.editor.page.cases.contextMenu", "Robot suite editor cases context menu"); } } }