/*************************************************************************************
* Copyright (c) 2009-2011 Red Hat, Inc. and others.
* 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:
* JBoss by Red Hat - Initial implementation.
************************************************************************************/
package org.jboss.tools.common.jdt.ui.buildpath.dialog;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.jboss.tools.common.jdt.ui.JDTExtUIActivator;
public class MaterializeLibraryDialog extends TitleAreaDialog {
private static final String SOURCE_PROPERTY = "SOURCE_PROPERTY";
private static final String FILENAME_PROPERTY = "FILENAME_PROPERTY";
private IContainer libFolder;
private Map<IClasspathEntry, String> classpathEntryPaths;
private Map<IPath, String> selectedClasspathEntryPaths;
private IClasspathContainer containerToMaterialize;
private final String libName;
private Image jarImage;
private Image projectImage;
private Text libfolderText;
private CheckboxTableViewer classpathEntriesViewer;
private Button keepSourceBtn;
private boolean keepSources;
private IMaterializeLibraryWarningFactory warningfactory;
private Label warningImg;
private Label warningLabel;
public MaterializeLibraryDialog(Shell shell, IProject project, IClasspathContainer containerToMaterialize, String defaultLib) {
super(shell);
setShellStyle(super.getShellStyle() | SWT.RESIZE | SWT.MODELESS);
this.libName = containerToMaterialize.getDescription();
IPath folderPath = project.getFullPath().append(defaultLib);
libFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(folderPath);
this.containerToMaterialize = containerToMaterialize;
warningfactory = new MaterializeLibraryWarningFactory();
initClasspathEntryPaths();
}
private void initClasspathEntryPaths() {
IClasspathEntry[] cpEntries = containerToMaterialize.getClasspathEntries();
classpathEntryPaths = new LinkedHashMap<IClasspathEntry, String>(cpEntries.length);
for (IClasspathEntry entry : cpEntries) {
if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY && entry.getPath() != null)
|| (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)) {
IPath sourceFilePath = entry.getPath();
String fileName = sourceFilePath.lastSegment();
classpathEntryPaths.put(entry, fileName);
}
}
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText("Copy Classpath Libraries");
}
private void initImages() {
jarImage = JDTExtUIActivator.getJarIcon();
projectImage = JDTExtUIActivator.getProjectIcon();
}
@Override
protected Control createDialogArea(Composite parent) {
initImages();
setTitle("Copy JAR files from "+libName);
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setEnabled(true);
GridLayout layout = new GridLayout(3, false);
layout.marginLeft = 12;
container.setLayout(layout);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
String message = NLS.bind("Copy selected JAR files from {0} to the destination folder.",libName);
String warning = warningfactory.getWarning(containerToMaterialize);
if (warning != null) {
displayWarning(container, warning);
}
setMessage(message);
Label libFolderLabel = new Label(container, SWT.NONE);
libFolderLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
false, 1, 1));
libFolderLabel.setText("Destination folder");
libfolderText = new Text(container, SWT.BORDER);
libfolderText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
false, 1, 1));
libfolderText.setEditable(true);
libfolderText.setText(libFolder.getFullPath().toPortableString());
libfolderText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent event) {
validate();
}
});
addSelectFolderButton(container);
displayClasspathEntriesTable(container);
return area;
}
private void displayWarning(Composite container, String warning) {
Composite composite = new Composite(container, SWT.NONE);
GridDataFactory.fillDefaults().align(SWT.LEFT,SWT.CENTER).span(3,1).applyTo(composite);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(composite);
warningImg = new Label(composite, SWT.CENTER);
warningImg.setImage(JFaceResources.getImage(DLG_IMG_MESSAGE_WARNING));
GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(warningImg);
warningLabel = new Label(composite, SWT.NONE);
warningLabel.setText(warning);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(warningLabel);
}
private void addSelectFolderButton(Composite container) {
Button button = new Button(container, SWT.NONE);
button.setLayoutData(new GridData(SWT.FILL, SWT.UP, false, false, 1, 1));
button.setText("Select Folder");
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
ContainerSelectionDialog dialog = new ContainerSelectionDialog(
getShell(),
getLibFolderFromText(libfolderText.getText()),
true,
"Select Destination Folder");
dialog.setTitle("Container Selection");
dialog.open();
Object[] result = dialog.getResult();
if (result != null && result[0] instanceof IPath) {
libfolderText.setText(((IPath) result[0]).toPortableString());
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
@Override
public boolean close() {
if (jarImage != null) {
jarImage.dispose();
}
if (projectImage != null) {
projectImage.dispose();
}
return super.close();
}
private void displayClasspathEntriesTable(Composite container) {
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 4);
gd.heightHint = 500;
gd.widthHint = 550;
classpathEntriesViewer = CheckboxTableViewer.newCheckList(container,
SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION );
Table table = classpathEntriesViewer.getTable();
table.setFocus();
table.setLayoutData(gd);
table.setLinesVisible(true);
table.setHeaderVisible(true);
TableColumn emptyColumn = new TableColumn(table, SWT.NONE);
emptyColumn.setWidth(20);
TableViewerColumn sourceColumn = new TableViewerColumn(classpathEntriesViewer, SWT.NONE);
sourceColumn.getColumn().setText("Source ");
sourceColumn.getColumn().setWidth(299);
TableViewerColumn destinationColumn = new TableViewerColumn(classpathEntriesViewer, SWT.NONE);
destinationColumn.getColumn().setText("Copy as...");
destinationColumn.getColumn().setWidth(248);
classpathEntriesViewer.setContentProvider(ArrayContentProvider.getInstance());
classpathEntriesViewer.setLabelProvider(new ClasspathEntryLabelProvider());
classpathEntriesViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
refresh();
}
});
classpathEntriesViewer.setInput(classpathEntryPaths.entrySet());
classpathEntriesViewer.setAllChecked(true);
addSelectionButton(container, "Select All", true);
addSelectionButton(container, "Deselect All", false);
addResetButton(container, "Reset");
keepSourceBtn = addCheckButton(container, "Keep source attachments", keepSources);
keepSourceBtn.setToolTipText("Source attachment paths may contain absolute paths");
addTableListeners();
}
private Button addCheckButton(Composite container, String label,
boolean selected) {
Button checkBtn = new Button(container, SWT.CHECK);
checkBtn.setText(label);
checkBtn.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1));
checkBtn.setSelection(selected);
return checkBtn;
}
private void addTableListeners() {
addCellEditors();
}
protected void addCellEditors() {
classpathEntriesViewer.setColumnProperties(
new String[] { "EMPTY", SOURCE_PROPERTY, FILENAME_PROPERTY });
TextCellEditor ce = new TextCellEditor( classpathEntriesViewer.getTable());
CellEditor[] editors = new CellEditor[] { null, ce, ce };
classpathEntriesViewer.setCellEditors(editors);
classpathEntriesViewer.setCellModifier(new FileNameCellModifier());
}
public Map<IPath, String> getSelectedClasspathEntryPaths() {
return selectedClasspathEntryPaths;
}
public IContainer getLibFolder() {
return libFolder;
}
public boolean isKeepSources() {
return keepSources;
}
private static IContainer getLibFolderFromText(String text) {
String portablePath = text.replaceAll("\\\\", "/");
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath path = new Path(portablePath);
if (path.segmentCount() == 1) {
return workspaceRoot.getProject(path.segment(0));
} if (path.segmentCount() > 1) {
return ResourcesPlugin.getWorkspace().getRoot().getFolder(path);
}
return null;
}
@Override
protected void okPressed() {
if (!validate()) {
return;
}
String dialogWarning = warningfactory.getDialogWarning(containerToMaterialize);
if (dialogWarning != null) {
String[] buttonLabels = new String[] { IDialogConstants.OK_LABEL,
IDialogConstants.CANCEL_LABEL };
MessageDialog dialog = new MessageDialog(getShell(), getShell().getText(), null, dialogWarning,
MessageDialog.WARNING, buttonLabels, 0);
if (dialog.open() == CANCEL) {
return;
}
}
libFolder = getLibFolderFromText(libfolderText.getText());
keepSources = keepSourceBtn.getSelection();
super.okPressed();
}
private boolean validate() {
boolean valid = validateLibFolder() && validateEntries();
if (valid) {
setErrorMessage(null);
}
return valid;
}
private boolean validateLibFolder() {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IContainer folder = getLibFolderFromText(libfolderText.getText());
if (folder == null || workspaceRoot.equals(folder)) {
setErrorMessage("You must select a project destination to copy classpath entries");
return false;
}
String ancestorPath = folder.getFullPath().segment(0);
IResource ancestor = workspaceRoot.findMember(ancestorPath);
if (ancestor == null || !ancestor.exists()) {
setErrorMessage(ancestorPath + " does not exist ");
return false;
}
return true;
}
@SuppressWarnings("unchecked")
private boolean validateEntries() {
Object[] selection = classpathEntriesViewer.getCheckedElements();
selectedClasspathEntryPaths = new LinkedHashMap<IPath, String>(
selection.length);
for (Object o : selection) {
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) o;
if (entry.getKey().getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
String name = entry.getValue();
if (!checkValidName(name)) {
setErrorMessage(name + " is not a valid file name");
return false;
}
}
selectedClasspathEntryPaths.put(entry.getKey().getPath(),
entry.getValue());
}
Set<String> duplicates = findDuplicates(selectedClasspathEntryPaths.values());
if (!duplicates.isEmpty()) {
setErrorMessage("Duplicate entries found : " + duplicates.toString());
return false;
}
return true;
}
private Set<String> findDuplicates(Collection<String> values) {
Set<String> uniqueNames = new HashSet<String>(values.size());
Set<String> duplicateNames = new HashSet<String>();
for (String name : values) {
if (!uniqueNames.add(name)) {
duplicateNames.add(name);
}
}
return duplicateNames;
}
@SuppressWarnings("unchecked")
private class ClasspathEntryLabelProvider extends LabelProvider implements
ITableLabelProvider {
private static final int SOURCE_COLUMN = 1;
private static final int FILENAME_COLUMN = 2;
public String getColumnText(Object element, int columnIndex) {
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) element;
StringBuilder text = new StringBuilder();
if (entry != null) {
if (columnIndex == SOURCE_COLUMN) {
text.append(entry.getKey().getPath().lastSegment());
} else if (columnIndex == FILENAME_COLUMN) {
text.append(entry.getValue());
}
}
return text.toString();
}
@Override
public Image getColumnImage(Object element, int columnIndex) {
Image img = null;
if (columnIndex > 0) {
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) element;
if (entry.getKey().getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
img = jarImage;
} else {
img = projectImage;
}
}
return img;
}
}
private Button addSelectionButton(Composite container, String label,
final boolean ischecked) {
Button button = new Button(container, SWT.NONE);
button.setLayoutData(new GridData(SWT.FILL, SWT.UP, false, false, 1, 1));
button.setText(label);
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
classpathEntriesViewer.setAllChecked(ischecked);
refresh();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
return button;
}
private Button addResetButton(Composite container, String label) {
Button button = new Button(container, SWT.NONE);
button.setLayoutData(new GridData(SWT.FILL, SWT.UP, false, false, 1, 1));
button.setText(label);
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
initClasspathEntryPaths();
classpathEntriesViewer.setInput(classpathEntryPaths.entrySet());
classpathEntriesViewer.setAllChecked(true);
refresh();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
return button;
}
protected void refresh() {
classpathEntriesViewer.refresh();
}
@SuppressWarnings("unchecked")
private class FileNameCellModifier implements ICellModifier {
public boolean canModify(Object element, String property) {
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) element;
return (entry.getKey().getEntryKind() == IClasspathEntry.CPE_LIBRARY)
&& (FILENAME_PROPERTY.equals(property) || SOURCE_PROPERTY
.equals(property));
}
public Object getValue(Object element, String property) {
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) element;
// if(entry.getKey().getEntryKind() == IClasspathEntry.CPE_LIBRARY)
// {
if (property.equals(SOURCE_PROPERTY)) {
return entry.getKey().getPath().toOSString();
} else if (property.equals(FILENAME_PROPERTY)) {
return entry.getValue();
}
// }
return ""; //$NON-NLS-1$
}
public void modify(Object element, String property, Object value) {
if (property.equals(FILENAME_PROPERTY)) {
TableItem item = (TableItem) element;
Map.Entry<IClasspathEntry, String> entry = (Map.Entry<IClasspathEntry, String>) item
.getData();
if (entry.getKey().getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
String name = value.toString();
entry.setValue(name);
validate();
classpathEntriesViewer.refresh();
}
}
}
}
public boolean checkValidName(String name) {
// TODO checks for :
// - duplicates
// - existing CPE
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IStatus result = workspace.validateName(name, IResource.FILE);
if (!result.isOK()) {
return false;
}
return !name.contains("\\")
&& (name.endsWith(".jar") || name.endsWith(".zip"));
}
}