/*******************************************************************************
* Copyright (c) 2016 Red Hat.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat - Initial Contribution
*******************************************************************************/
package org.eclipse.linuxtools.internal.docker.ui.wizards;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.linuxtools.docker.ui.Activator;
import org.eclipse.linuxtools.internal.docker.core.ContainerFileProxy;
import org.eclipse.linuxtools.internal.docker.ui.CheckboxTreeAndListGroup;
import org.eclipse.linuxtools.internal.docker.ui.MinimizedFileSystemElement;
import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory;
import org.eclipse.swt.SWT;
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.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.FileSystemElement;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.model.WorkbenchViewerComparator;
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
/**
* A standard file selection dialog which solicits a list of files from the user.
* The <code>getResult</code> method returns the selected files.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
* <p>
* Example:
* <pre>
* FileSelectionDialog dialog =
* new FileSelectionDialog(getShell(), rootElement, msg);
* dialog.setInitialSelections(selectedResources);
* dialog.open();
* return dialog.getResult();
* </pre>
* </p>
* @noextend This class is not intended to be subclassed by clients.
*/
public class ContainerCopyFromPage extends WizardPage {
private final static String NAME = "ContainerCopyFrom.name"; //$NON-NLS-1$
private final static String TITLE = "ContainerCopyFrom.title"; //$NON-NLS-1$
private final static String DESC = "ContainerCopyFrom.desc"; //$NON-NLS-1$
private static final String TARGET_LABEL = "ContainerCopyFrom.target.label"; //$NON-NLS-1$
private static final String TARGET_TOOLTIP = "ContainerCopyFrom.target.tooltip"; //$NON-NLS-1$
private static final String SOURCE_LABEL = "ContainerCopyFrom.source.label"; //$NON-NLS-1$
private static final String SOURCE_TOOLTIP = "ContainerCopyFrom.source.tooltip"; //$NON-NLS-1$
private static final String NO_TARGET_SPECIFIED = "ContainerCopyFrom.notarget.error"; //$NON-NLS-1$
private static final String NO_SOURCE_SPECIFIED = "ContainerCopyFrom.nosource.error"; //$NON-NLS-1$
private static final String BROWSE_LABEL = "ContainerCopyFrom.browse.label"; //$NON-NLS-1$
// the root file representative to populate the viewer with
private FileSystemElement root;
private IImportStructureProvider structureProvider;
private boolean canBrowseContainer;
// the visual selection widget group
CheckboxTreeAndListGroup selectionGroup;
private Text targetText;
private Text sourceText;
private Button browseButton;
private String target;
// sizing constants
private static final int SIZING_SELECTION_WIDGET_WIDTH = 500;
private static final int SIZING_SELECTION_WIDGET_HEIGHT = 250;
private static final int COLUMNS = 3;
/**
* Wizard page for copying files from container
*
* @param fileSystemElement
* - FileSystemElement of root
* @param structureProvider
* - IImportStructureProvider to get file system structure from
* container
* @param containerName
* - name of container
* @param canBrowseContainer
* - whether we can browse the Container's file system
*/
public ContainerCopyFromPage(FileSystemElement fileSystemElement,
IImportStructureProvider structureProvider, String containerName,
boolean canBrowseContainer) {
super(WizardMessages.getString(NAME));
setDescription(WizardMessages.getFormattedString(DESC,
containerName));
setTitle(WizardMessages.getString(TITLE));
setImageDescriptor(SWTImagesFactory.DESC_WIZARD);
root = fileSystemElement;
this.structureProvider = structureProvider;
this.canBrowseContainer = canBrowseContainer;
}
/*
* Return the host directory for the copy operation
*/
public String getTarget() {
return target;
}
/*
* Get an iterator for the selected items to copy
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Iterator getValueIterator() {
if (canBrowseContainer) {
return selectionGroup.getAllWhiteCheckedItems();
} else {
// We need to fake a collection of MinimizedFileSystemElement with
// one element.
ArrayList out = new ArrayList();
String sourceName = sourceText.getText();
MinimizedFileSystemElement element = new MinimizedFileSystemElement(
sourceName, null, false);
element.setFileSystemObject(
new ContainerFileProxy(sourceName, "", false)); //$NON-NLS-1$
out.add(element);
return out.iterator();
}
}
private ModifyListener Listener = e -> validate();
private ICheckStateListener CheckListener = e -> validate();
private void validate() {
boolean complete = true;
boolean error = false;
if (targetText.getText().length() == 0) {
error = true;
setErrorMessage(WizardMessages.getString(NO_TARGET_SPECIFIED));
} else {
File f = new File(targetText.getText());
if (!f.exists()) {
error = true;
setErrorMessage(WizardMessages.getString(NO_TARGET_SPECIFIED));
}
}
if (!error) {
if (canBrowseContainer) {
if (selectionGroup.getCheckedElementCount() == 0) {
error = true;
setErrorMessage(
WizardMessages.getString(NO_SOURCE_SPECIFIED));
}
} else {
if (sourceText.getText().length() == 0) {
error = true;
setErrorMessage(
WizardMessages.getString(NO_SOURCE_SPECIFIED));
}
}
}
if (!error) {
target = targetText.getText();
setErrorMessage(null);
}
setPageComplete(complete && !error);
}
@Override
public void createControl(Composite parent) {
// page group
Composite composite = new Composite(parent, SWT.NULL);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1)
.grab(true, false).applyTo(composite);
GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6)
.applyTo(composite);
Label targetLabel = new Label(composite, SWT.NULL);
targetLabel.setText(WizardMessages.getString(TARGET_LABEL));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1)
.grab(false, false).applyTo(targetLabel);
targetText = new Text(composite, SWT.BORDER | SWT.SINGLE);
targetText.addModifyListener(Listener);
targetText.setToolTipText(WizardMessages.getString(TARGET_TOOLTIP));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1)
.grab(true, false).applyTo(targetText);
browseButton = new Button(composite, SWT.NONE);
browseButton.setText(WizardMessages.getString(BROWSE_LABEL));
browseButton.addSelectionListener(onBrowseSelect());
GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).span(1, 1)
.grab(false, false).applyTo(browseButton);
// Create a fake parent of the root to be the dialog input element.
// Use an empty label so that display of the element's full name
// doesn't include a confusing label
FileSystemElement input = new FileSystemElement("", null, true);//$NON-NLS-1$
input.addChild(root);
root.setParent(input);
Composite selectionComposite = null;
if (canBrowseContainer) {
selectionComposite = new Composite(composite, SWT.NULL);
GridLayout selectionLayout = new GridLayout();
selectionComposite.setLayout(selectionLayout);
selectionGroup = new CheckboxTreeAndListGroup(selectionComposite,
input, getFolderProvider(), getDynamicFolderProvider(),
new WorkbenchLabelProvider(), getFileProvider(),
new WorkbenchLabelProvider(), SWT.NONE,
SIZING_SELECTION_WIDGET_WIDTH, // since this page has no
// other significantly-sized
SIZING_SELECTION_WIDGET_HEIGHT); // widgets we need to
// hardcode the combined
// widget's
// size, otherwise it will open too small
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(3, 1)
.grab(true, false).applyTo(selectionComposite);
} else {
Label sourceLabel = new Label(composite, SWT.NONE);
sourceLabel.setText(WizardMessages.getString(SOURCE_LABEL));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.span(1, 1).grab(false, false).applyTo(sourceLabel);
sourceText = new Text(composite, SWT.BORDER | SWT.SINGLE);
sourceText.addModifyListener(Listener);
sourceText.setToolTipText(WizardMessages.getString(SOURCE_TOOLTIP));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1)
.grab(true, false).applyTo(sourceText);
}
if (canBrowseContainer) {
WorkbenchViewerComparator comparator = new WorkbenchViewerComparator();
selectionGroup.setTreeComparator(comparator);
selectionGroup.setListComparator(comparator);
selectionGroup.addCheckStateListener(CheckListener);
}
setControl(composite);
validate();
setPageComplete(false);
if (canBrowseContainer) {
selectionGroup.aboutToOpen();
}
}
private SelectionListener onBrowseSelect() {
final ContainerCopyFromPage page = this;
return new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
DirectoryDialog d = new DirectoryDialog(
Activator.getActiveWorkbenchShell());
String x = d.open();
if (x != null) {
page.targetText.setText(x);
}
}
};
}
/**
* Returns a content provider for <code>FileSystemElement</code>s that returns
* only files as children.
*/
private ITreeContentProvider getFileProvider() {
return new WorkbenchContentProvider() {
@Override
public Object[] getChildren(Object o) {
if (o instanceof FileSystemElement) {
return ((FileSystemElement) o).getFiles().getChildren(o);
}
return new Object[0];
}
};
}
/**
* Returns a content provider for <code>FileSystemElement</code>s that returns
* only folders as children.
*/
private ITreeContentProvider getFolderProvider() {
return new WorkbenchContentProvider() {
@Override
public Object[] getChildren(Object o) {
if (o instanceof FileSystemElement) {
return ((FileSystemElement) o).getFolders().getChildren(o);
}
return new Object[0];
}
};
}
/**
* Returns a content provider for <code>FileSystemElement</code>s that
* returns only folders as children.
*/
private ITreeContentProvider getDynamicFolderProvider() {
return new WorkbenchContentProvider() {
@Override
public Object[] getChildren(Object o) {
if (o instanceof MinimizedFileSystemElement) {
return ((MinimizedFileSystemElement) o)
.getFolders(structureProvider)
.getChildren(o);
} else if (o instanceof FileSystemElement) {
return ((FileSystemElement) o).getFolders().getChildren(o);
}
return new Object[0];
}
};
}
}