// ============================================================================
//
// 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.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
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.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.Text;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
import org.talend.commons.emf.FactoriesUtil;
import org.talend.commons.utils.WorkspaceUtils;
import org.talend.core.model.properties.Project;
import org.talend.cwm.helper.ResourceHelper;
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.ExportWriterFactory;
import org.talend.dataprofiler.core.ui.imex.model.IExportWriter;
import org.talend.dataprofiler.core.ui.imex.model.ItemRecord;
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 org.talend.dq.helper.resourcehelper.IndicatorResourceFileHelper;
import org.talend.dq.indicators.definitions.DefinitionHandler;
import org.talend.repository.ProjectManager;
import org.talend.resource.ResourceManager;
import orgomg.cwm.objectmodel.core.ModelElement;
/**
* This class defines the UI for the export feature in TOP and TQ for the Data profile perspective.
*/
public class ExportWizardPage extends WizardPage {
private static final String SHOW_ONLY_SELECTED = Messages.getString("ExportWizardPage.9"); //$NON-NLS-1$
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 INCLUDE_DEPENDANCY = Messages.getString("ExportWizardPage.12"); //$NON-NLS-1$
private static final String DESELECT_ALL = Messages.getString("ExportWizardPage.11"); //$NON-NLS-1$
private static final String SELECT_ALL = Messages.getString("ExportWizardPage.10"); //$NON-NLS-1$
private static Logger log = Logger.getLogger(ExportWizardPage.class);
private CheckboxTreeViewer repositoryTree;
protected Button dirBTN, archBTN;
private Button browseDirBTN, browseArchBTN;
private Text dirTxt, archTxt;
protected Button selectAllBTN, deselectAllBTN, addRequireBTN;
private IPath specifiedPath;
protected IExportWriter writer;
public static final String[] FILE_EXPORT_MASK = { "*.zip;*.tar;*.tar.gz", "*.*" }; //$NON-NLS-1$//$NON-NLS-2$
private final ViewerFilter treeFilter = new TreeFilter();
private final String underlineStr = "_";//$NON-NLS-1$
private final String subrepName = "subreports";//$NON-NLS-1$
public ExportWizardPage(String specifiedPath) {
super(Messages.getString("ExportWizardPage.2")); //$NON-NLS-1$
setMessage(Messages.getString("ExportWizardPage.3")); //$NON-NLS-1$
this.specifiedPath = specifiedPath == null ? null : new Path(specifiedPath);
this.writer = ExportWriterFactory.create(EImexType.FILE);
}
/*
* (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);
initControlState();
addListeners();
setControl(top);
}
/**
* DOC bZhou Comment method "initControlState".
*/
protected void initControlState() {
setArchState(false);
setPageComplete(false);
}
/**
* DOC bZhou Comment method "setDirState".
*
* @param state
*/
protected void setDirState(boolean state) {
dirTxt.setEnabled(state);
browseDirBTN.setEnabled(state);
if (state) {
writer = ExportWriterFactory.create(EImexType.FILE);
updateBasePath();
}
}
/**
* DOC zshen Comment method "updateBasePath".
*/
public String updateBasePath() {
String basePath;
if (isDirState()) {
basePath = getTextContent(dirTxt);
} else {
basePath = getTextContent(archTxt);
}
textModified(basePath);
return basePath;
}
/**
* DOC zshen Comment method "getTextContent".
*
* @param archTxt2
* @return
*/
protected String getTextContent(Text archTxt2) {
if (archTxt2 == null) {
return PluginConstant.EMPTY_STRING;
}
return archTxt2.getText();
}
/**
* 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 = ExportWriterFactory.create(EImexType.ZIP_FILE);
updateBasePath();
}
}
/**
* DOC bZhou Comment method "isArchState".
*
* @return
*/
public boolean isArchState() {
return archBTN.getSelection();
}
/**
* 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) {
IPath path = new Path(result);
if (StringUtils.isBlank(path.getFileExtension())) {
path = path.addFileExtension("zip");//$NON-NLS-1$
}
archTxt.setText(path.toOSString());
}
}
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();
}
});
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()) {
// ADD msjian TDQ-12245: for the reference project file which is depended on by the main items, we
// ignore it(means not export it).
if (!DqFileUtils.isLocalProjectFile(file)) {
continue;
}
// TDQ-12245~
ItemRecord findRecord = ItemRecord.findRecord(file);
if (findRecord != null) {
repositoryTree.setChecked(findRecord, checked);
} else {
log.error("Can't find the file: " + file.getAbsolutePath());//$NON-NLS-1$
}
}
} else {
ModelElement element = record.getElement();
if (element != null) {
List<ModelElement> dependencyClients = EObjectHelper.getDependencyClients(element);
ImportAndExportUtils.iterateUncheckClientDependency(dependencyClients, repositoryTree);
}
}
}
repositoryTree.refresh();
checkForErrors();
}
});
}
/**
* DOC bZhou Comment method "textModified".
*
* @param pathStr
*/
public void textModified(String pathStr) {
writer.setBasePath(new Path(pathStr));
checkForErrors();
}
/**
* this check that the folder entered in the target export location exist otherwhise set an erro message and disable
* export.
*/
protected void checkForErrors() {
List<String> errors = new ArrayList<String>();
errors.addAll(writer.check());
ItemRecord[] elements = getElements();
for (ItemRecord record : elements) {
errors.addAll(record.getErrors());
for (File depFile : record.getDependencySet()) {
// ADD msjian TDQ-12245: for the reference project file which is depended on by the main items, we
// ignore it(means not export it).
if (!DqFileUtils.isLocalProjectFile(depFile)) {
continue;
}
// TDQ-12245~
ItemRecord findRecord = ItemRecord.findRecord(depFile);
if (findRecord == null || !repositoryTree.getChecked(findRecord)) {
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~
errors.add("\"" + record.getName() + "\" miss dependency : " + dptLabel);//$NON-NLS-1$ //$NON-NLS-2$
}
}
}
if (!errors.isEmpty()) {
setErrorMessage(errors.get(0));
} else {
setErrorMessage(null);
}
updatePageStatus();
}
/**
* update the page state that is the finish button enable state according to the error message being present or not
* and user select at least one item to export.
*/
protected void updatePageStatus() {
setPageComplete(getErrorMessage() == null && getElements().length > 0);
}
/**
* DOC bZhou Comment method "createRepositoryTree".
*
* @param top
*/
protected void createRepositoryTree(Composite top) {
Composite treeComposite = new Composite(top, SWT.NONE);
treeComposite.setLayout(new GridLayout(2, false));
treeComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
repositoryTree = new ContainerCheckedTreeViewer(treeComposite);
repositoryTree.setContentProvider(new FileTreeContentProvider());
repositoryTree.setLabelProvider(new FileTreeLabelProvider());
repositoryTree.setInput(writer.computeInput(specifiedPath));
repositoryTree.expandAll();
repositoryTree.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
createUtilityButtons(treeComposite);
}
/**
* DOC bZhou Comment method "createUtilityButtons".
*
* @param treeComposite
*/
protected void createUtilityButtons(Composite treeComposite) {
Composite utilityComposite = new Composite(treeComposite, SWT.NONE);
utilityComposite.setLayout(new GridLayout());
utilityComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL));
Composite btnsComposite = new Composite(utilityComposite, SWT.NONE);
btnsComposite.setLayout(new GridLayout());
GridData gd = new GridData();
gd.verticalAlignment = SWT.BEGINNING;
gd.horizontalIndent = 0;
gd.horizontalSpan = 0;
btnsComposite.setLayoutData(gd);
selectAllBTN = new Button(btnsComposite, SWT.PUSH);
selectAllBTN.setText(SELECT_ALL);
selectAllBTN.setToolTipText(SELECT_ALL);
deselectAllBTN = new Button(btnsComposite, SWT.PUSH);
deselectAllBTN.setText(DESELECT_ALL);
deselectAllBTN.setToolTipText(DESELECT_ALL);
addRequireBTN = new Button(btnsComposite, SWT.PUSH);
addRequireBTN.setText(INCLUDE_DEPENDANCY);
addRequireBTN.setToolTipText(INCLUDE_DEPENDANCY);
Composite infoComposite = new Composite(utilityComposite, SWT.NONE);
infoComposite.setLayout(new GridLayout());
gd = new GridData(GridData.FILL_BOTH);
gd.verticalAlignment = SWT.BOTTOM;
gd.horizontalIndent = 0;
gd.horizontalSpan = 0;
infoComposite.setLayoutData(gd);
final Button showSelectBTN = new Button(infoComposite, SWT.CHECK);
showSelectBTN.setText(SHOW_ONLY_SELECTED);
showSelectBTN.setToolTipText(SHOW_ONLY_SELECTED);
Button[] utilityBTNs = new Button[] { selectAllBTN, deselectAllBTN, addRequireBTN };
for (Button btn : utilityBTNs) {
gd = new GridData();
gd.widthHint = 170;
gd.verticalIndent = 0;
gd.horizontalIndent = 0;
btn.setLayoutData(gd);
}
selectAllBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
TreeItem[] topItems = repositoryTree.getTree().getItems();
for (TreeItem treeItem : topItems) {
repositoryTree.setSubtreeChecked(treeItem.getData(), true);
}
repositoryTree.refresh();
updatePageStatus();
}
});
deselectAllBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
TreeItem[] topItems = repositoryTree.getTree().getItems();
for (TreeItem treeItem : topItems) {
repositoryTree.setSubtreeChecked(treeItem.getData(), false);
}
repositoryTree.refresh();
updatePageStatus();
}
});
addRequireBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (showSelectBTN.getSelection()) {
filterUncheckedItems(false);
}
ItemRecord[] records = getElements();
for (ItemRecord record : records) {
for (File depFile : record.getDependencySet()) {
// ADD msjian TDQ-12245: for the reference project file which is depended on by the main items, we
// ignore it(means not export it).
if (!DqFileUtils.isLocalProjectFile(depFile)) {
continue;
}
// TDQ-12245~
ItemRecord depRecord = ItemRecord.findRecord(depFile);
if (!repositoryTree.getChecked(depRecord)) {
repositoryTree.setChecked(depRecord, true);
}
}
}
if (showSelectBTN.getSelection()) {
filterUncheckedItems(true);
}
checkForErrors();
}
});
showSelectBTN.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
filterUncheckedItems(showSelectBTN.getSelection());
}
});
}
private void filterUncheckedItems(boolean isFiltered) {
if (isFiltered) {
repositoryTree.addFilter(treeFilter);
} else {
ItemRecord[] elements = getElements();
repositoryTree.removeFilter(treeFilter);
repositoryTree.expandAll();
repositoryTree.setCheckedElements(elements);
}
}
/**
* DOC bZhou Comment method "createSelectComposite".
*
* @param top
*/
protected 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>();
boolean sumIndicatorAdded = false;
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, add it's dependency Sum Indicator
if (!sumIndicatorAdded) {
String meanIndicatorUuid = "_ccI48RF2Ed2PKb6nEJEvhw"; //$NON-NLS-1$
String sumIndicatorLabel = "Sum"; //$NON-NLS-1$
ModelElement element = record.getElement();
if (element != null && element instanceof IndicatorDefinition
&& meanIndicatorUuid.equals(ResourceHelper.getUUID(element))) {
IndicatorDefinition sumIndicator = DefinitionHandler.getInstance().getIndicatorDefinition(
sumIndicatorLabel);
if (sumIndicator != null) {
IFile sumIndicatorIFile = IndicatorResourceFileHelper.findCorrespondingFile(sumIndicator);
if (sumIndicatorIFile != null) {
File sumIndicatorFile = WorkspaceUtils.ifileToFile(sumIndicatorIFile);
if (sumIndicatorFile != null) {
itemRecords.add(new ItemRecord(sumIndicatorFile));
sumIndicatorAdded = true;
}
}
}
}
}
}
}
}
return itemRecords.toArray(new ItemRecord[itemRecords.size()]);
}
/**
* Getter for writer.
*
* @return the writer
*/
public IExportWriter getWriter() {
return this.writer;
}
/**
* DOC bZhou ExportWizardPage class global comment. Detailled comment
*/
class TreeFilter extends ViewerFilter {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object,
* java.lang.Object)
*/
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
ItemRecord record = (ItemRecord) element;
return repositoryTree.getChecked(record);
}
}
/**
*
* 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);
IFile iFile = ResourceManager.getJRXMLFolder().getFile(subrepName);
File subRepFolder = WorkspaceUtils.ifileToFile(iFile);
if (subRepFolder == null || !subRepFolder.exists()) {
return;
}
Map<String, List<String>> mainSubRepMap = ReportFileHelper.getMainSubRepMap();
String fName;
for (File f : subRepFolder.listFiles()) {
fName = f.getName();
if (fName.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);
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);
itemRecords.add(itemRecord);
}
}
}
}
}
/**
*
* check if the output path is correct.
*
* @return
*/
public boolean canFinish() {
String lastPath = writer.getBasePath().toString();
if (lastPath == null || PluginConstant.EMPTY_STRING.equals(lastPath)) {
MessageDialog.openError(getShell(), "Error", Messages.getString("ExportWizardPage.emptyPath"));//$NON-NLS-1$//$NON-NLS-2$
return false;
}
ProjectManager pManager = ProjectManager.getInstance();
Project project = pManager.getCurrentProject().getEmfProject();
File outputDir = new File(lastPath + File.separator + project.getTechnicalLabel()); //$NON-NLS-1$
// if the file exists,pop an dialog to ask that it will override the old file.
if ((dirBTN.getSelection() && outputDir.exists())
|| (archBTN.getSelection() && new File(archTxt.getText().trim()).exists())) {
File oldFile = outputDir.exists() ? outputDir : new File(archTxt.getText().trim());
if (MessageDialogWithToggle.openConfirm(null,
Messages.getString("ExportWizard.waring"), Messages.getString("ExportWizard.fileAlreadyExist"))) { //$NON-NLS-1$ //$NON-NLS-2$
FileUtils.deleteQuietly(oldFile);
} else {
return false;
}
}
return true;
}
}