// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dataprofiler.core.ui.editor.analysis.drilldown;
import java.text.Collator;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableColorProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.nebula.widgets.pagination.IPageLoader;
import org.eclipse.nebula.widgets.pagination.PageChangedAdapter;
import org.eclipse.nebula.widgets.pagination.PageLoaderStrategyHelper;
import org.eclipse.nebula.widgets.pagination.PageableController;
import org.eclipse.nebula.widgets.pagination.collections.PageResult;
import org.eclipse.nebula.widgets.pagination.collections.PageResultContentProvider;
import org.eclipse.nebula.widgets.pagination.renderers.navigation.ResultAndNavigationPageGraphicsRenderer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
import org.talend.cwm.indicator.ColumnFilter;
import org.talend.cwm.relational.TdColumn;
import org.talend.dataprofiler.common.ui.pagination.pageloder.MapDBPageConstant;
import org.talend.dataprofiler.common.ui.pagination.pageloder.MapDBPageLoader;
import org.talend.dataprofiler.core.ImageLib;
import org.talend.dataprofiler.core.PluginConstant;
import org.talend.dataprofiler.core.i18n.internal.DefaultMessagesImpl;
import org.talend.dataquality.analysis.Analysis;
import org.talend.dataquality.analysis.AnalysisType;
import org.talend.dataquality.indicators.Indicator;
import org.talend.dataquality.indicators.mapdb.AbstractDB;
import org.talend.dataquality.indicators.mapdb.MapDBManager;
import org.talend.dataquality.indicators.mapdb.MapDBUtils;
import org.talend.dataquality.indicators.validation.IDataValidationFactory;
import org.talend.dq.helper.SqlExplorerUtils;
/**
*
* DOC zshen class global comment. Detailled comment
*
* Display result for drill down operation
*/
public class DrillDownResultEditor extends EditorPart {
private static Logger log = Logger.getLogger(DrillDownResultEditor.class);
private TableViewer tableView;
private Action exportAction;
private Hashtable<String, Action> actionList;
public static final String[] ACTION_NAME = { "export" };//$NON-NLS-1$
public static final String NULL_VALUE_DISPLAY_TEXT = "(null)"; //$NON-NLS-1$
public DrillDownResultEditor() {
// TODO Auto-generated constructor stub
}
@Override
public void doSave(IProgressMonitor monitor) {
// TODO Auto-generated method stub
}
@Override
public void doSaveAs() {
// TODO Auto-generated method stub
}
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
this.setSite(site);
this.setInput(input);
DrillDownEditorInput ddEditorInput = (DrillDownEditorInput) input;
this.setPartName(ddEditorInput.getMenuType());
this.setTitleToolTip(ddEditorInput.getToolTipText());
}
@Override
public boolean isDirty() {
return false;
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
@Override
public void createPartControl(Composite parent) {
GridLayout layout = new GridLayout();
parent.setLayoutData(new GridData(GridData.FILL_BOTH));
// layout.marginTop = 10;
parent.setLayout(layout);
// createPopupMenu();
exportAction = SqlExplorerUtils.getDefault().createExportCSVAction();
createCoolBar(parent);
tableView = new TableViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
Table table = tableView.getTable();
SqlExplorerUtils.getDefault().setExportCSVActionTable(exportAction, table);
MenuManager popupMenu = new MenuManager();
// IAction newRowAction = new NewRowAction();
exportAction.setImageDescriptor(ImageLib.getImageDescriptor(ImageLib.EXPORT_WIZARD));
popupMenu.add(exportAction);
Menu menu = popupMenu.createContextMenu(table);
table.setMenu(menu);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(table);
if (this.getEditorInput() instanceof DrillDownEditorInput) {
DrillDownEditorInput ddEditorInput = (DrillDownEditorInput) this.getEditorInput();
if (ddEditorInput.getCurrIndicator().isUsedMapDBMode()) {
initTableViewerForMapDB(parent, table, ddEditorInput);
} else {
initTableViewerForJava(table, ddEditorInput);
}
// 3) Create Table columns with sort of paginated list.
for (TableColumn packColumn : table.getColumns()) {
packColumn.pack();
}
}
}
/**
* DOC talend Comment method "initTableViewerForJava".
*
* @param table
* @param ddEditorInput
*/
private void initTableViewerForJava(Table table, DrillDownEditorInput ddEditorInput) {
addTableColumn(ddEditorInput, table);
table.setLinesVisible(true);
table.setHeaderVisible(true);
table.setData(ddEditorInput.getDataSet());
tableView.setLabelProvider(new DrillDownResultLabelProvider());
tableView.setContentProvider(new DrillDownResultContentProvider());
tableView.setInput(this.getEditorInput());
}
/**
* DOC talend Comment method "initTableViewerForMapDB".
*
* @param parent
* @param table
* @param ddEditorInput
*/
@SuppressWarnings("unchecked")
private void initTableViewerForMapDB(final Composite parent, final Table table, DrillDownEditorInput ddEditorInput) {
table.setLinesVisible(true);
table.setHeaderVisible(true);
tableView.setLabelProvider(new DrillDownResultLabelProvider());
tableView.setContentProvider(new DrillDownResultContentProvider());
// set page size
final PageableController controller = new PageableController(MapDBPageConstant.NUMBER_PER_PAGE);
Object dataSetForMapDB = ddEditorInput.getDataSetForMapDB(controller.getPageSize());
if (dataSetForMapDB == null) {
log.error(DefaultMessagesImpl.getString("DrillDownResultEditor.drillDownError"), new RuntimeException(
DefaultMessagesImpl.getString("DrillDownResultEditor.drillDownErrorMessage")));
} else {
table.setData(dataSetForMapDB);
}
// for columnSet analysis here only have one db file need to support drill down and data section
Analysis analysis = ddEditorInput.getAnalysis();
AnalysisType analysisType = analysis.getParameters().getAnalysisType();
IPageLoader<PageResult<Object[]>> pageLoader = null;
AbstractDB<Object> mapDB = ddEditorInput.getMapDB();
Indicator generateMapDBIndicator = ddEditorInput.getGenerateMapDBIndicator();
MapDBManager.getInstance().addDBRef(MapDBUtils.getMapDBFile(generateMapDBIndicator));
Long itemsSize = ddEditorInput.getItemSize(mapDB);
if (AnalysisType.COLUMN_SET == analysisType) {
pageLoader = new MapDBPageLoader<Object>(mapDB, IDataValidationFactory.INSTANCE.createValidation(ddEditorInput
.getCurrIndicator()), itemsSize);
} else {
// ~
ColumnFilter filter = ddEditorInput.getColumnFilter();
pageLoader = new MapDBPageLoader<Object>(mapDB, null, itemsSize, filter);
}
controller.addPageChangedListener(PageLoaderStrategyHelper.createLoadPageAndReplaceItemsListener(controller, tableView,
pageLoader, PageResultContentProvider.getInstance(), null));
controller.addPageChangedListener(new PageChangedAdapter() {
/*
* (non-Javadoc)
*
* @see org.eclipse.nebula.widgets.pagination.PageChangedAdapter#pageIndexChanged(int, int,
* org.eclipse.nebula.widgets.pagination.PageableController)
*/
@Override
public void pageIndexChanged(int oldPageIndex, int newPageIndex, PageableController controller) {
Object data = table.getData();
if (data != null && SqlExplorerUtils.getDefault().isInstanceofTalendDataSet(data)) {
long totalSize = controller.getTotalElements();
long pageSize = controller.getPageSize();
long pageIndex = controller.getPageOffset();
long fromIndex = pageIndex;
long toIndex = pageIndex + pageSize;
if (toIndex > totalSize) {
toIndex = totalSize;
}
SqlExplorerUtils.getDefault().resetTalendDataSetIndex(data, fromIndex, toIndex);
parent.layout();
}
}
});
// Create navigation page links
ResultAndNavigationPageGraphicsRenderer resultAndNavigationPageGraphicsRenderer = new ResultAndNavigationPageGraphicsRenderer(
parent, SWT.NONE, controller);
resultAndNavigationPageGraphicsRenderer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
createColumns(tableView, controller, ((DrillDownEditorInput) this.getEditorInput()));
// Set current page to 0 to refresh the table
controller.setCurrentPage(0);
}
/**
* DOC talend Comment method "createColumns".
*
* @param tableView2
* @param controller
* @param currIndicator
*/
private void createColumns(TableViewer tableView2, PageableController controller, DrillDownEditorInput ddEditorInput) {
List<String> tableColumnNames = ddEditorInput.filterAdaptColumnHeader();
for (String tableColumnName : tableColumnNames) {
// First column is for the first name
TableViewerColumn col = createTableViewerColumn(tableView2, tableColumnName);
TableSectionViewerProvider provider = new TableSectionViewerProvider();
col.setLabelProvider(provider);
// TDQ-11356 msjian 2015-12-4: make the sort work well in the drilldown editor
addSorter(tableView2.getTable(), col.getColumn());
// TDQ-11356~
}
}
/**
* DOC zshen ColumnSetResultPage class global comment. Detailled comment
*/
class TableSectionViewerProvider extends CellLabelProvider implements IStructuredContentProvider, ITableLabelProvider,
ITableColorProvider {
@SuppressWarnings("unchecked")
public Object[] getElements(Object inputElement) {
List<Object> columnDataSet = (List<Object>) inputElement;
return columnDataSet.toArray();
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// nothing need to do at here
}
public Image getImage(Object element) {
if (element instanceof TdColumn) {
return ImageLib.getImage(ImageLib.TD_COLUMN);
}
return null;
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
public Image getColumnImage(Object element, int columnIndex) {
// TODO Auto-generated method stub
return null;
}
@SuppressWarnings("unchecked")
public String getColumnText(Object element, int columnIndex) {
if (List.class.isInstance(element)) {
List<Object> listElement = (List<Object>) element;
int listSize = listElement.size();
String[] keyArray = new String[listSize];
for (int index = 0; index < listElement.size(); index++) {
Object tempData = listElement.get(index);
keyArray[index] = tempData == null ? StringUtils.EMPTY : tempData.toString();
}
if (columnIndex < keyArray.length) {
if (keyArray[columnIndex] == null) {
return NULL_VALUE_DISPLAY_TEXT;
}
return keyArray[columnIndex];
}
} else {
for (int i = 0; i < ((Object[]) element).length; i++) {
if (columnIndex == i) {
return String.valueOf(((Object[]) element)[i]);
}
}
}
return null;
}
@Override
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
@Override
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
@Override
public void removeListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
public Color getBackground(Object element, int columnIndex) {
return null;
}
public Color getForeground(Object element, int columnIndex) {
// MOD by zshen for feature 14000
return null;
// ~14000
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell)
*/
@Override
public void update(ViewerCell cell) {
Object element = cell.getElement();
int index = cell.getColumnIndex();
cell.setText(getColumnText(element, index));
}
}
/**
* DOC talend Comment method "createTableViewerColumn".
*
* @param tableView2
* @param tableColumnName
* @return
*/
private TableViewerColumn createTableViewerColumn(TableViewer tableView2, String tableColumnName) {
final TableViewerColumn viewerColumn = new TableViewerColumn(tableView2, SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
column.setText(tableColumnName);
column.setResizable(true);
column.setMoveable(true);
return viewerColumn;
}
private void createCoolBar(Composite parent) {
CoolBar coolBar = new CoolBar(parent, SWT.HORIZONTAL | SWT.HORIZONTAL);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(coolBar);
actionList = new Hashtable<String, Action>();
actionList.put(ACTION_NAME[0], exportAction);
ToolBar toolBar = new ToolBar(coolBar, SWT.RIGHT | SWT.FLAT);
toolBar.pack();
for (String element : ACTION_NAME) {
ToolItem item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(actionList.get(element).getImageDescriptor().createImage());
item.setToolTipText(actionList.get(element).getText());
item.addSelectionListener(new ListenToTheAction(actionList.get(element)));
}
CoolItem coolEdit = new CoolItem(coolBar, SWT.HORIZONTAL | SWT.DROP_DOWN);
coolEdit.setControl(toolBar);
CoolItem[] coolItems = coolBar.getItems();
for (CoolItem coolItem : coolItems) {
Control control = coolItem.getControl();
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point coolSize = coolItem.computeSize(size.x, size.y);
if (control instanceof ToolBar) {
ToolBar bar = (ToolBar) control;
if (bar.getItemCount() > 0) {
size.x = bar.getItem(0).getWidth();
}
}
coolItem.setMinimumSize(size);
coolItem.setPreferredSize(coolSize);
coolItem.setSize(coolSize);
}
Point p = toolBar.computeSize(SWT.DEFAULT, SWT.DEFAULT);
toolBar.setSize(p);
Point p2 = coolEdit.computeSize(p.x, p.y);
coolEdit.setControl(toolBar);
coolEdit.setSize(p2);
coolBar.setLocked(true);
}
private void addTableColumn(DrillDownEditorInput ddEditorInput, Table table) {
List<String> columnElementList = ddEditorInput.filterAdaptColumnHeader();
for (String columnElement : columnElementList) {
TableColumn column = new TableColumn(table, SWT.CENTER);
column.setText(columnElement);
addSorter(table, column);
}
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
private void addSorter(final Table table, final TableColumn column) {
column.addListener(SWT.Selection, new Listener() {
boolean isAscend = true;
Collator comparator = Collator.getInstance(Locale.getDefault());
public void handleEvent(Event event) {
int columnIndex = getColumnIndex(table, column);
TableItem[] items = table.getItems();
int length = "...".equals(items[items.length - 1].getText(columnIndex)) ? items.length - 1 : items.length;//$NON-NLS-1$
for (int i = 1; i < length; i++) {
String value2 = items[i].getText(columnIndex);
for (int j = 0; j < i; j++) {
String value1 = items[j].getText(columnIndex);
boolean isLessThan = true;
if (StringUtils.isNumeric(value2) && StringUtils.isNotEmpty(value2) && StringUtils.isNumeric(value1)
&& StringUtils.isNotEmpty(value1)) {
isLessThan = Long.valueOf(value2).compareTo(Long.valueOf(value1)) < 0;
} else {
isLessThan = comparator.compare(value2, value1) < 0;
}
if ((isAscend && isLessThan) || (!isAscend && !isLessThan)) {
String[] values = getTableItemText(table, items[i]);
Object obj = items[i].getData();
items[i].dispose();
TableItem item = new TableItem(table, SWT.NONE, j);
item.setText(values);
item.setData(obj);
items = table.getItems();
break;
}
}
}
table.setSortColumn(column);
table.setSortDirection((isAscend ? SWT.UP : SWT.DOWN));
isAscend = !isAscend;
}
});
}
private int getColumnIndex(Table table, TableColumn column) {
TableColumn[] columns = table.getColumns();
for (int i = 0; i < columns.length; i++) {
if (columns[i].equals(column)) {
return i;
}
}
return -1;
}
private String[] getTableItemText(Table table, TableItem item) {
int count = table.getColumnCount();
String[] strs = new String[count];
for (int i = 0; i < count; i++) {
strs[i] = item.getText(i);
}
return strs;
}
/**
*
* DOC zshen DrillDownResultEditor class global comment. Detailled comment
*
* FIXME this inner class should be static. Confirm and fix the error.
*
*/
private class DrillDownResultLabelProvider implements ITableLabelProvider {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
*/
public Image getColumnImage(Object element, int columnIndex) {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
*/
public String getColumnText(Object element, int columnIndex) {
// MOD qiongli 2011-3-31,bug 20033,avoid ArrayIndexOutOfBoundsException
if (columnIndex >= ((Object[]) element).length) {
return PluginConstant.EMPTY_STRING;
}
Object object = ((Object[]) element)[columnIndex];
if (object != null) {
return object.toString();
}
return NULL_VALUE_DISPLAY_TEXT;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
*/
public void dispose() {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
*/
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void removeListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
}
/**
*
* DOC zshen DrillDownResultEditor class global comment. Detailled comment
*
* FIXME this inner class should be static. Confirm and fix the error.
*/
private class DrillDownResultContentProvider implements IStructuredContentProvider {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
if (inputElement instanceof DrillDownEditorInput) {
DrillDownEditorInput ddEditorInput = ((DrillDownEditorInput) inputElement);
List<Object[]> newColumnElementList = ddEditorInput.filterAdaptDataList();
if (ddEditorInput.isDataSpill()) {
Object[] leaveOutData = new Object[newColumnElementList.get(0).length];
for (int i = 0; i < newColumnElementList.get(0).length; i++) {
leaveOutData[i] = "...";//$NON-NLS-1$
}
newColumnElementList.add(leaveOutData);
}
return newColumnElementList.toArray();
} else if (List.class.isInstance(inputElement)) {
List<?> columnDataSet = (List<?>) inputElement;
return columnDataSet.toArray();
}
return new Object[0];
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// TODO Auto-generated method stub
viewer.getControl().pack();
}
}
/**
*
* DOC zshen DrillDownResultEditor class global comment. Detailled comment
*
* FIXME this inner class should be static. Confirm and fix the error.
*/
private class ListenToTheAction extends SelectionAdapter {
Action theAction;
public ListenToTheAction(Action action) {
super();
this.theAction = action;
}
@Override
public void widgetSelected(SelectionEvent e) {
this.theAction.run();
// changeCoolBarState();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.WorkbenchPart#dispose()
*/
@Override
public void dispose() {
super.dispose();
DrillDownEditorInput ddEditorInput = (DrillDownEditorInput) this.getEditorInput();
Indicator generateMapDBIndicator = ddEditorInput.getGenerateMapDBIndicator();
MapDBManager.getInstance().removeDBRef(MapDBUtils.getMapDBFile(generateMapDBIndicator));
}
}