/*******************************************************************************
* Copyright (c) 2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.fusesource.ide.commons.ui.views;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.properties.tabbed.ISection;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.fusesource.ide.commons.Activator;
import org.fusesource.ide.commons.Viewers;
import org.fusesource.ide.commons.tree.Refreshable;
import org.fusesource.ide.commons.ui.IConfigurableColumns;
import org.fusesource.ide.commons.ui.Menus;
import org.fusesource.ide.commons.ui.Widgets;
import org.fusesource.ide.commons.ui.actions.ConfigureColumnsAction;
import org.fusesource.ide.commons.ui.chart.TableChartOptions;
import org.fusesource.ide.commons.ui.config.ColumnConfiguration;
import org.fusesource.ide.commons.ui.config.TableConfiguration;
import org.fusesource.ide.commons.ui.label.ChartLabelProvider;
import org.fusesource.ide.commons.ui.label.FunctionColumnLabelProvider;
import org.fusesource.ide.commons.ui.label.ImageLabelProvider;
import org.fusesource.ide.commons.ui.label.LongTimestampAsTimeThenDateLabelProvider;
import org.fusesource.ide.commons.ui.label.TimeThenDateFunctionLabelProvider;
import org.fusesource.ide.commons.ui.label.TimeThenDateLabelProvider;
import org.fusesource.ide.commons.util.Function1;
import org.fusesource.ide.commons.util.Objects;
public abstract class ColumnViewSupport extends ViewPart implements IConfigurableColumns, IViewPage, ISection, Refreshable {
private Action refreshAction;
private Action chartAction;
private Action doubleClickAction;
private List<Function1> functions = new ArrayList<Function1>();
private Menu menu;
private IPageSite pageSite;
private TableConfiguration configuration;
private boolean showChartingOptions;
protected TableChartOptions chartOptions;
private boolean isSectionActivated;
private ConfigureColumnsAction configureColumnsAction;
private TabbedPropertySheetPage tabbedPropertySheetPage;
private IChangeListener changeListener;
private List<Object> localMenuActions = new ArrayList<Object>();
private List<Object> toolBarActions = new ArrayList<Object>();
public ColumnViewSupport() {
super();
}
@Override
public void init(IPageSite pageSite) {
this.pageSite = pageSite;
}
public IPageSite getPageSite() {
if (tabbedPropertySheetPage != null) {
IPageSite answer = tabbedPropertySheetPage.getSite();
if (answer != null) {
return answer;
}
}
return pageSite;
}
@Override
public void refresh() {
Viewers.refresh(getViewer());
}
public void createControl(Composite parent) {
createPartControl(parent);
}
public void addLocalMenuActions(Object... newActions) {
for (Object action : newActions) {
localMenuActions.add(action);
}
}
public void addToolBarActions(Object... newActions) {
for (Object action : newActions) {
toolBarActions.add(action);
}
}
public Control getControl() {
if (getViewer() == null) {
return null;
}
return getViewer().getControl();
}
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// TODO Auto-generated method stub
}
public void setActionBars(IActionBars actionBars) {
// TODO Auto-generated method stub
}
@Override
public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
this.tabbedPropertySheetPage = tabbedPropertySheetPage;
init(tabbedPropertySheetPage.getSite());
createPartControl(parent);
}
@Override
public void setInput(IWorkbenchPart part, ISelection selection) {
}
@Override
public void dispose() {
deactivateSection();
super.dispose();
}
@Override
public void aboutToBeShown() {
if (!isSectionActivated) {
isSectionActivated = true;
addToolBarActions();
addLocalMenus();
if (getActionBars() != null) {
getActionBars().updateActionBars();
}
setSelectionProvider();
}
}
protected void setSelectionProvider() {
IWorkbenchPartSite site = getSite();
IPageSite pageSite = getPageSite();
if (site != null) {
site.setSelectionProvider(getViewer());
}
if (tabbedPropertySheetPage instanceof TabFolderSupport2) {
TabFolderSupport2 tfs = (TabFolderSupport2) tabbedPropertySheetPage;
IViewSite viewSite = tfs.getViewSite();
if (viewSite != null) {
viewSite.setSelectionProvider(getViewer());
/*
PropertySheet propertySheet = tfs.getPropertySheet();
IWorkbenchPage page = viewSite.getPage();
IWorkbenchPart activePart = page.getActivePart();
if (propertySheet != null) {
propertySheet.getSite().getPage().addPostSelectionListener(propertySheet);
}
*/
}
}
if (pageSite != null) {
// NOTE the following code can cause ECLIPSE-692
// so lets not do it for now :)
//pageSite.setSelectionProvider(getViewer());
}
if (site == null && pageSite == null) {
warnNoSite();
}
}
@Override
public void aboutToBeHidden() {
//if (isFocused() || !propertySheet.isPinned()) {
// hidden by selecting another tab
deactivateSection();
//}
}
protected void deactivateSection() {
if (isSectionActivated) {
isSectionActivated = false;
// remove tool bar actions
IToolBarManager toolBarManager = getToolBarManager();
if (toolBarManager != null) {
removeToolBarActions(toolBarManager);
toolBarManager.update(false);
}
// remove local menus
IMenuManager menuManager = getMenuManager();
if (menuManager != null) {
removeLocalMenus(menuManager);
menuManager.update(false);
} else {
Activator.getLogger().debug("############ NO MENUMANAGER!");
}
if (getActionBars() != null) {
getActionBars().updateActionBars();
}
// clear status line
clearStatusLine();
}
}
/**
* Clears the status line.
*/
public void clearStatusLine() {
/*
IStatusLineManager manager = propertySheet.getViewSite()
.getActionBars().getStatusLineManager();
IContributionItem[] items = manager.getItems();
for (IContributionItem item : items) {
if (item instanceof StatusLineContributionItem) {
((StatusLineContributionItem) item)
.setText(Util.ZERO_LENGTH_STRING);
}
}
*/
}
/**
* Activates the section.
*/
protected void activateSection() {
}
@Override
public int getMinimumHeight() {
return 0;
}
@Override
public boolean shouldUseExtraSpace() {
return true;
}
@Override
public void updateColumnConfiguration(TableConfiguration configuration) {
// TODO Auto-generated method stub
}
@Override
public void createPartControl(Composite parent) {
// TODO Auto-generated method stub
}
public abstract ColumnViewer getViewer();
protected abstract String getHelpID();
protected abstract void showChartDialog();
/**
* Adds the tool bar actions.
*/
private void addToolBarActions() {
IToolBarManager toolBarManager = getToolBarManager();
if (toolBarManager != null) {
addToolBarActions(toolBarManager);
}
}
protected void addToolBarActions(IToolBarManager manager) {
Menus.addAction(manager, refreshAction);
if (showChartAction()) {
Menus.addAction(manager, chartAction);
}
Menus.addAction(manager, toolBarActions);
}
protected void removeToolBarActions(IToolBarManager manager) {
Menus.removeAction(manager, toolBarActions);
Menus.removeAction(manager, refreshAction);
Menus.removeAction(manager, chartAction);
}
protected void addLocalMenus(IMenuManager manager) {
Menus.addAction(manager, refreshAction);
Menus.addAction(manager, configureColumnsAction);
if (showChartAction()) {
Menus.addAction(manager, chartAction);
}
Menus.addAction(manager, localMenuActions);
}
protected void removeLocalMenus(IMenuManager manager) {
//Menus.removeAction(manager, refreshAction);
//Menus.removeAction(manager, configureColumnsAction);
Menus.removeAction(manager, chartAction);
Menus.removeAction(manager, localMenuActions);
}
/*
protected void fillContextMenu(IMenuManager manager) {
manager.add(refreshAction);
if (showChartAction()) {
manager.add(chartAction);
}
manager.add(new ConfigureColumnsAction(this));
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
*/
/**
* Adds the local menus.
*/
private void addLocalMenus() {
IMenuManager menuManager = getMenuManager();
if (menuManager != null) {
addLocalMenus(menuManager);
menuManager.setVisible(true);
}
}
protected IMenuManager getMenuManager() {
IActionBars actionBars = getActionBars();
IMenuManager menuManager = null;
if (actionBars != null) {
menuManager = actionBars.getMenuManager();
}
return menuManager;
}
protected IToolBarManager getToolBarManager() {
IActionBars actionBars = getActionBars();
IToolBarManager answer = null;
if (actionBars != null) {
answer = actionBars.getToolBarManager();
}
return answer;
}
protected IActionBars getActionBars() {
IPageSite pageSite = getPageSite();
IActionBars actionBars = null;
if (pageSite != null) {
actionBars = pageSite.getActionBars();
}
if (actionBars == null) {
IViewSite viewSite = getViewSite();
if (viewSite != null) {
actionBars = viewSite.getActionBars();
}
}
return actionBars;
}
protected void addFunction(Function1 function) {
functions.add(function);
}
protected void clearColumns() {
functions.clear();
}
/*
protected void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
ColumnViewSupport.this.fillContextMenu(manager);
}
});
menu = menuMgr.createContextMenu(getViewer().getControl());
getViewer().getControl().setMenu(menu);
IWorkbenchPartSite site = getSite();
if (site != null) {
site.registerContextMenu(menuMgr, getViewer());
} else if (pageSite != null) {
// TODO use a different ID?
pageSite.registerContextMenu(getHelpID(), menuMgr, getViewer());
} else {
warnNoSite();
}
}
protected void contributeToActionBars() {
IActionBars bars = null;
if (getViewSite() != null) {
bars = getViewSite().getActionBars();
} else if (pageSite != null) {
bars = pageSite.getActionBars();
} else {
warnNoSite();
return;
}
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
*/
protected void warnNoSite() {
Activator.getLogger().warning("No IViewSite or IPageSite registered for " + this);
}
protected void makeActions() {
refreshAction = new Action() {
@Override
public void run() {
refresh();
}
};
refreshAction.setId(getClass().getName() + ".refresh");
refreshAction.setText("Refresh");
refreshAction.setToolTipText("Refreshes the view");
Activator.setLocalImageDescriptors(refreshAction, "refresh.gif"); //$NON-NLS-1$
configureColumnsAction = new ConfigureColumnsAction(this);
chartAction = new Action() {
@Override
public void run() {
showChartDialog();
}
};
chartAction.setId(getClass().getName() + ".chart");
chartAction.setText("Create Chart");
chartAction.setToolTipText("Create a chart from the current table");
// TODO
Activator.setLocalImageDescriptors(chartAction, "chart.gif"); //$NON-NLS-1$
/*
* action2 = new Action() { public void run() {
* showMessage("Action 2 executed"); } }; action2.setText("Action 2");
* action2.setToolTipText("Action 2 tooltip");
* action2.setImageDescriptor
* (PlatformUI.getWorkbench().getSharedImages()
* .getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
*/
if (doubleClickAction == null) {
doubleClickAction = new Action() {
@Override
public void run() {
ISelection selection = getViewer().getSelection();
doubleClickSelection(selection);
}
};
doubleClickAction.setId(getClass().getName() + ".doubleClick");
}
}
public Action getDoubleClickAction() {
return doubleClickAction;
}
public void setDoubleClickAction(Action doubleClickAction) {
this.doubleClickAction = doubleClickAction;
}
protected void doubleClickSelection(ISelection selection) {
((IStructuredSelection) selection)
.getFirstElement();
}
protected void hookDoubleClickAction() {
Widgets.setDoubleClickAction(getViewer(), doubleClickAction);
}
protected void showMessage(String message) {
MessageDialog.openInformation(getViewer().getControl().getShell(),
"Message View", message);
}
@Override
public abstract List<String> getColumns();
@Override
public boolean getDefaultVisibility(String column) {
return true;
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
getViewer().getControl().setFocus();
}
@Override
public TableConfiguration getConfiguration() {
if (configuration == null) {
configuration = TableConfiguration.loadConfiguration(getColumnConfigurationId());
configuration.addDefaultColumns(getColumns());
}
return configuration;
}
protected abstract TableChartOptions createChartOptions();
public void setConfiguration(TableConfiguration configuration) {
if (configuration != this.configuration) {
if (this.configuration != null) {
this.configuration.removeColumnListeners(getViewer());
}
this.configuration = configuration;
if (this.configuration != null) {
this.configuration.addColumnListeners(getViewer());
}
}
}
protected boolean showChartAction() {
return showChartingOptions && chartOptions.isValid();
}
public TableChartOptions getChartOptions() {
if (chartOptions == null) {
chartOptions = createChartOptions();
}
return chartOptions;
}
/**
* Based on the table configuration and defaults lets update the label provider for the column
*/
protected void configureLabelProvider(ViewerColumn viewerColumn, ColumnConfiguration config, CellLabelProvider labelProvider) {
Class<?> returnType = Objects.getReturnType(labelProvider);
String style = config.getLabelProviderStyle();
FunctionColumnLabelProvider flp = null;
if (labelProvider instanceof FunctionColumnLabelProvider) {
flp = (FunctionColumnLabelProvider) labelProvider;
returnType = flp.getReturnType();
}
if (viewerColumn != null) {
CellLabelProvider provider = config.getLabelProvider();
if (provider != null) {
viewerColumn.setLabelProvider(provider);
} else {
if (style != null && style.equals("timeThenDate")) {
if (flp != null) {
viewerColumn.setLabelProvider(new TimeThenDateFunctionLabelProvider(flp.getFunction()));
} else {
viewerColumn.setLabelProvider(new TimeThenDateLabelProvider());
}
} else if (style != null && style.equals("longTimestampAsTimeThenDate")) {
viewerColumn.setLabelProvider(new LongTimestampAsTimeThenDateLabelProvider());
} else if (Objects.isNumberType(returnType)) {
if (style == null || !style.equals("plain")) {
viewerColumn.setLabelProvider(new ChartLabelProvider(labelProvider, getViewer()));
}
} else if (Objects.equal(style, "image") && flp != null) {
viewerColumn.setLabelProvider(new ImageLabelProvider(flp.getFunction()));
}
}
}
}
/*
protected boolean hasLabelProvider(ViewerColumn viewerColumn) {
// lets use reflection
Field field;
try {
field = ViewerColumn.class.getDeclaredField("labelProvider");
field.setAccessible(true);
Object provider = field.get(viewerColumn);
return provider != null;
} catch (Exception e) {
Activator.getLogger().debug("Failed to get labelProvider field: " + e);
return false;
}
}
*/
protected void setInput(Object input) {
ObservableLists.removeListener(getViewer().getInput(), getChangeListener());
ObservableLists.addListener(input, getChangeListener());
Viewers.setInput(getViewer(), input);
// TODO is this needed?
//getViewer().refresh();
}
protected IChangeListener getChangeListener() {
if (changeListener == null) {
changeListener = new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
refreshViewerOnChange();
}
};
}
return changeListener;
}
/**
* The underlying model has changed so refresh the viewer
*/
protected void refreshViewerOnChange() {
Viewers.refresh(getViewer());
}
public class ColumnFunctionComparator extends ViewerComparator {
public static final int ASCENDING = 0;
public static final int DESCENDING = 1;
private int propertyIndex;
private int defaultSortColumnIndex;
private int direction = DESCENDING;
public ColumnFunctionComparator() {
this.propertyIndex = 0;
direction = DESCENDING;
}
public void setDefaultSortColumn(int column) {
defaultSortColumnIndex = column;
setColumn(column);
}
public void setColumn(int column) {
if (column == this.propertyIndex) {
// Same column as last sort; toggle the direction
direction = 1 - direction;
} else {
// New column; do an ascending sort
this.propertyIndex = column;
direction = ASCENDING;
}
}
public void setDescending(boolean descending) {
if (descending) {
direction = DESCENDING;
} else {
direction = ASCENDING;
}
}
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
return compareByColumn(e1, e2, propertyIndex);
}
protected int compareByColumn(Object e1, Object e2, int sortIndex) {
int answer = 0;
if (sortIndex < 0 || sortIndex >= functions.size()) {
answer = compareDefaultSortColumn(e1, e2, sortIndex);
} else {
Function1 function = functions.get(sortIndex);
Object v1 = function.apply(e1);
Object v2 = function.apply(e2);
answer = Objects.compare(v1, v2);
if (answer == 0) {
answer = compareDefaultSortColumn(e1, e2, sortIndex);
}
}
if (direction == DESCENDING) {
answer = -answer;
}
return answer;
}
public int compareDefaultSortColumn(Object e1, Object e2, int sortIndex) {
if (sortIndex == defaultSortColumnIndex) {
return Objects.compare(e1, e2);
} else {
return compareByColumn(e1, e2, defaultSortColumnIndex);
}
}
}
}