// ============================================================================
//
// 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.imex;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
import org.talend.commons.emf.FactoriesUtil;
import org.talend.commons.exception.ExceptionHandler;
import org.talend.cwm.helper.ResourceHelper;
import org.talend.dataprofiler.core.ImageLib;
import org.talend.dataprofiler.core.PluginConstant;
import org.talend.dataprofiler.core.migration.helper.IndicatorDefinitionFileHelper;
import org.talend.dataprofiler.core.ui.imex.model.EImexType;
import org.talend.dataprofiler.core.ui.imex.model.IImportWriter;
import org.talend.dataprofiler.core.ui.imex.model.ImportWriterFactory;
import org.talend.dataprofiler.core.ui.imex.model.ItemRecord;
import org.talend.dataprofiler.core.ui.progress.ProgressUI;
import org.talend.dataprofiler.core.ui.utils.DqFileUtils;
import org.talend.dataprofiler.core.ui.utils.ImportAndExportUtils;
import org.talend.dataquality.indicators.definition.IndicatorDefinition;
import org.talend.dq.helper.EObjectHelper;
import org.talend.dq.helper.PropertyHelper;
import org.talend.dq.helper.ReportFileHelper;
import orgomg.cwm.objectmodel.core.ModelElement;
/**
* DOC bZhou class global comment. Detailled comment
*/
public class ImportWizardPage extends WizardPage {
private static final String SELECT_ARCHIVE_FILE = Messages.getString("ExportWizardPage.8"); //$NON-NLS-1$
private static final String BROWSE = Messages.getString("ExportWizardPage.7"); //$NON-NLS-1$
private static final String SELECT_ROOT_DIR = Messages.getString("ExportWizardPage.6"); //$NON-NLS-1$
private static final String OVERWRITE_EXIST_ITEM = Messages.getString("ImportWizardPage.4"); //$NON-NLS-1$
private CheckboxTreeViewer repositoryTree;
private TableViewer errorsList;
protected Button dirBTN, archBTN;
private Button browseDirBTN, browseArchBTN;
protected Button overwriteBTN;
protected Text dirTxt, archTxt;
protected IImportWriter writer;
protected String basePath;
private List<String> errors = new ArrayList<String>();
private final String underlineStr = "_";//$NON-NLS-1$
private final String subrepName = "subreports";//$NON-NLS-1$
private static final String[] FILE_EXPORT_MASK = { "*.zip;*.tar;*.tar.gz", "*.*" }; //$NON-NLS-1$//$NON-NLS-2$
public ImportWizardPage() {
super(Messages.getString("ImportWizardPage.2")); //$NON-NLS-1$
setMessage(Messages.getString("ImportWizardPage.3")); //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
Composite top = new Composite(parent, SWT.NONE);
top.setLayout(new GridLayout());
top.setLayoutData(new GridData(GridData.FILL_BOTH));
createSelectComposite(top);
createRepositoryTree(top);
createErrorsList(top);
createOptionComposite(top);
initControlState();
addListeners();
setControl(top);
}
/**
* DOC bZhou Comment method "addListeners".
*/
private void addListeners() {
SelectionListener modeSwitchListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setDirState(isDirState());
setArchState(!isDirState());
}
};
dirBTN.addSelectionListener(modeSwitchListener);
archBTN.addSelectionListener(modeSwitchListener);
ModifyListener populateListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateBasePath();
}
};
dirTxt.addModifyListener(populateListener);
archTxt.addModifyListener(populateListener);
browseDirBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String result = openDirectoryDialog();
if (result != null) {
dirTxt.setText(result);
}
}
private String openDirectoryDialog() {
DirectoryDialog dialog = new DirectoryDialog(Display.getDefault().getActiveShell());
if (dirTxt.getText() != null) {
dialog.setFilterPath(dirTxt.getText());
}
return dialog.open();
}
});
browseArchBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String result = openFileDialog();
if (result != null) {
archTxt.setText(result);
}
}
private String openFileDialog() {
FileDialog dialog = new FileDialog(Display.getDefault().getActiveShell());
dialog.setFilterExtensions(FILE_EXPORT_MASK);
if (archTxt.getText() != null) {
dialog.setFileName(archTxt.getText());
}
return dialog.open();
}
});
overwriteBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// MOD msjian 2012-2-29 TDQ-4701: fixed another issue, when the user checked the overwrite checkbox, do
// not do migration
populateElement();
checkforErrors();
// TDQ-4701 ~
}
});
repositoryTree.getTree().addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
TreeItem item = (TreeItem) e.item;
ItemRecord record = (ItemRecord) item.getData();
if (record.getFile().isFile()) {
// MOD qiongli TDQ-5368 only uncheck the client dependecy when uncheck an item,not supplier
// dependency.
boolean checked = item.getChecked();
if (checked) {
for (File file : record.getDependencySet()) {
ItemRecord findRecord = ItemRecord.findRecord(file);
if (findRecord != null) {
repositoryTree.setChecked(findRecord, checked);
}
}
} else {
ModelElement element = record.getElement();
if (element != null) {
List<ModelElement> dependencyClients = EObjectHelper.getDependencyClients(element);
ImportAndExportUtils.iterateUncheckClientDependency(dependencyClients, repositoryTree);
}
}
}
populateElement();
repositoryTree.refresh();
checkforErrors();
}
});
}
/**
*
* Comment method "updateBasePath".
*/
public void updateBasePath() {
if (isDirState()) {
basePath = dirTxt.getText();
} else {
basePath = archTxt.getText();
}
textModified(basePath);
}
/**
* if the user select:overwrite, the conflick records become valid.otherwise, invalid when conflict
*/
private void populateElement() {
ItemRecord[] invalidRecords = writer.populate(getElements(), !overwriteBTN.getSelection());
updateErrorList(invalidRecords);
if (invalidRecords.length > 0) {
removeInvalidRecords(invalidRecords);
}
}
/**
* DOC bZhou Comment method "removeInvalidRecords".
*
* @param invalidRecords
*/
public void removeInvalidRecords(ItemRecord[] invalidRecords) {
if (invalidRecords != null) {
for (ItemRecord record : invalidRecords) {
if (!overwriteBTN.getSelection()) {
repositoryTree.setChecked(record, false);
}
}
repositoryTree.refresh();
}
}
/**
* DOC sgandon Comment method "dirTextModified".
*/
protected void textModified(String pathStr) {
IPath path = new Path(pathStr);
if (path.toFile().exists()) {
ItemRecord input = writer.computeInput(path);
migrate();
repositoryTree.setInput(input);
repositoryTree.expandAll();
TreeItem[] topItems = repositoryTree.getTree().getItems();
for (TreeItem treeItem : topItems) {
repositoryTree.setSubtreeChecked(treeItem.getData(), true);
}
repositoryTree.refresh();
} else {
repositoryTree.setInput(null);
}
populateElement();
checkforErrors();
}
/**
* DOC bZhou Comment method "migrate".
*/
private void migrate() {
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
writer.migration(monitor);
}
};
try {
ProgressUI.popProgressDialog(op);
} catch (Exception e) {
ExceptionHandler.process(e);
}
}
/**
* update the page state that is the finish button enable state according to the error message being present or not.
*/
protected void updatePageStatus() {
boolean valid = getErrorMessage() == null;
setPageComplete(valid);
}
/**
* check that directory exist and issue an error message if not. <br>
* check that the folder is a data quality repository or issue an error.<br>
* check that anything is check in the tree or issue an error.<br>
*/
protected void checkforErrors() {
List<String> dErrors = new ArrayList<String>();
if (repositoryTree.getTree().getItems().length == 0) {
dErrors.add(Messages.getString("ImportWizardPage.0")); //$NON-NLS-1$
}
if (repositoryTree.getCheckedElements().length == 0) {
dErrors.add(Messages.getString("ImportWizardPage.1")); //$NON-NLS-1$
}
dErrors.addAll(writer.check());
ItemRecord[] elements = getElements();
for (ItemRecord record : elements) {
dErrors.addAll(record.getErrors());
for (File depFile : record.getDependencySet()) {
ItemRecord findRecord = ItemRecord.findRecord(depFile);
if (findRecord == null || !repositoryTree.getChecked(findRecord)) {
// TDQ-12410: if the dependency comes from reference project, we ingore it.
if (!DqFileUtils.isFileUnderBasePath(depFile, writer.getBasePath())) {
continue;
}
ModelElement element = ItemRecord.getElement(depFile);
// if the element is IndicatorDefinition and it exist in the current project and don't include any
// sql and java templates and the AggregatedDefinitions is not empty or TableOverview/ViewOverview
// Indicator, don't add it into errors even if it is not exist
if (element instanceof IndicatorDefinition) {
String uuid = ResourceHelper.getUUID(element);
if (IndicatorDefinitionFileHelper.isTechnialIndicator(uuid)) {
continue;
}
}
// MOD qiongli 2012-12-13 TDQ-5356 use itself file name for jrxml
boolean isJrxmlDepFile = depFile.getName().endsWith(FactoriesUtil.JRXML);
// MOD msjian TDQ-5909: modify to displayName
String dptLabel = element != null && !isJrxmlDepFile && PropertyHelper.getProperty(element) != null ? PropertyHelper
.getProperty(element).getDisplayName() : depFile.getName();
// TDQ-5909~
dErrors.add("\"" + record.getName() + "\" miss dependency :" + dptLabel); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
if (!dErrors.isEmpty()) {
setErrorMessage(dErrors.get(0));
} else {
setErrorMessage(null);
}
updatePageStatus();
}
/**
* DOC bZhou Comment method "initControlState".
*/
protected void initControlState() {
setArchState(false);
setPageComplete(false);
this.writer = ImportWriterFactory.create(EImexType.FILE);
}
/**
* DOC bZhou Comment method "createRepositoryTree".
*
* @param top
*/
private void createRepositoryTree(Composite top) {
repositoryTree = new ContainerCheckedTreeViewer(top);
repositoryTree.setContentProvider(new FileTreeContentProvider());
repositoryTree.setLabelProvider(new FileTreeLabelProvider());
repositoryTree.setInput(PluginConstant.EMPTY_STRING);
GridDataFactory.fillDefaults().grab(true, true).applyTo(repositoryTree.getTree());
}
/**
* DOC bZhou Comment method "createErrorsList".
*
* @param top
*/
private void createErrorsList(Composite top) {
Group errorGroup = new Group(top, SWT.NONE);
errorGroup.setLayout(new GridLayout());
errorGroup.setText(Messages.getString("ImportWizardPage.5")); //$NON-NLS-1$
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.heightHint = 100;
errorGroup.setLayoutData(gridData);
errorsList = new TableViewer(errorGroup, SWT.BORDER);
errorsList.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
errorsList.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
return errors.toArray();
}
});
errorsList.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
return element.toString();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
*/
@Override
public Image getImage(Object element) {
if (overwriteBTN.getSelection()) {
return ImageLib.getImage(ImageLib.WARN_OVR);
}
return ImageLib.getImage(ImageLib.ICON_ERROR_INFO);
}
});
errorsList.setInput(this);
errorsList.setSorter(new ViewerSorter());
}
/**
* DOC bZhou Comment method "createOptionComposite".
*
* @param top
*/
private void createOptionComposite(Composite top) {
overwriteBTN = new Button(top, SWT.CHECK);
overwriteBTN.setText(OVERWRITE_EXIST_ITEM);
overwriteBTN.setToolTipText(OVERWRITE_EXIST_ITEM);
}
/**
* DOC bZhou Comment method "setDirState".
*
* @param state
*/
protected void setDirState(boolean state) {
dirTxt.setEnabled(state);
browseDirBTN.setEnabled(state);
if (state) {
writer = ImportWriterFactory.create(EImexType.FILE);
updateBasePath();
}
}
/**
* DOC bZhou Comment method "isDirState".
*
* @return
*/
public boolean isDirState() {
return dirBTN.getSelection();
}
/**
* DOC bZhou Comment method "setArchState".
*
* @param state
*/
protected void setArchState(boolean state) {
archTxt.setEnabled(state);
browseArchBTN.setEnabled(state);
if (state) {
writer = ImportWriterFactory.create(EImexType.ZIP_FILE);
updateBasePath();
}
}
/**
* DOC bZhou Comment method "isArchState".
*
* @return
*/
public boolean isArchState() {
return archBTN.getSelection();
}
/**
* DOC bZhou Comment method "createSelectComposite".
*
* @param top
*/
private void createSelectComposite(Composite top) {
Composite selectComp = new Composite(top, SWT.NONE);
selectComp.setLayout(new GridLayout(3, false));
selectComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
dirBTN = new Button(selectComp, SWT.RADIO);
dirBTN.setText(SELECT_ROOT_DIR);
dirBTN.setToolTipText(SELECT_ROOT_DIR);
setButtonLayoutData(dirBTN);
dirTxt = new Text(selectComp, SWT.BORDER);
dirTxt.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
browseDirBTN = new Button(selectComp, SWT.PUSH);
browseDirBTN.setText(BROWSE);
browseDirBTN.setToolTipText(BROWSE);
setButtonLayoutData(browseDirBTN);
archBTN = new Button(selectComp, SWT.RADIO);
archBTN.setText(SELECT_ARCHIVE_FILE);
archBTN.setToolTipText(SELECT_ARCHIVE_FILE);
setButtonLayoutData(archBTN);
archTxt = new Text(selectComp, SWT.BORDER);
archTxt.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
browseArchBTN = new Button(selectComp, SWT.PUSH);
browseArchBTN.setText(BROWSE);
browseArchBTN.setToolTipText(BROWSE);
setButtonLayoutData(browseArchBTN);
}
/**
* DOC bZhou Comment method "getElements".
*
* @return
*/
public ItemRecord[] getElements() {
List<ItemRecord> itemRecords = new ArrayList<ItemRecord>();
Object[] checkedElements = repositoryTree.getCheckedElements();
for (Object obj : checkedElements) {
if (obj instanceof ItemRecord) {
ItemRecord record = (ItemRecord) obj;
// MOD qiongli 2012-4-20,add related subreport jrxml/jasper file to elements.
File file = record.getFile();
if (file.isFile()) {
itemRecords.add(record);
if (file.getName().endsWith(FactoriesUtil.JRXML)) {
addSubRepToElements(record, itemRecords);
}
// if it is Mean Indicator, import it's dependency Sum Indicator also
String meanIndicatorUuid = "_ccI48RF2Ed2PKb6nEJEvhw"; //$NON-NLS-1$
ModelElement element = record.getElement();
if (element != null && element instanceof IndicatorDefinition
&& meanIndicatorUuid.equals(ResourceHelper.getUUID(element))) {
File sumIndicatorFile = getSumIndicatorFile(element);
if (sumIndicatorFile != null) {
itemRecords.add(new ItemRecord(sumIndicatorFile, record.getRootFolderPath()));
}
}
}
}
}
return itemRecords.toArray(new ItemRecord[itemRecords.size()]);
}
/**
* get the Sum Indicator File according to the Mean Indicator's ModelElement.
*
* @param meanIndicator
* @return
*/
private File getSumIndicatorFile(ModelElement meanIndicator) {
String sumIndicatorLabel = "Sum"; //$NON-NLS-1$
File sumIndicatorFile = null;
File meanIndicatorFile = new File(meanIndicator.eResource().getURI().toFileString());
if (meanIndicatorFile.exists() && meanIndicatorFile.isFile()) {
File parentFile = meanIndicatorFile.getParentFile();
File[] listFiles = parentFile.listFiles();
for (File listFile : listFiles) {
if (listFile.isFile()) {
String fileName = listFile.getName();
if (!StringUtils.isBlank(fileName)) {
if (fileName.startsWith(sumIndicatorLabel) && fileName.endsWith(FactoriesUtil.DEFINITION)) {
sumIndicatorFile = listFile;
break;
}
}
}
}
}
return sumIndicatorFile;
}
/**
* Getter for writer.
*
* @return the writer
*/
public IImportWriter getWriter() {
return this.writer;
}
/**
* DOC bZhou Comment method "updateErrorList".
*
* @param records
*/
public void updateErrorList(ItemRecord[] records) {
errors.clear();
for (ItemRecord record : records) {
errors.addAll(record.getErrors());
}
errorsList.setInput(errors);
errorsList.refresh();
}
/**
*
* add related subReport jrxml/jasper file to List.
*
* @param record
* @param itemRecords
*/
private void addSubRepToElements(ItemRecord record, List<ItemRecord> itemRecords) {
File file = record.getFile();
if (record.getProperty() == null) {
return;
}
String version = record.getProperty().getVersion();
String nameWithoutVersion = file.getName().replaceAll(underlineStr + version, PluginConstant.EMPTY_STRING)
.replaceAll(PluginConstant.DOT_STRING + FactoriesUtil.JRXML, PluginConstant.EMPTY_STRING);
File parentFile = file.getParentFile().getParentFile();
if (parentFile == null || !parentFile.exists()) {
return;
}
File subRepFolder = new Path(parentFile.getPath() + IPath.SEPARATOR + subrepName).toFile();
if (subRepFolder == null || !subRepFolder.exists()) {
return;
}
Map<String, List<String>> mainSubRepMap = ReportFileHelper.getMainSubRepMap();
String fName;
for (File f : subRepFolder.listFiles()) {
fName = f.getName();
if (f.getName().equalsIgnoreCase(file.getName())) {
continue;
}
// add the same name jasper file when the sub-report jrxml is checked on UI.
if (fName.equalsIgnoreCase(nameWithoutVersion + PluginConstant.DOT_STRING + PluginConstant.JASPER_STRING)) {
ItemRecord itemRecord = new ItemRecord(f, record.getRootFolderPath());
itemRecords.add(itemRecord);
continue;
}
// add sub-reports jrxml and jasper when the main-report is checked on UI.
List<String> subLsFromMap = mainSubRepMap.get(nameWithoutVersion);
if (subLsFromMap != null) {
for (String name : subLsFromMap) {
if (fName.startsWith(name)) {
ItemRecord itemRecord = new ItemRecord(f, record.getRootFolderPath());
itemRecords.add(itemRecord);
}
}
}
}
}
}