/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.wizards;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
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.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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IExportWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.core.designer.util.FileUtils;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.workspace.DotProjectUtils;
import org.teiid.designer.core.workspace.ModelProject;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.core.workspace.ModelWorkspaceFilter;
import org.teiid.designer.core.workspace.ModelWorkspaceItem;
import org.teiid.designer.core.workspace.ModelWorkspaceSelections;
import org.teiid.designer.core.workspace.ModelWorkspaceView;
import org.teiid.designer.ui.PluginConstants;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.UiPlugin;
import org.teiid.designer.ui.common.InternalUiConstants;
import org.teiid.designer.ui.common.util.WidgetFactory;
import org.teiid.designer.ui.common.util.WidgetUtil;
import org.teiid.designer.ui.common.util.WizardUtil;
import org.teiid.designer.ui.common.wizard.AbstractWizard;
import org.teiid.designer.ui.common.wizard.AbstractWizardPage;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* @since 8.0
*/
public final class ExportModelerProjectSetWizard extends AbstractWizard
implements FileUtils.Constants, IExportWizard, InternalUiConstants.Widgets, PluginConstants.Images, CoreStringUtil.Constants,
UiConstants {
private static final String I18N_PREFIX = I18nUtil.getPropertyPrefix(ExportModelerProjectSetWizard.class);
private static final ImageDescriptor IMAGE = UiPlugin.getDefault().getImageDescriptor(EXPORT_PROJECT_ICON);
private static final String TITLE = getString("title"); //$NON-NLS-1$
private static final String PAGE_TITLE = getString("pageTitle"); //$NON-NLS-1$
private static final String FILE_DIALOG_TITLE = getString("fileDialogTitle"); //$NON-NLS-1$
private static final String PROJECTS_GROUP = getString("projectsGroup"); //$NON-NLS-1$
private static final String FILE_GROUP = getString("fileGroup"); //$NON-NLS-1$
private static final String FILE_LABEL = getString("fileLabel"); //$NON-NLS-1$
private static final String FILE_BUTTON = getString("browse_3"); //$NON-NLS-1$
private static final String INITIAL_MESSAGE = getString("initialMessage"); //$NON-NLS-1$
private static final String NO_SELECTIONS_MESSAGE = getString("noSelectionsMessage"); //$NON-NLS-1$
private static final String NESTED_PROJECT_MESSAGE = getString("nestedProjectMessage"); //$NON-NLS-1$
private static final String NESTED_PROJECT_ERROR = getString("nestedProjectError"); //$NON-NLS-1$
private static final String NO_FILE_MESSAGE = getString("noFileMessage"); //$NON-NLS-1$
private static final String INVALID_FILE_MESSAGE = getString("invalidFileMessage"); //$NON-NLS-1$
private static final String FILE_IMPORT_TAG = ".zip";//$NON-NLS-1$
private static final String OPTIONS_GROUP_LABEL = getString("optionsGroup.label"); //$NON-NLS-1$
private static final String CLEAR_CONNECTION_INFO_LABEL = getString("clearConnectionInfo.label"); //$NON-NLS-1$
private final static String STORE_ZIP_FILE_NAMES_ID = getString("storeZipFileNamesId");//$NON-NLS-1$
private static boolean exportLicensed = false;
private boolean projectsSelected = false;
/**
* @since 4.0
*/
private static String getString( final String id ) {
return Util.getString(I18N_PREFIX + id);
}
private ModelWorkspaceSelections selections;
private File targetZipFileName;
private IStructuredSelection selection;
private WizardPage page1;
private CheckboxTreeViewer viewer;
private Combo zipFileCombo;
private Button clearConnectionInfoCheckBox;
/**
* @since 4.0
*/
public ExportModelerProjectSetWizard() {
super(UiPlugin.getDefault(), TITLE, IMAGE);
}
/**
* @see org.eclipse.jface.wizard.IWizard#createPageControls(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPageControls( Composite pageContainer ) {
if (exportLicensed) {
super.createPageControls(pageContainer);
}
this.page1.setMessage(INITIAL_MESSAGE);
}
/**
* @see org.eclipse.jface.wizard.IWizard#performFinish()
* @since 4.0
*/
@Override
public boolean finish() {
List selectedProjects = getSelectedProjects();
if (this.targetZipFileName.exists() && !WidgetUtil.confirmOverwrite(this.targetZipFileName)) {
return false;
}
// about to invoke the operation so save our state
saveWidgetValues();
if (selectedProjects.size() > 0)
return executeExportOperation(
new ModelerProjectZipOperation(
selectedProjects,
targetZipFileName.getAbsolutePath(),
this.clearConnectionInfoCheckBox.getSelection()));
return true;
}
/**
* @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
* @since 4.0
*/
@Override
public void init( final IWorkbench workbench,
final IStructuredSelection selection ) {
this.selection = selection;
this.selections = new ModelWorkspaceSelections();
this.page1 = new AbstractWizardPage(ExportModelerProjectSetWizard.class.getSimpleName(), PAGE_TITLE) {
@Override
public void createControl( final Composite parent ) {
setControl(createPageControl(parent));
}
};
addPage(page1);
}
Composite createEmptyPageControl( final Composite parent ) {
return new Composite(parent, SWT.NONE);
}
/**
* @since 4.0
*/
Composite createPageControl( final Composite parent ) {
// Create page
final Composite pg = new Composite(parent, SWT.NONE);
pg.setLayout(new GridLayout());
// Add widgets to page
Group group = WidgetFactory.createGroup(pg, PROJECTS_GROUP, GridData.FILL_BOTH);
// Add contents to view form
this.viewer = (CheckboxTreeViewer)WidgetFactory.createTreeViewer(group, SWT.CHECK | SWT.MULTI);
viewer.addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged( CheckStateChangedEvent event ) {
validatePage();
}
});
final Tree tree = this.viewer.getTree();
tree.setLayoutData(new GridData(GridData.FILL_BOTH));
final ModelWorkspaceView view = new ModelWorkspaceView();
view.setRestrictedToModelWorkspaceItemsOnly(true);
view.getModelWorkspaceFilters().add(new ModelWorkspaceFilter() {
@Override
public boolean select( final Object parent,
final Object node ) {
if (node instanceof ModelProject && ((ModelProject)node).isOpen()) {
try {
if (!((ModelProject)node).getProject().hasNature(ModelerCore.HIDDEN_PROJECT_NATURE_ID)) {
return true;
}
} catch (CoreException e) {
Util.log(e);
}
}
return false;
}
});
this.selections.setModelWorkspaceView(view);
final ITreeContentProvider treeContentProvider = new ITreeContentProvider() {
@Override
public void dispose() {
}
@Override
public Object[] getChildren( final Object node ) {
return EMPTY_STRING_ARRAY;
}
@Override
public Object[] getElements( final Object inputElement ) {
try {
return view.getChildren(ModelerCore.getModelWorkspace());
} catch (final ModelWorkspaceException err) {
Util.log(err);
return EMPTY_STRING_ARRAY;
}
}
@Override
public Object getParent( final Object node ) {
return null;
}
@Override
public boolean hasChildren( final Object node ) {
return false;
}
@Override
public void inputChanged( final Viewer viewer,
final Object oldInput,
final Object newInput ) {
}
};
this.viewer.setContentProvider(treeContentProvider);
this.viewer.setLabelProvider(new LabelProvider() {
final WorkbenchLabelProvider workbenchProvider = new WorkbenchLabelProvider();
@Override
public Image getImage( final Object node ) {
if (node instanceof EObject) {
return ModelUtilities.getEMFLabelProvider().getImage(node);
}
return workbenchProvider.getImage(((ModelWorkspaceItem)node).getResource());
}
@Override
public String getText( final Object node ) {
if (node instanceof EObject) {
return ModelUtilities.getEMFLabelProvider().getText(node);
}
return workbenchProvider.getText(((ModelWorkspaceItem)node).getResource());
}
});
this.viewer.setInput(this);
Group optionsGroup = WidgetFactory.createGroup(pg, OPTIONS_GROUP_LABEL, GridData.FILL_HORIZONTAL);
// Add contents to view form
clearConnectionInfoCheckBox = new Button(optionsGroup,SWT.CHECK);
clearConnectionInfoCheckBox.setText(CLEAR_CONNECTION_INFO_LABEL);
final IDialogSettings settings = getDialogSettings();
group = WidgetFactory.createGroup(pg, FILE_GROUP, GridData.FILL_HORIZONTAL, 1, 3);
{
WidgetFactory.createLabel(group, FILE_LABEL);
this.zipFileCombo = WidgetFactory.createCombo(group,
SWT.NONE,
GridData.FILL_HORIZONTAL,
settings.getArray(FILE_LABEL));
this.zipFileCombo.addModifyListener(new ModifyListener() {
@Override
public void modifyText( final ModifyEvent event ) {
handleSourceFileChanged();
}
});
WidgetFactory.createButton(group, FILE_BUTTON).addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( final SelectionEvent event ) {
handleBrowseButtonSelected();
}
});
}
// Initialize widgets
if (this.selection != null) {
final Iterator iter = this.selection.iterator();
for (@SuppressWarnings("unused")
int ndx = 0; iter.hasNext(); ++ndx) {
final Object obj = iter.next();
final IPath path = (obj instanceof IResource ? ((IResource)obj).getFullPath() : view.getPath(obj));
if (path != null) {
try {
Object proj = view.findObject(path);
if (proj != null) viewer.setChecked(proj, true);
} catch (final ModelWorkspaceException err) {
Util.log(err);
WidgetUtil.showError(err);
}
}
}
}
// Initialize widgets w/ last selections made by user
restoreWidgetValues();
this.page1.setMessage(INITIAL_MESSAGE);
this.getShell().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
validatePage();
}
});
return pg;
}
/**
* @since 4.0
*/
void handleBrowseButtonSelected() {
// Display file dialog for user to choose libraries
final FileDialog dlg = new FileDialog(getShell(), SWT.SAVE | SWT.SINGLE);
dlg.setText(FILE_DIALOG_TITLE);
final String someName = dlg.open();
if (someName != null) {
this.zipFileCombo.setText(someName);
}
validatePage();
}
/**
* @since 4.0
*/
void handleSourceFileChanged() {
String someName = this.zipFileCombo.getText();
if (someName != null && someName.length() > 0) {
final char lastChr = someName.charAt(someName.length() - 1);
if (someName.indexOf(FILE_EXTENSION_SEPARATOR) < 0 && lastChr != ':' && lastChr != '\\' && lastChr != '/') {
someName += FILE_IMPORT_TAG;
}
this.targetZipFileName = new File(someName);
} else {
this.targetZipFileName = null;
}
validatePage();
}
/**
* @since 4.0
*/
void validatePage() {
if (viewer.getCheckedElements().length == 0) {
WizardUtil.setPageComplete(this.page1, NO_SELECTIONS_MESSAGE, IMessageProvider.ERROR);
projectsSelected = false;
return;
}
projectsSelected = true;
List projects = getSelectedProjects();
try {
for (int i = 0; i < projects.size(); i++) {
if (DotProjectUtils.getDotProjectCount((IContainer)projects.get(i), true, true) > 1) {
WizardUtil.setPageComplete(this.page1, NESTED_PROJECT_MESSAGE, IMessageProvider.ERROR);
return;
}
}
} catch (Exception ce) {
ce.printStackTrace();
WizardUtil.setPageComplete(this.page1, NESTED_PROJECT_ERROR, IMessageProvider.ERROR);
return;
}
if (this.targetZipFileName == null) {
WizardUtil.setPageComplete(this.page1, NO_FILE_MESSAGE, IMessageProvider.ERROR);
return;
}
if (this.targetZipFileName.isDirectory() || !FileUtils.isFilenameValid(targetZipFileName.getName())) {
WizardUtil.setPageComplete(this.page1, INVALID_FILE_MESSAGE, IMessageProvider.ERROR);
return;
}
if (this.targetZipFileName.exists()) {
WizardUtil.setPageComplete(this.page1,
WidgetUtil.getFileExistsMessage(this.targetZipFileName),
IMessageProvider.WARNING);
return;
}
WizardUtil.setPageComplete(this.page1);
}
/**
* @see org.eclipse.jface.wizard.IWizard#canFinish()
* @since 4.2
*/
@Override
public boolean canFinish() {
if (projectsSelected && page1.isPageComplete()) return true;
return false;
}
private List getSelectedProjects() {
Object[] checkedProjects = viewer.getCheckedElements();
final ArrayList objs = new ArrayList(checkedProjects.length);
for (int i = 0; i < checkedProjects.length; i++) {
ModelProject proj = (ModelProject)checkedProjects[i];
objs.add(proj.getResource());
}
if (objs.isEmpty()) return Collections.EMPTY_LIST;
return objs;
}
/**
* Export the passed resource and recursively export all of its child resources (iff it's a container). Answer a boolean
* indicating success.
*
* @return boolean
*/
protected boolean executeExportOperation( ModelerProjectZipOperation op ) {
op.setCreateLeadupStructure(true);
op.setUseCompression(true);
try {
getContainer().run(true, true, op);
} catch (InterruptedException e) {
return false;
} catch (InvocationTargetException e) {
String message = e.getTargetException().getMessage();
if (message == null || message.length() == 0) {
message = getString("exportProblemsMessage"); //$NON-NLS-1$
}
ErrorDialog.openError(getContainer().getShell(), getString("exportProblemsTitle"), //$NON-NLS-1$
message,
op.getStatus());
Util.log(e.getTargetException());
return false;
}
IStatus status = op.getStatus();
if (!status.isOK()) {
ErrorDialog.openError(getContainer().getShell(), getString("exportProblemsTitle"), //$NON-NLS-1$
null,
status);
Util.log(status);
return false;
}
return true;
}
/**
* Sets the source name of the import to be the supplied path. Adds the name of the path to the list of items in the source
* combo and selects it.
*
* @param path the path to be added
*/
protected void setZipFileName( String path ) {
if (path.length() > 0) {
String[] currentItems = this.zipFileCombo.getItems();
int selectionIndex = -1;
for (int i = 0; i < currentItems.length; i++) {
if (currentItems[i].equals(path)) selectionIndex = i;
}
if (selectionIndex < 0) {
int oldLength = currentItems.length;
String[] newItems = new String[oldLength + 1];
System.arraycopy(currentItems, 0, newItems, 0, oldLength);
newItems[oldLength] = path;
this.zipFileCombo.setItems(newItems);
selectionIndex = oldLength;
}
this.zipFileCombo.select(selectionIndex);
}
}
/**
* Use the dialog store to restore widget values to the values that they held last time this wizard was used to completion
*/
protected void restoreWidgetValues() {
IDialogSettings settings = getDialogSettings();
WidgetUtil.removeMissingResources(settings, STORE_ZIP_FILE_NAMES_ID);
if (settings != null) {
String[] sourceNames = settings.getArray(STORE_ZIP_FILE_NAMES_ID);
if (sourceNames == null) return; // ie.- no values stored, so stop
// set filenames history
for (int i = 0; i < sourceNames.length; i++)
zipFileCombo.add(sourceNames[i]);
zipFileCombo.select(0);
}
}
/**
* Since Finish was pressed, write widget values to the dialog store so that they will persist into the next invocation of
* this wizard page
*/
protected void saveWidgetValues() {
IDialogSettings settings = getDialogSettings();
if (settings != null) {
// update source names history
String[] sourceNames = settings.getArray(STORE_ZIP_FILE_NAMES_ID);
if (sourceNames == null) sourceNames = new String[0];
sourceNames = getLastTwentyComboNames(sourceNames);
settings.put(STORE_ZIP_FILE_NAMES_ID, sourceNames);
}
}
private String[] getLastTwentyComboNames( String[] currentArray ) {
int nValues = currentArray.length;
// Let's walk through the list and remove duplicates
Collection nonDuplicates = new ArrayList(nValues);
String currentZipName = zipFileCombo.getText();
if (currentZipName == null) return currentArray;
for (int i = 0; i < nValues; i++) {
if (!currentArray[i].equals(currentZipName)) nonDuplicates.add(currentArray[i]);
}
Object[] newArray = nonDuplicates.toArray();
int newArrayLength = newArray.length + 1;
String[] newStrings = new String[newArrayLength];
newStrings[0] = currentZipName;
for (int i = 0; i < newArray.length; i++) {
if (i > 18) break;
newStrings[i + 1] = (String)newArray[i];
}
return newStrings;
}
}