| /*=============================================================================# |
| # Copyright (c) 2010, 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.r.ui.dataeditor; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| |
| import java.util.Iterator; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| |
| import org.eclipse.statet.jcommons.lang.NonNull; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.ui.SharedUIResources; |
| import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem; |
| import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| import org.eclipse.statet.ecommons.ui.workbench.BasicEditorOutlinePage; |
| import org.eclipse.statet.ecommons.waltable.coordinate.LRangeList; |
| |
| import org.eclipse.statet.internal.r.ui.RUIPlugin; |
| import org.eclipse.statet.r.ui.dataeditor.IRDataTableInput; |
| import org.eclipse.statet.r.ui.dataeditor.IRDataTableListener; |
| import org.eclipse.statet.r.ui.dataeditor.IRDataTableVariable; |
| import org.eclipse.statet.r.ui.dataeditor.RDataTableColumn; |
| import org.eclipse.statet.rj.data.RFactorStore; |
| import org.eclipse.statet.rj.data.RStore; |
| |
| |
| @NonNullByDefault |
| public class RDataEditorOutlinePage extends BasicEditorOutlinePage { |
| |
| |
| private static final Object[] NO_CHILDREN= new @NonNull Object[0]; |
| |
| |
| static abstract class VariablePropertyItem { |
| |
| |
| protected final IRDataTableVariable variable; |
| |
| |
| public VariablePropertyItem(final IRDataTableVariable column) { |
| this.variable= column; |
| } |
| |
| |
| public Object getParent() { |
| return this.variable; |
| } |
| |
| public boolean hasChildren() { |
| return false; |
| } |
| |
| public Object[] getChildren() { |
| return NO_CHILDREN; |
| } |
| |
| public abstract String getName(); |
| |
| public int getCount() { |
| return -1; |
| } |
| |
| |
| @Override |
| public int hashCode() { |
| return getName().hashCode() * this.variable.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(final @Nullable Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj instanceof VariablePropertyItem) { |
| final VariablePropertyItem other= (VariablePropertyItem)obj; |
| return (getName() == other.getName() |
| && this.variable.equals(other.variable)); |
| } |
| return false; |
| } |
| |
| } |
| |
| private static class FactorLevels extends VariablePropertyItem { |
| |
| |
| public FactorLevels(final RDataTableColumn column) { |
| super(column); |
| } |
| |
| |
| @Override |
| public boolean hasChildren() { |
| return true; |
| } |
| |
| @Override |
| public Object[] getChildren() { |
| final RFactorStore data= (RFactorStore)((RDataTableColumn)this.variable).getDataStore(); |
| return data.getLevels().toArray(); |
| } |
| |
| @Override |
| public String getName() { |
| return "Factor Levels"; |
| } |
| |
| @Override |
| public int getCount() { |
| final RFactorStore data= (RFactorStore)((RDataTableColumn)this.variable).getDataStore(); |
| return data.getLevelCount(); |
| } |
| |
| } |
| |
| private static class FTableFactorLevels extends VariablePropertyItem { |
| |
| |
| public FTableFactorLevels(final FTableVariable variable) { |
| super(variable); |
| } |
| |
| |
| @Override |
| public boolean hasChildren() { |
| return true; |
| } |
| |
| @Override |
| public Object[] getChildren() { |
| final RStore data= ((FTableVariable)this.variable).getLevelStore(); |
| return data.toArray(); |
| } |
| |
| @Override |
| public String getName() { |
| return "Levels"; |
| } |
| |
| @Override |
| public int getCount() { |
| final RStore data= ((FTableVariable)this.variable).getLevelStore(); |
| return (int)data.getLength(); |
| } |
| |
| } |
| |
| |
| private class RDataContentProvider implements ITreeContentProvider { |
| |
| @Override |
| public void inputChanged(final Viewer viewer, final @Nullable Object oldInput, final @Nullable Object newInput) { |
| } |
| |
| @Override |
| public Object[] getElements(final Object inputElement) { |
| final RDataTableContentDescription contentDescription= RDataEditorOutlinePage.this.contentDescription; |
| if (contentDescription != null) { |
| return new Object[] { contentDescription }; |
| } |
| return NO_CHILDREN; |
| } |
| |
| @Override |
| public @Nullable Object getParent(final Object element) { |
| if (element instanceof RDataTableColumn) { |
| return RDataEditorOutlinePage.this.contentDescription; |
| } |
| if (element instanceof VariablePropertyItem) { |
| return ((VariablePropertyItem)element).getParent(); |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean hasChildren(final Object element) { |
| final RDataTableContentDescription contentDescription= RDataEditorOutlinePage.this.contentDescription; |
| if (element == contentDescription) { |
| return (contentDescription.getVariables().length > 0); |
| } |
| if (element instanceof RDataTableColumn) { |
| final RDataTableColumn column= (RDataTableColumn)element; |
| return (column.getVarType() == IRDataTableVariable.FACTOR); |
| } |
| else if (element instanceof FTableVariable) { |
| return true; |
| } |
| else if (element instanceof VariablePropertyItem) { |
| final VariablePropertyItem item= (VariablePropertyItem) element; |
| return item.hasChildren(); |
| } |
| return false; |
| } |
| |
| @Override |
| public Object[] getChildren(final Object parentElement) { |
| final RDataTableContentDescription contentDescription= RDataEditorOutlinePage.this.contentDescription; |
| { final Object[] columns; |
| if (parentElement == contentDescription |
| && (columns= contentDescription.getVariables()).length <= 2500 ) { |
| return columns; |
| } |
| } |
| if (parentElement instanceof RDataTableColumn) { |
| final RDataTableColumn column= (RDataTableColumn) parentElement; |
| if (column.getVarType() == IRDataTableVariable.FACTOR) { |
| return new Object[] { new FactorLevels(column) }; |
| } |
| } |
| else if (parentElement instanceof FTableVariable) { |
| return new Object[] { new FTableFactorLevels((FTableVariable) parentElement) }; |
| } |
| else if (parentElement instanceof VariablePropertyItem) { |
| final VariablePropertyItem item= (VariablePropertyItem) parentElement; |
| return item.getChildren(); |
| } |
| return new Object[0]; |
| } |
| |
| @Override |
| public void dispose() { |
| } |
| |
| } |
| |
| private final RDataEditor editor; |
| |
| private @Nullable RDataTableContentDescription contentDescription; |
| |
| |
| public RDataEditorOutlinePage(final RDataEditor editor) { |
| super("org.eclipse.statet.r.menu.RDataOutlineViewContextMenu"); //$NON-NLS-1$ |
| this.editor= editor; |
| } |
| |
| |
| public RDataEditor getDataEditor() { |
| return this.editor; |
| } |
| |
| @Override |
| protected IDialogSettings getDialogSettings() { |
| return DialogUtils.getDialogSettings(RUIPlugin.getInstance(), "RDataOutlineView"); |
| } |
| |
| @Override |
| protected void configureViewer(final TreeViewer viewer) { |
| viewer.setUseHashlookup(true); |
| viewer.setContentProvider(new RDataContentProvider()); |
| viewer.setLabelProvider(new RDataLabelProvider()); |
| viewer.setInput(this); |
| } |
| |
| @Override |
| protected void init() { |
| super.init(); |
| this.editor.getRDataTable().addTableListener(new IRDataTableListener() { |
| @Override |
| public void inputChanged(final IRDataTableInput input, final RDataTableContentDescription description) { |
| final RDataTableContentDescription oldDescription= RDataEditorOutlinePage.this.contentDescription; |
| final boolean isNew= (description != null |
| && (oldDescription == null |
| || oldDescription.getVariables().length != description.getVariables().length )); |
| RDataEditorOutlinePage.this.contentDescription= description; |
| |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return; |
| } |
| viewer.refresh(); |
| if (isNew && RDataEditorOutlinePage.this.contentDescription != null) { |
| // viewer.setExpandedTreePaths(new TreePath[] { new TreePath(new Object[] { fDescription }) }); |
| viewer.expandToLevel(3); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| protected @Nullable TreeViewer getViewer() { |
| return (TreeViewer)super.getViewer(); |
| } |
| |
| @Override |
| protected void selectInEditor(final ISelection selection) { |
| if (selection.isEmpty()) { |
| return; |
| } |
| if (selection instanceof IStructuredSelection) { |
| final IStructuredSelection structuredSelection= (IStructuredSelection)selection; |
| if (structuredSelection.size() == 1) { |
| final Object element= structuredSelection.getFirstElement(); |
| if (element instanceof RDataTableColumn) { |
| this.editor.getRDataTable().revealColumn(((RDataTableColumn) element).getIndex()); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void contextMenuAboutToShow(final IMenuManager m) { |
| final IStructuredSelection selection= (IStructuredSelection)nonNullAssert(getViewer()) |
| .getSelection(); |
| for (final Iterator<?> iterator= selection.iterator(); iterator.hasNext();) { |
| final Object element= iterator.next(); |
| if (!(element instanceof RDataTableColumn)) { |
| return; |
| } |
| } |
| |
| m.add(new SimpleContributionItem("Select Column", "S") { |
| @Override |
| protected void execute() throws ExecutionException { |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return; |
| } |
| final IStructuredSelection selection= (IStructuredSelection)viewer.getSelection(); |
| final LRangeList columnIndexes= new LRangeList(); |
| for (final Iterator<?> iterator= selection.iterator(); iterator.hasNext();) { |
| final Object element= iterator.next(); |
| if (element instanceof RDataTableColumn) { |
| columnIndexes.values().add(((RDataTableColumn) element).getIndex()); |
| } |
| else { |
| return; |
| } |
| } |
| RDataEditorOutlinePage.this.editor.getRDataTable().selectColumns(columnIndexes); |
| } |
| }); |
| |
| m.add(new Separator()); |
| if (selection.size() == 1) { |
| m.add(new SimpleContributionItem( |
| "Sort Increasing by Column", "I", |
| SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_SORT_ALPHA_IMAGE_ID), null ) { |
| @Override |
| protected void execute() throws ExecutionException { |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return; |
| } |
| final IStructuredSelection selection= (IStructuredSelection)viewer.getSelection(); |
| final Object element= selection.getFirstElement(); |
| if (selection.size() == 1 && element instanceof RDataTableColumn) { |
| final RDataTableColumn column= (RDataTableColumn) element; |
| RDataEditorOutlinePage.this.editor.getRDataTable().sortByColumn(column.getIndex(), true); |
| } |
| } |
| }); |
| m.add(new SimpleContributionItem( |
| "Sort Decreasing by Column", "I") { |
| @Override |
| protected void execute() throws ExecutionException { |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return; |
| } |
| final IStructuredSelection selection= (IStructuredSelection)viewer.getSelection(); |
| final Object element= selection.getFirstElement(); |
| if (selection.size() == 1 && element instanceof RDataTableColumn) { |
| final RDataTableColumn column= (RDataTableColumn) element; |
| RDataEditorOutlinePage.this.editor.getRDataTable().sortByColumn(column.getIndex(), false); |
| } |
| } |
| }); |
| } |
| m.add(new SimpleContributionItem("Clear All Sorting", "O") { |
| @Override |
| protected void execute() throws ExecutionException { |
| RDataEditorOutlinePage.this.editor.getRDataTable().clearSorting(); |
| } |
| }); |
| } |
| |
| } |