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()); } } }