// ============================================================================
//
// 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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.talend.core.model.repository.ERepositoryObjectType;
import org.talend.cwm.helper.SwitchHelpers;
import org.talend.dataprofiler.core.ImageLib;
import org.talend.dataprofiler.core.PluginConstant;
import org.talend.dataprofiler.core.i18n.internal.DefaultMessagesImpl;
import org.talend.dataprofiler.core.ui.dialog.TwoPartCheckSelectionDialog;
import org.talend.dataprofiler.core.ui.views.provider.DQRepositoryViewLabelProvider;
import org.talend.dataprofiler.core.ui.views.provider.ResourceViewContentProvider;
import org.talend.dataprofiler.core.ui.wizard.analysis.table.TableContentProvider;
import org.talend.dq.helper.RepositoryNodeHelper;
import org.talend.dq.nodes.DBCatalogRepNode;
import org.talend.dq.nodes.DBSchemaRepNode;
import org.talend.dq.nodes.DBTableFolderRepNode;
import org.talend.dq.nodes.DBTableRepNode;
import org.talend.dq.nodes.DBViewFolderRepNode;
import org.talend.dq.nodes.DBViewRepNode;
import org.talend.dq.nodes.DFConnectionFolderRepNode;
import org.talend.repository.model.IRepositoryNode;
import org.talend.repository.model.RepositoryNode;
/**
* DOC xqliu class global comment. Detailled comment
*/
public class TablesSelectionDialog extends TwoPartCheckSelectionDialog {
private Map<RepositoryNodeKey, List<IRepositoryNode>> packageCheckedMap;
private TableSelectionType tableType;
public TableSelectionType getTableType() {
return this.tableType;
}
public void setTableType(TableSelectionType tableType) {
this.tableType = tableType;
}
public TablesSelectionDialog(AbstractAnalysisMetadataPage metadataFormPage, Shell parent, String title,
List<IRepositoryNode> columnSetList, String message, RepositoryNode connComboSelectNode) {
super(metadataFormPage, parent, message);
this.setDialogType(DIALOG_TYPE_TABLE);
this.setInput(connComboSelectNode == null ? RepositoryNodeHelper.getRootNode(ERepositoryObjectType.METADATA)
: connComboSelectNode);
packageCheckedMap = new HashMap<RepositoryNodeKey, List<IRepositoryNode>>();
initCheckedColumnSet(columnSetList);
this.setTitle(title);
this.tableType = TableSelectionType.TABLE;
}
@Override
/**
* DOC mzhao bug 9240 mzhao 2009-11-05.
*
* @param columnSetList
*/
protected void unfoldToCheckedElements() {
// if there have a selected tree node, only unfold it is enough
if (this.selectedTreeRepoNode != null) {
Iterator<RepositoryNodeKey> it = packageCheckedMap.keySet().iterator();
while (it.hasNext()) {
RepositoryNodeKey csk = it.next();
if (this.selectedTreeRepoNode.equals(csk.getPackageNode())) {
unfoldRepositoryNode(csk);
break;
}
}
} else { // if there have not a selected tree node, unfold all nodes
Iterator<RepositoryNodeKey> it = packageCheckedMap.keySet().iterator();
while (it.hasNext()) {
RepositoryNodeKey csk = it.next();
unfoldRepositoryNode(csk);
}
}
}
private void unfoldRepositoryNode(RepositoryNodeKey csk) {
IRepositoryNode packageNode = csk.getPackageNode();
List<IRepositoryNode> checkedTableNodeList = packageCheckedMap.get(csk);
if (checkedTableNodeList != null && !checkedTableNodeList.isEmpty()) {
if (isHideNode(checkedTableNodeList) && RepositoryNodeHelper.isOpenDQCommonViewer()) {
packageNode = findLastVisibleNode(checkedTableNodeList.get(0));
this.setMessage(DefaultMessagesImpl.getString("ColumnSelectionDialog.CannotFindNodeMessage")); //$NON-NLS-1$
if (packageNode == null) {
return;
}
}
// // to get TableFolderNode or viewFolderNode
IRepositoryNode selectNode = getAdaptLocationNode(packageNode, checkedTableNodeList.get(0));
if (selectNode != null) {
packageNode = selectNode;
}
getTreeViewer().expandToLevel(packageNode, 1);
StructuredSelection structSel = new StructuredSelection(packageNode);
getTreeViewer().setSelection(structSel);
}
}
/*
* (non-Javadoc)
*
* @see org.talend.dataprofiler.core.ui.dialog.TwoPartCheckSelectionDialog#restoreCheckStatus()
*/
@Override
protected void restoreCheckStatus() {
if (packageCheckedMap.keySet().size() == 0) {
return;
}
RepositoryNodeKey[] packeNodeKeyArray = new RepositoryNodeKey[packageCheckedMap.keySet().size()];
packeNodeKeyArray = packageCheckedMap.keySet().toArray(packeNodeKeyArray);
List<IRepositoryNode> folderNodeList = new ArrayList<IRepositoryNode>();
for (RepositoryNodeKey pKey : packeNodeKeyArray) {
List<IRepositoryNode> allCheckedTableNodeList = packageCheckedMap.get(pKey);
int addedCount = 0;
for (IRepositoryNode tableOrViewNode : allCheckedTableNodeList) {
// Add the adapted table or view node into list.
if (addedCount == 2) {
break;
}
IRepositoryNode adaptLocationNode = null;
adaptLocationNode = getAdaptLocationNode(pKey.getPackageNode(), tableOrViewNode);
if (!folderNodeList.contains(adaptLocationNode)) {
folderNodeList.add(adaptLocationNode);
addedCount++;
}
}
}
getTreeViewer().setCheckedElements(folderNodeList.toArray());
}
@Override
protected void restoreTableCheckStatus() {
List<IRepositoryNode> allCheckedTables = this.getAllCheckedTables();
if (!allCheckedTables.isEmpty()) {
getTableViewer().setCheckedElements(allCheckedTables.toArray(new IRepositoryNode[allCheckedTables.size()]));
}
}
private void initCheckedColumnSet(List<IRepositoryNode> columnSetList) {
List<IRepositoryNode> packageList = new ArrayList<IRepositoryNode>();
for (IRepositoryNode columnSetNode : columnSetList) {
if (columnSetNode instanceof DBTableRepNode) {
DBTableRepNode tableRepNode = (DBTableRepNode) columnSetNode;
// MOD qiongli 2012-5-4 TDQ-5137 use the table parent(DBTableFolderRepNode not DBCatalogRepNode or
// DBSchemaRepNode).
IRepositoryNode parentPackageNode = tableRepNode.getParent();
if (parentPackageNode != null) {
if (!packageList.contains(parentPackageNode)) {
packageList.add(parentPackageNode);
}
RepositoryNodeKey packageKey = new RepositoryNodeKey(parentPackageNode);
List<IRepositoryNode> repoNodelist = packageCheckedMap.get(packageKey);
if (repoNodelist == null) {
repoNodelist = new ArrayList<IRepositoryNode>();
this.packageCheckedMap.put(packageKey, repoNodelist);
}
repoNodelist.add(tableRepNode);
}
} else if (columnSetNode instanceof DBViewRepNode) {
// support DBview
DBViewRepNode viewRepNode = (DBViewRepNode) columnSetNode;
IRepositoryNode parentPackageNode = viewRepNode.getParent();
if (parentPackageNode != null) {
if (!packageList.contains(parentPackageNode)) {
packageList.add(parentPackageNode);
}
RepositoryNodeKey packageKey = new RepositoryNodeKey(parentPackageNode);
List<IRepositoryNode> repoNodelist = packageCheckedMap.get(packageKey);
if (repoNodelist == null) {
repoNodelist = new ArrayList<IRepositoryNode>();
this.packageCheckedMap.put(packageKey, repoNodelist);
}
repoNodelist.add(viewRepNode);
}
}
}
this.setInitialElementSelections(packageList);
}
@Override
protected void initProvider() {
fLabelProvider = new DQRepositoryViewLabelProvider();
fContentProvider = new DBTreeViewContentProvider();
sLabelProvider = new TableLabelProvider();
sContentProvider = new TableContentProvider();
}
@Override
protected void addCheckedListener() {
// When user checks a checkbox in the tree, check all its children
getTreeViewer().addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
TreePath treePath = new TreePath(new Object[] { event.getElement() });
getTreeViewer().setSelection(new TreeSelection(treePath));
if (event.getChecked()) {
Object element = event.getElement();
getTreeViewer().setSubtreeChecked(element, true);
if (element instanceof IRepositoryNode) {
setOutput(element);
handleTablesChecked((IRepositoryNode) element, true);
}
} else {
Object element = event.getElement();
getTreeViewer().setSubtreeChecked(element, false);
if (element instanceof IRepositoryNode) {
setOutput(element);
handleTablesChecked((IRepositoryNode) element, false);
}
}
updateOKStatus();
}
});
getTableViewer().addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
Object element = event.getElement();
if (element instanceof DBTableRepNode || element instanceof DBViewRepNode) {
handleTableChecked((IRepositoryNode) element, event.getChecked());
}
}
});
}
private IRepositoryNode[] getCheckedTableNodes(IRepositoryNode node) {
RepositoryNodeKey packageKey = new RepositoryNodeKey(node);
List<IRepositoryNode> repoNodeList = packageCheckedMap.get(packageKey);
if (repoNodeList == null) {
Boolean allCheckFlag = this.getTreeViewer().getChecked(node);
this.getTableViewer().setAllChecked(allCheckFlag);
repoNodeList = allCheckFlag ? RepositoryNodeHelper.getNamedColumnSetNodes(node) : new ArrayList<IRepositoryNode>();
packageCheckedMap.put(packageKey, repoNodeList);
return allCheckFlag ? repoNodeList.toArray(new IRepositoryNode[repoNodeList.size()]) : null;
} else {
return repoNodeList.toArray(new IRepositoryNode[repoNodeList.size()]);
}
}
private void handleTableChecked(IRepositoryNode columnSet, Boolean checkedFlag) {
IRepositoryNode parentPackageNode = columnSet.getParent();
if (checkedFlag) {
getTreeViewer().setChecked(parentPackageNode, true);
}
RepositoryNodeKey repositoryNodeKey = new RepositoryNodeKey(parentPackageNode);
List<IRepositoryNode> repoNodeList = packageCheckedMap.get(repositoryNodeKey);
if (repoNodeList == null) {
repoNodeList = new ArrayList<IRepositoryNode>();
packageCheckedMap.put(repositoryNodeKey, repoNodeList);
}
if (checkedFlag) {
repoNodeList.add(columnSet);
} else {
repoNodeList.remove(columnSet);
}
// If the element in the right table check viewer are all DESELECTED, then clear the check status in the left
// tree viewer.
if (!checkedFlag && repoNodeList.size() == 0) {
getTreeViewer().setChecked(parentPackageNode, false);
}
}
private void handleTablesChecked(IRepositoryNode packageNode, Boolean checkedFlag) {
RepositoryNodeKey key = new RepositoryNodeKey(packageNode);
List<IRepositoryNode> repoNodeList = checkedFlag ? RepositoryNodeHelper.getNamedColumnSetNodes(packageNode) : null;
packageCheckedMap.put(key, repoNodeList);
getTableViewer().setAllChecked(checkedFlag);
}
/*
* (non-Javadoc)
*
* @see org.talend.dataprofiler.core.ui.dialog.TwoPartCheckSelectionDialog#updateOKStatus()
*/
@Override
protected void updateOKStatus() {
int initSize = 0;
for (RepositoryNodeKey nodeKey : packageCheckedMap.keySet()) {
List<IRepositoryNode> tableList = packageCheckedMap.get(nodeKey);
initSize += tableList == null ? 0 : tableList.size();
}
if (initSize <= 0) {
Status fCurrStatus = new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, IStatus.WARNING,
DefaultMessagesImpl.getString("TablesSelectionDialog.noTableFoundWarning", PluginConstant.SPACE_STRING), null); //$NON-NLS-1$
this.updateStatus(fCurrStatus);
return;
}
super.updateOKStatus();
}
@Override
protected void addSelectionButtonListener(Button selectButton, Button deselectButton) {
SelectionListener listener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object[] viewerElements = fContentProvider.getElements(getTreeViewer().getInput());
if (fContainerMode) {
getTreeViewer().setCheckedElements(viewerElements);
} else {
for (Object viewerElement : viewerElements) {
getTreeViewer().setSubtreeChecked(viewerElement, true);
}
}
packageCheckedMap.clear();
if (getTableViewer().getInput() != null) {
handleTablesChecked((IRepositoryNode) getTableViewer().getInput(), true);
}
updateOKStatus();
}
};
selectButton.addSelectionListener(listener);
listener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getTreeViewer().setCheckedElements(new Object[0]);
packageCheckedMap.clear();
if (getTableViewer().getInput() != null) {
handleTablesChecked((IRepositoryNode) getTableViewer().getInput(), false);
}
updateOKStatus();
}
};
deselectButton.addSelectionListener(listener);
}
public void selectionChanged(SelectionChangedEvent event) {
Object selectedObj = ((IStructuredSelection) event.getSelection()).getFirstElement();
if (selectedObj != null) {
if (selectedObj instanceof DBTableFolderRepNode || selectedObj instanceof DBViewFolderRepNode) {
IRepositoryNode node = (IRepositoryNode) selectedObj;
this.selectedTreeRepoNode = node.getParent();
this.setOutput(node);
IRepositoryNode[] tables = getCheckedTableNodes(node);
if (tables != null) {
this.getTableViewer().setCheckedElements(tables);
}
}
}
}
/**
* This class will combine catlogName and/or schemaName as a key.
*
* FIXME this inner class should be static. Confirm and fix the error.
*/
class RepositoryNodeKey {
private static final String CATALOG_NAME = "__Catalog_Name__";//$NON-NLS-1$
private static final String SCHEMA_NAME = "__Schema_Name__";//$NON-NLS-1$
private String catalogName;
private String schemaName;
private IRepositoryNode node = null;
public RepositoryNodeKey(IRepositoryNode node) {
this.node = node;
initNames(node);
}
private void initNames(IRepositoryNode node) {
if (node instanceof DBCatalogRepNode) {
DBCatalogRepNode catalogNode = (DBCatalogRepNode) node;
catalogName = SwitchHelpers.CATALOG_SWITCH.doSwitch(catalogNode.getCatalog()) == null ? CATALOG_NAME
: SwitchHelpers.CATALOG_SWITCH.doSwitch(catalogNode.getCatalog()).getName();
schemaName = SCHEMA_NAME;
} else if (node instanceof DBSchemaRepNode) {
DBSchemaRepNode schemaNode = (DBSchemaRepNode) node;
RepositoryNode parentNode = schemaNode.getParent();
if (parentNode instanceof DBCatalogRepNode) {
initNames(parentNode);
} else {
catalogName = CATALOG_NAME;
}
schemaName = SwitchHelpers.SCHEMA_SWITCH.doSwitch(schemaNode.getSchema()) == null ? SCHEMA_NAME
: SwitchHelpers.SCHEMA_SWITCH.doSwitch(schemaNode.getSchema()).getName();
} else if (node instanceof DBTableFolderRepNode || node instanceof DBViewFolderRepNode) {
initNames(node.getParent());
// MOD qiongli 2012-5-4 TDQ-5137.
this.node = node.getParent();
} else {
catalogName = CATALOG_NAME;
schemaName = SCHEMA_NAME;
}
}
public IRepositoryNode getPackageNode() {
return this.node;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((catalogName == null) ? 0 : catalogName.hashCode());
result = prime * result + ((schemaName == null) ? 0 : schemaName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final RepositoryNodeKey other = (RepositoryNodeKey) obj;
if (catalogName == null) {
if (other.catalogName != null) {
return false;
}
} else if (!catalogName.equals(other.catalogName)) {
return false;
}
if (schemaName == null) {
if (other.schemaName != null) {
return false;
}
} else if (!schemaName.equals(other.schemaName)) {
return false;
}
return true;
}
}
@Override
protected void computeResult() {
setResult(getAllCheckedTables());
}
private List<IRepositoryNode> getAllCheckedTables() {
Object[] checkedNodes = this.getTreeViewer().getCheckedElements();
List<IRepositoryNode> tableList = new ArrayList<IRepositoryNode>();
for (Object obj : checkedNodes) {
if (!(obj instanceof DBTableFolderRepNode || obj instanceof DBViewFolderRepNode)) {
continue;
}
IRepositoryNode node = (IRepositoryNode) obj;
RepositoryNodeKey packageKey = new RepositoryNodeKey(node);
if (packageCheckedMap.containsKey(packageKey)) {
tableList.addAll(packageCheckedMap.get(packageKey));
} else {
tableList.addAll(RepositoryNodeHelper.getNamedColumnSetNodes(node));
}
}
// ADD msjian 2011-7-8 feature 22206: Add filters
// add the miss of before checked when use the filter
Iterator<?> it = packageCheckedMap.keySet().iterator();
while (it.hasNext()) {
RepositoryNodeKey packageKey = (RepositoryNodeKey) it.next();
List<?> checkedTableNodeList = packageCheckedMap.get(packageKey);
if (checkedTableNodeList != null) {
for (int i = 0; i < checkedTableNodeList.size(); i++) {
if (!tableList.contains(checkedTableNodeList.get(i))) {
tableList.add((IRepositoryNode) checkedTableNodeList.get(i));
}
}
}
}
return tableList;
}
@Override
protected void okPressed() {
List<IRepositoryNode> allCheckedTables = getAllCheckedTables();
// Added TDQ-8718 20140505 yyin: if no columns checked, warn the user
if (allCheckedTables.size() == 0) {
MessageDialogWithToggle.openWarning(this.getShell(), DefaultMessagesImpl.getString("ColumnSelectionDialog.warning"),//$NON-NLS-1$
DefaultMessagesImpl.getString("TablesSelectionDialog.NoTableSelecte"));//$NON-NLS-1$
return;
}// ~
super.okPressed();
this.packageCheckedMap = null;
}
/**
* label provider for table viewer.
*
* FIXME this inner class should be static. Confirm and fix the error.
*/
class TableLabelProvider extends LabelProvider {
@Override
public Image getImage(Object element) {
if (element instanceof DBTableRepNode) {
return ImageLib.getImage(ImageLib.TABLE);
} else if (element instanceof DBViewRepNode) {
return ImageLib.getImage(ImageLib.VIEW);
} else {
return null;
}
}
@Override
public String getText(Object element) {
if (element instanceof IRepositoryNode) {
return ((IRepositoryNode) element).getLabel();
}
return "";//$NON-NLS-1$
}
}
/**
* DOC xqliu TablesSelectionDialog class global comment. Detailled comment
*/
class DBTreeViewContentProvider extends ResourceViewContentProvider {
public DBTreeViewContentProvider() {
super();
}
@Override
public Object[] getChildren(Object parentElement) {
if (!(parentElement instanceof DBTableFolderRepNode || parentElement instanceof DBViewFolderRepNode)) {
if (parentElement instanceof IRepositoryNode) {
IRepositoryNode repoNode = (IRepositoryNode) parentElement;
return filterTableView(repoNode.getChildren()).toArray();
}
}
return null;
}
@Override
public Object getParent(Object element) {
if (element instanceof IRepositoryNode) {
return ((IRepositoryNode) element).getParent();
}
return null;
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof IRepositoryNode) {
if (!(element instanceof DBTableFolderRepNode || element instanceof DBViewFolderRepNode)) {
return ((IRepositoryNode) element).hasChildren();
}
}
return false;
}
}
/**
* Table Selection Dialog type enum.
*/
public enum TableSelectionType {
TABLE("table", "Table"), //$NON-NLS-1$//$NON-NLS-2$
VIEW("view", "View"), //$NON-NLS-1$//$NON-NLS-2$
ALL("all", "Table/View"); //$NON-NLS-1$//$NON-NLS-2$
private String key;
private String label;
public String getKey() {
return this.key;
}
public String getLabel() {
return this.label;
}
TableSelectionType() {
this("table", "Table"); //$NON-NLS-1$//$NON-NLS-2$
}
TableSelectionType(String key) {
this(key, key);
}
TableSelectionType(String key, String label) {
this.key = key;
this.label = label;
}
}
/**
* filter for table and view according to the dialog's type.
*
* @param nodes
* @return
*/
public List<IRepositoryNode> filterTableView(List<IRepositoryNode> nodes) {
List<IRepositoryNode> list = new ArrayList<IRepositoryNode>();
for (IRepositoryNode node : nodes) {
// MOD klliu 2001-03-08 bug 19243: In table selection wizard should filter mdm and file connection
if (!(node instanceof DFConnectionFolderRepNode)) {
if (node instanceof DBTableFolderRepNode) {
if (TableSelectionType.TABLE.equals(getTableType()) || TableSelectionType.ALL.equals(getTableType())) {
list.add(node);
}
} else if (node instanceof DBViewFolderRepNode) {
if (TableSelectionType.VIEW.equals(getTableType()) || TableSelectionType.ALL.equals(getTableType())) {
list.add(node);
}
} else {
list.add(node);
}
}
}
return list;
}
}