package bndtools.wizards.project;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
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.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
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.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE.SharedImages;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import aQute.bnd.build.Project;
import aQute.bnd.build.Workspace;
import aQute.bnd.osgi.Constants;
import bndtools.Plugin;
public class ImportBndWorkspaceWizardPageOne extends WizardPage {
private Text txtFolder;
private Button deleteButton;
private Button inferExecutionEnvironmentButton;
/**
* TableViewer is used to display an image for the project which is not possible with a ListViewer
*/
private TableViewer tableViewer;
private ControlDecoration txtFolderErrorDecorator;
protected ImportBndWorkspaceWizardPageOne(String pageName) {
super(pageName);
setTitle("Bnd Workspace Projects");
setDescription("Select a root directory of Bnd Workspace");
}
/**
* Return the valid Bnd Workspace root, which was specified by the user Uses UI-Thread, do not call from other
* Threads
*
* @return valid folder
*/
File getSelectedFolder() {
if (!isPageComplete()) {
throw new IllegalStateException("getSelectedFolder cannot be called before wizard-page is marked as complete!");
}
return new File(txtFolder.getText());
}
/**
* Return the selection, if the user wants to delete all existing settings. Uses UI-Thread, do not call from other
* Threads
*
* @return selection-state from checkbox
*/
boolean isDeleteSettings() {
return deleteButton.getSelection();
}
/**
* Return the selection, if the user wants to infer the execution-environment from BND
* {@link Constants#JAVAC_TARGET}. Uses UI-Thread, do not call from other Threads
*
* @return selection-state from checkbox
*/
boolean isInferExecutionEnvironment() {
return inferExecutionEnvironmentButton.getSelection();
}
@Override
public void createControl(final Composite parent) {
final Composite container = new Composite(parent, SWT.NONE);
Label lblFolder = new Label(container, SWT.NONE);
lblFolder.setText("Root Directory:");
txtFolder = new Text(container, SWT.BORDER | SWT.SINGLE);
txtFolder.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent event) {
getWizard().getContainer().updateButtons();
}
});
//Adding the decorator
txtFolderErrorDecorator = new ControlDecoration(txtFolder, SWT.TOP | SWT.RIGHT);
FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
Image img = fieldDecoration.getImage();
txtFolderErrorDecorator.setImage(img);
txtFolderErrorDecorator.setDescriptionText("Selected folder must contain valid Bnd Workspace configuration project.");
// hiding it initially
txtFolderErrorDecorator.hide();
Button btnOpenDialog = new Button(container, SWT.PUSH);
btnOpenDialog.setText("Browse...");
btnOpenDialog.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
DirectoryDialog dirDialog = new DirectoryDialog(container.getShell());
dirDialog.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
dirDialog.setText("Select the folder containing the project.");
txtFolder.setText(dirDialog.open());
getWizard().getContainer().updateButtons();
}
});
Label lblProjects = new Label(container, SWT.NONE);
lblProjects.setText("Projects:");
tableViewer = new TableViewer(container, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
tableViewer.setComparator(new ViewerComparator() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
// configuration project always first
if (e1 instanceof File && e2 instanceof Project) {
return -1;
} else if (e1 instanceof Project && e2 instanceof File) {
return 1;
}
Project p1 = (Project) e1;
Project p2 = (Project) e2;
return super.compare(viewer, p1.getName(), p2.getName());
}
});
tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
// Disable selection since the tableviewer should be readonly, but not disabled
if (!event.getSelection().isEmpty()) {
tableViewer.setSelection(StructuredSelection.EMPTY);
}
}
});
TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
column.setLabelProvider(new ProjectsColumnLabelProvider());
Button refreshButton = new Button(container, SWT.PUSH);
refreshButton.setText("Refresh");
refreshButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
getWizard().getContainer().updateButtons();
}
});
deleteButton = new Button(container, SWT.CHECK);
deleteButton.setText("Delete existing settings");
inferExecutionEnvironmentButton = new Button(container, SWT.CHECK);
inferExecutionEnvironmentButton.setSelection(true);
inferExecutionEnvironmentButton.setText("Infer execution-environment (J2SE and JavaSE).");
inferExecutionEnvironmentButton
.setToolTipText("Uses the 'javac.target' from the Bnd Workspace to infer a Execution Environment to the JRE container. If nothing matches, the default JRE will be used.\nExisting containers will be removed.");
FormLayout layout = new FormLayout();
container.setLayout(layout);
FormData fd_lblFolder = new FormData();
fd_lblFolder.top = new FormAttachment(0, 10);
fd_lblFolder.left = new FormAttachment(0, 10);
lblFolder.setLayoutData(fd_lblFolder);
FormData fd_txtFolder = new FormData();
fd_txtFolder.top = new FormAttachment(lblFolder, 0, SWT.CENTER);
fd_txtFolder.left = new FormAttachment(lblFolder, 10);
fd_txtFolder.right = new FormAttachment(100, -100);
txtFolder.setLayoutData(fd_txtFolder);
FormData fd_btnDialog = new FormData();
fd_btnDialog.top = new FormAttachment(lblFolder, 0, SWT.CENTER);
fd_btnDialog.left = new FormAttachment(txtFolder, 10);
fd_btnDialog.right = new FormAttachment(100, -10);
btnOpenDialog.setLayoutData(fd_btnDialog);
FormData fd_lblProjects = new FormData();
fd_lblProjects.top = new FormAttachment(lblFolder, 20);
fd_lblProjects.left = new FormAttachment(lblFolder, 0, SWT.LEFT);
lblProjects.setLayoutData(fd_lblProjects);
FormData fd_table = new FormData();
fd_table.top = new FormAttachment(lblProjects, 5);
fd_table.left = new FormAttachment(lblFolder, 0, SWT.LEFT);
fd_table.right = new FormAttachment(100, -100);
fd_table.bottom = new FormAttachment(100, -55);
tableViewer.getTable().setLayoutData(fd_table);
FormData fd_btnRefresh = new FormData();
fd_btnRefresh.top = new FormAttachment(tableViewer.getTable(), 0, SWT.TOP);
fd_btnRefresh.left = new FormAttachment(btnOpenDialog, 0, SWT.LEFT);
fd_btnRefresh.right = new FormAttachment(100, -10);
refreshButton.setLayoutData(fd_btnRefresh);
FormData fd_btnDelete = new FormData();
fd_btnDelete.top = new FormAttachment(tableViewer.getTable(), 10);
fd_btnDelete.left = new FormAttachment(lblFolder, 0, SWT.LEFT);
deleteButton.setLayoutData(fd_btnDelete);
FormData fd_btnInfer = new FormData();
fd_btnInfer.top = new FormAttachment(deleteButton, 10);
fd_btnInfer.left = new FormAttachment(lblFolder, 0, SWT.LEFT);
inferExecutionEnvironmentButton.setLayoutData(fd_btnInfer);
getShell().setMinimumSize(470, 450);
// required to avoid an error in the system
setControl(parent);
setPageComplete(false);
txtFolder.setText(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
}
@Override
public boolean canFlipToNextPage() {
// single page
return false;
}
@Override
public boolean isPageComplete() {
return updateWorkspaceSelection();
}
/**
* Takes the selected/typed folder from the the {@link #txtFolder} and tries to obtain a valid Bnd Workspace. In any
* case, the {@link #tableViewer} is updated.
*
* @return true, when a Bnd Workspace was selected and properly initialized
*/
private boolean updateWorkspaceSelection() {
final String selectedFolder = txtFolder.getText();
boolean result = false;
// check if folder containing a cnf-folder for Bnd was selected
if (null != selectedFolder && selectedFolder.trim().length() > 0) {
File chosenDirectory = new File(txtFolder.getText());
if (chosenDirectory.exists()) {
final Workspace bndWorkspace;
try {
bndWorkspace = Workspace.getWorkspace(chosenDirectory);
setErrorMessage(null);
txtFolderErrorDecorator.hide();
List<Object> tableEntries = new ArrayList<Object>(bndWorkspace.getAllProjects());
tableEntries.add(bndWorkspace.getBuildDir());
tableViewer.setInput(tableEntries);
result = true;
} catch (Exception e) {
// not a valid Bnd Workspace folder
setErrorMessage(e.getMessage());
txtFolderErrorDecorator.show();
}
} else {
// handle non-existing folders
setErrorMessage("No Workspace found from: " + selectedFolder);
txtFolderErrorDecorator.show();
}
}
if (!result) {
tableViewer.setInput(Collections.emptyList());
}
for (TableColumn col : tableViewer.getTable().getColumns()) {
// make sure TableViewerColumn has enough width to display new selection
col.pack();
}
tableViewer.refresh();
return result;
}
private static final class ProjectsColumnLabelProvider extends ColumnLabelProvider {
private static final String KEY_GENERAL_PROJECT = ProjectsColumnLabelProvider.class.getName();
private static final String KEY_GENERAL_PROJECT_GREYSCALE = KEY_GENERAL_PROJECT + "_grey";
private static final String KEY_JAVA_PROJECT = KEY_GENERAL_PROJECT + "_java";
private static final String KEY_JAVA_PROJECT_GREYSCALE = KEY_JAVA_PROJECT + "_grey";
private ProjectsColumnLabelProvider() {
// prepare images (greyscale used for disabled)
if (Plugin.getDefault().getImageRegistry().get(KEY_GENERAL_PROJECT) == null) {
Image image = PlatformUI.getWorkbench().getSharedImages().getImage(SharedImages.IMG_OBJ_PROJECT);
Plugin.getDefault().getImageRegistry().put(KEY_GENERAL_PROJECT, image);
Plugin.getDefault().getImageRegistry().put(KEY_GENERAL_PROJECT_GREYSCALE, new Image(Display.getCurrent(), image, SWT.IMAGE_GRAY));
}
if (Plugin.getDefault().getImageRegistry().get(KEY_JAVA_PROJECT) == null) {
// use Java-Project image from JDT (unfortunately not shared by JDT-Plugin)
Image image = AbstractUIPlugin.imageDescriptorFromPlugin(JavaUI.ID_PLUGIN, "icons/full/eview16/projects.gif").createImage();
Plugin.getDefault().getImageRegistry().put(KEY_JAVA_PROJECT, image);
Plugin.getDefault().getImageRegistry().put(KEY_JAVA_PROJECT_GREYSCALE, new Image(Display.getCurrent(), image, SWT.IMAGE_GRAY));
}
}
@Override
public String getText(Object element) {
String text;
if (element instanceof File) {
text = ((File) element).getName() + " - configuration project";
} else {
text = ((Project) element).getName();
}
if (projectExistsInEclipse(element)) {
text = text + " (project already exists, metadata will updated)";
}
return text;
}
@Override
public Color getForeground(Object element) {
if (projectExistsInEclipse(element)) {
// maybe check for some "disabled" foreground to work better with theming
return Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
}
return super.getForeground(element);
}
@Override
public Image getImage(Object element) {
boolean projectExists = projectExistsInEclipse(element);
final Image image;
if (element instanceof File) {
if (projectExists) {
image = Plugin.getDefault().getImageRegistry().get(KEY_GENERAL_PROJECT_GREYSCALE);
} else {
image = Plugin.getDefault().getImageRegistry().get(KEY_GENERAL_PROJECT);
}
} else {
if (projectExists) {
image = Plugin.getDefault().getImageRegistry().get(KEY_JAVA_PROJECT_GREYSCALE);
} else {
image = Plugin.getDefault().getImageRegistry().get(KEY_JAVA_PROJECT);
}
}
return image;
}
private boolean projectExistsInEclipse(Object element) {
final IProject existingProject;
if (element instanceof File) {
File cnfFile = (File) element;
existingProject = ResourcesPlugin.getWorkspace().getRoot().getProject(cnfFile.getName());
return existingProject.exists() && existingProject.getLocation().toString().equals(cnfFile.toString());
}
Project project = (Project) element;
existingProject = ResourcesPlugin.getWorkspace().getRoot().getProject(project.getName());
return existingProject.exists() && existingProject.getLocation().toString().equals(project.getBase().toString());
}
}
}