blob: 856b945e206e52f910cfa3b605ea74d565106593 [file] [log] [blame]
/*=============================================================================#
# 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();
}
});
}
}