/**
* Copyright 2010 The University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package unc.lib.cdr.workbench.capture;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
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.ViewerComparator;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
import org.osgi.service.prefs.BackingStoreException;
import unc.lib.cdr.workbench.originals.OriginalFileStore;
import unc.lib.cdr.workbench.originals.OriginalStub;
import unc.lib.cdr.workbench.rcp.Activator;
/**
* @author Gregory Jansen
*
*/
public class PickOriginalLocationsPage extends WizardPage implements Listener {
// constants
private static final int SIZING_TEXT_FIELD_WIDTH = 250;
private static final String PRESTAGE_PREFERENCE_NODE_ID = "prestage_locations";
IStructuredSelection selection;
// properties
private URI location = null;
// A boolean to indicate if the user has typed anything
private boolean locationChanged = false;
// private boolean prestagedChanged = false;
// widgets
private Combo locationField;
private Button drivesBrowseButton;
private Button removeableButton;
private Combo projectCombo;
private CheckboxTreeViewer fileTreeViewer;
private FileStoreProvider provider = new FileStoreProvider();
private IProject project;
// private String prestagedLocation;
private String[] previousPrestages;
/**
* @param pageName
*/
public PickOriginalLocationsPage(String pageName,
IStructuredSelection selection) {
super(pageName);
this.selection = selection;
setTitle("Import Originals");
setDescription("Select original folders or files to include in your project.");
loadPreviousPrestages();
}
/**
*
*/
private void loadPreviousPrestages() {
org.osgi.service.prefs.Preferences preferences = new ConfigurationScope()
.getNode(Activator.PLUGIN_ID).node(PRESTAGE_PREFERENCE_NODE_ID);
String[] keys = new String[] {};
try {
keys = preferences.childrenNames();
} catch (BackingStoreException e) {
e.printStackTrace();
}
final HashMap<String, Integer> counts = new HashMap<String, Integer>();
for (String k : keys) {
int c = preferences.node(k).getInt("count", 0);
String uri = preferences.node(k).get("uri", "default");
counts.put(uri, Integer.valueOf(c));
}
List<String> list = new ArrayList(counts.keySet());
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String arg0, String arg1) {
return counts.get(arg0) - counts.get(arg1);
}
});
this.previousPrestages = list.toArray(new String[keys.length]);
}
private void saveToPreviousPrestages(String uri) {
String loc = Integer.toString(uri.hashCode());
org.osgi.service.prefs.Preferences allLocations = new ConfigurationScope()
.getNode(Activator.PLUGIN_ID).node(PRESTAGE_PREFERENCE_NODE_ID);
int c = 1;
try {
if (allLocations.nodeExists(loc)) {
c = c + allLocations.node(loc).getInt("count", 1);
}
} catch (BackingStoreException e1) {
e1.printStackTrace();
}
allLocations.node(loc).putInt("count", c);
allLocations.node(loc).put("uri", uri);
try {
allLocations.flush();
} catch (BackingStoreException e) {
e.printStackTrace();
}
}
/**
* @return
*/
private String checkValidLocation() {
// TODO validate it
if (this.location != null) {
return null;
} else {
return "You have not selected a valid location";
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets
* .Composite)
*/
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NULL);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
| GridData.HORIZONTAL_ALIGN_FILL));
composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
composite.setFont(parent.getFont());
createRootDirectoryGroup(composite);
createFileSelectionGroup(composite);
createRemoveableGroup(composite);
createDestinationGroup(composite);
updateWidgets();
setPageComplete(determinePageCompletion());
setErrorMessage(null); // should not initially have error message
composite.pack();
setControl(composite);
}
private void createRemoveableGroup(Composite composite) {
Group optionsGroup = new Group(composite, SWT.NONE);
// optionsGroup.setText("Pre-Staged Location");
GridLayout layout = new GridLayout();
layout.numColumns = 2;
optionsGroup.setLayout(layout);
optionsGroup.setFont(composite.getFont());
optionsGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.GRAB_HORIZONTAL));
Label lab = new Label(optionsGroup, SWT.WRAP);
GridData labdata = new GridData();
// labdata.verticalSpan = 2;
labdata.horizontalAlignment = GridData.FILL;
labdata.horizontalSpan = 1;
lab.setLayoutData(labdata);
lab.setText("Removeable media, such as optical discs and flash drives, are not always reachable.");
this.removeableButton = new Button(optionsGroup, SWT.CHECK);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
data.horizontalSpan = 3;
this.removeableButton.setLayoutData(data);
this.removeableButton.setText("This is removeable media.");
}
/**
* @param parent
*/
private void createFileSelectionGroup(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
composite.setLayout(layout);
composite.setFont(parent.getFont());
composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL));
// Create the tree viewer to display the file tree
fileTreeViewer = new CheckboxTreeViewer(composite);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 200;
fileTreeViewer.getTree().setLayoutData(gd);
fileTreeViewer.setContentProvider(provider);
fileTreeViewer.setLabelProvider(provider);
fileTreeViewer.setAutoExpandLevel(2);
fileTreeViewer.setInput(FileStoreProvider.EMPTY_ROOT); // pass a
// non-null that
// will be
// ignored
fileTreeViewer.setComparator(new ViewerComparator() {
@Override
public int category(Object element) {
if (IFileStore.class.isInstance(element)) {
IFileStore fs = (IFileStore) element;
if (fs.fetchInfo().isDirectory()) {
return 0;
} else {
return 1;
}
}
return super.category(element);
}
});
// When user checks a checkbox in the tree, check all its children
fileTreeViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
// If the item is checked . . .
if (event.getChecked()) {
// uncheck all its parents and all descendants
IFileStore f = (IFileStore) event.getElement();
IPath fpath = new Path(f.toURI().getPath());
for (Object checkedThing : fileTreeViewer
.getCheckedElements()) {
IFileStore thing = (IFileStore) checkedThing;
IPath path = new Path(thing.toURI().getPath());
if (fpath.equals(path)) {
continue;
} else if (fpath.isPrefixOf(path)) {
fileTreeViewer.setChecked(checkedThing, false);
} else if (path.isPrefixOf(fpath)) {
fileTreeViewer.setChecked(checkedThing, false);
}
}
}
}
});
}
/**
* Creates the import destination specification controls.
*
* @param parent
* the parent control
*/
protected final void createDestinationGroup(Composite parent) {
// container specification group
Composite containerGroup = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
containerGroup.setLayout(layout);
containerGroup.setLayoutData(new GridData(
GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
containerGroup.setFont(parent.getFont());
// container label
Label resourcesLabel = new Label(containerGroup, SWT.NONE);
resourcesLabel.setText("Into Project");
resourcesLabel.setFont(parent.getFont());
// container name entry field
projectCombo = new Combo(containerGroup, SWT.SINGLE | SWT.BORDER
| SWT.READ_ONLY);
projectCombo.addListener(SWT.Selection, this);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.GRAB_HORIZONTAL);
data.widthHint = SIZING_TEXT_FIELD_WIDTH;
projectCombo.setLayoutData(data);
projectCombo.setFont(parent.getFont());
initialPopulateProjectField();
}
/**
* Create the group for creating the root directory
*/
protected void createRootDirectoryGroup(Composite parent) {
Composite sourceContainerGroup = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
sourceContainerGroup.setLayout(layout);
sourceContainerGroup.setFont(parent.getFont());
sourceContainerGroup.setLayoutData(new GridData(
GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
Label groupLabel = new Label(sourceContainerGroup, SWT.NONE);
groupLabel.setText("Location");
groupLabel.setFont(parent.getFont());
Label spacerLabel = new Label(sourceContainerGroup, SWT.NONE);
spacerLabel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
spacerLabel.setText("");
// source browse button
drivesBrowseButton = new Button(sourceContainerGroup, SWT.PUSH);
drivesBrowseButton.setText("Browse Drives..");
drivesBrowseButton.addListener(SWT.Selection, this);
drivesBrowseButton.setLayoutData(new GridData(
GridData.HORIZONTAL_ALIGN_FILL));
drivesBrowseButton.setFont(parent.getFont());
setButtonLayoutData(drivesBrowseButton);
// source name entry field
locationField = new Combo(sourceContainerGroup, SWT.BORDER);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.GRAB_HORIZONTAL);
data.widthHint = SIZING_TEXT_FIELD_WIDTH;
data.horizontalSpan = 4;
locationField.setLayoutData(data);
locationField.setFont(parent.getFont());
locationField.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateFromLocationField();
}
});
locationField.addKeyListener(new KeyListener() {
/*
* @see KeyListener.keyPressed
*/
public void keyPressed(KeyEvent e) {
// If there has been a key pressed then mark as dirty
locationChanged = true;
if (e.character == SWT.CR) {
locationChanged = false;
updateFromLocationField();
}
}
/*
* @see KeyListener.keyReleased
*/
public void keyReleased(KeyEvent e) {
}
});
locationField.addFocusListener(new FocusListener() {
/*
* @see FocusListener.focusGained(FocusEvent)
*/
public void focusGained(FocusEvent e) {
// Do nothing when getting focus
}
/*
* @see FocusListener.focusLost(FocusEvent)
*/
public void focusLost(FocusEvent e) {
// Clear the flag to prevent constant update
if (locationChanged) {
locationChanged = false;
updateFromLocationField();
}
}
});
}
/**
* @return
*/
private boolean determinePageCompletion() {
String validLocationMessage = checkValidLocation();
if (validLocationMessage != null) {
setErrorMessage(validLocationMessage);
return false;
}
if (this.fileTreeViewer.getCheckedElements().length < 1) {
setErrorMessage("Please select originals to link in the folder tree.");
return false;
}
setErrorMessage(null);
setMessage(null);
return true;
}
public URI getSourceLocation() {
return location;
}
/**
*
*/
protected void handleDrivesBrowseButtonPressed() {
DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.SHEET);
dialog.setMessage("Select the location");
String locationstr = dialog.open();
if (locationstr != null && locationstr.trim().length() > 0) {
File f = new File(locationstr);
this.location = f.toURI();
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.
* Event)
*/
@Override
public void handleEvent(Event event) {
Widget source = event.widget;
if (source == this.drivesBrowseButton) {
handleDrivesBrowseButtonPressed();
updateWidgets();
selectFirstCheckbox();
setMessage(null);
setPageComplete(true);
}
}
private void selectFirstCheckbox() {
if (this.fileTreeViewer.getInput() != null) {
FileStoreProvider.Root root = (FileStoreProvider.Root) this.fileTreeViewer
.getInput();
if (root.roots != null && root.roots.length > 0) {
this.fileTreeViewer.setChecked(root.roots[0], true);
// this.fileTreeViewer.setSelection(new TreeSelection(new
// TreePath(new Object[] {root, root.roots[0]})));
}
}
}
/**
*
*/
private IProject getProject() {
String pname = this.projectCombo.getItems()[this.projectCombo
.getSelectionIndex()];
return ResourcesPlugin.getWorkspace().getRoot().getProject(pname);
}
/**
*
*/
private void initialPopulateProjectField() {
java.util.List<String> openProjects = new ArrayList<String>();
for (IProject p : ResourcesPlugin.getWorkspace().getRoot()
.getProjects()) {
if (p.isOpen())
openProjects.add(p.getName());
}
projectCombo.setItems(openProjects.toArray(new String[] {}));
IProject p = null;
if (selection != null && !selection.isEmpty()) {
if (IProject.class.isInstance(selection.getFirstElement())) {
p = (IProject) selection.getFirstElement();
} else if (OriginalStub.class.isInstance(selection
.getFirstElement())) {
OriginalStub stub = (OriginalStub) selection.getFirstElement();
p = (IProject) stub.getProject();
} else if (OriginalFileStore.class.isInstance(selection
.getFirstElement())) {
OriginalFileStore store = (OriginalFileStore) selection
.getFirstElement();
p = store.getProject();
}
}
if (p != null && p.isOpen()) {
projectCombo.select(openProjects.indexOf(p.getName()));
} else {
projectCombo.select(0);
}
}
/**
* Check if widgets are enabled or disabled by a change in the dialog.
*/
protected void updateWidgets() {
if (location != null) {
if (URIUtil.isFileURI(this.location)) {
this.locationField.setText(location.getPath());
} else {
this.locationField.setText(location.toString());
}
} else {
this.locationField.setText("");
}
// if (prestagedLocation != null) {
// this.preStagedCombo.setText(prestagedLocation);
// } else {
// this.preStagedCombo.setText("");
// }
try {
updateFileTree();
} catch (Exception e) {
e.printStackTrace();
}
boolean pageComplete = determinePageCompletion();
setPageComplete(pageComplete);
if (pageComplete) {
setMessage(null);
}
}
private void updateFileTree() throws URISyntaxException, CoreException {
URI baseURI = null;
IFileStore base = null;
if (location == null) {
this.fileTreeViewer.setInput(FileStoreProvider.EMPTY_ROOT);
} else {
baseURI = location;
base = EFS.getStore(baseURI);
if (!base.equals(this.fileTreeViewer.getInput())) {
this.fileTreeViewer.setInput(new FileStoreProvider.Root(base));
}
}
if (this.fileTreeViewer.getCheckedElements().length == 0) {
selectFirstCheckbox();
}
}
private void updateFromLocationField() {
try {
URI loc = URIUtil.fromString(locationField.getText());
if (loc.getScheme() == null) {
loc = URIUtil.fromString("file:" + locationField.getText());
}
} catch (URISyntaxException e) {
this.location = null;
setErrorMessage("Cannot parse location: " + e.getLocalizedMessage());
}
updateWidgets();
}
// private void updateFromPrestagedLocation() {
// this.prestagedLocation = this.preStagedCombo.getText();
// updateWidgets();
// }
/**
* @return
*/
public boolean finish() {
List<URI> selected = getCheckedLocations();
boolean removeable = this.removeableButton.getSelection();
URI prestageBase = null;
Job linkJob = new OriginalsLinkJob(this.location, selected,
getProject(), removeable);
// linkJob.addJobChangeListener(this);
linkJob.schedule();
// SNAPSHOT MAY NOT BE NEEDED ANY MORE and takes time
// for (IFolder folder : linkJob.getLinkFolders()) {
// Job snapshotJob = new OriginalFolderSnapshotJob(folder, false);
// snapshotJob.schedule(Job.BUILD);
// }
return true;
}
/**
* @return
*
*/
private List<URI> getCheckedLocations() {
List<URI> result = new ArrayList<URI>();
for (Object o : this.fileTreeViewer.getCheckedElements()) {
result.add(((IFileStore) o).toURI());
}
return result;
}
}