/** * Aptana Studio * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). * Please see the license.html included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package com.aptana.editor.php.internal.ui.preferences; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.DialogPage; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; 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.DirectoryDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; import org.eclipse.ui.progress.UIJob; import com.aptana.editor.php.internal.builder.IPHPLibrary; import com.aptana.editor.php.internal.builder.LibraryManager; import com.aptana.editor.php.internal.builder.preferences.ProjectDependencies; /** * Composite for editing PHP project build path. * * @author Pavel Petrochenko * @author Denis Denisenko */ public class BuildPathEditingComposite extends Composite { private TableViewer workspaceViewer; private TableViewer directoryViewer; private CheckboxTableViewer libraryViewer; private boolean usesCustomLibs; private Set<String> notusedLibraries = new HashSet<String>(); private Button customLibsButton; private Button select; private Button deselect; private IProject project; private final PropertyPage propertyPage; /** * Constructs a new BuildPathEditingComposite * * @param propertyPage * The {@link PropertyPage} that contains this composite. * @param parent * @param style */ public BuildPathEditingComposite(PropertyPage propertyPage, Composite parent, int style) { super(parent, style); Assert.isNotNull(propertyPage, "PropertyPage was null"); //$NON-NLS-1$ this.propertyPage = propertyPage; this.project = (IProject) propertyPage.getElement().getAdapter(IProject.class); this.setLayout(new FillLayout()); TabFolder fld = new TabFolder(this, SWT.LEFT); TabItem item = new TabItem(fld, SWT.NONE); item.setText(Messages.BuildPathEditingComposite_ProjectsTabTitle); createWorkspacePart(item); TabItem item1 = new TabItem(fld, SWT.NONE); item1.setText(Messages.BuildPathEditingComposite_DirectoriesTabTitle); TabItem item2 = new TabItem(fld, SWT.NONE); item2.setText(Messages.BuildPathEditingComposite_libraries); createDirectoryPart(item1); createLibraryPart(item2); } private void createLibraryPart(TabItem item) { TabFolder parent2 = item.getParent(); Composite projectPart = new Composite(parent2, SWT.NONE); projectPart.setLayout(new GridLayout(2, false)); customLibsButton = new Button(projectPart, SWT.CHECK); GridData layoutData = new GridData(GridData.FILL_HORIZONTAL); layoutData.horizontalSpan = 2; customLibsButton.setLayoutData(layoutData); customLibsButton.setText(Messages.BuildPathEditingComposite_projectSpecific); libraryViewer = CheckboxTableViewer.newCheckList(projectPart, SWT.BORDER); libraryViewer.setContentProvider(new ArrayContentProvider()); IPHPLibrary[] allLibraries = LibraryManager.getInstance().getAllLibraries(); libraryViewer.setInput(allLibraries); libraryViewer.setComparator(new ViewerComparator()); final Map<URL,Image> images = new HashMap<URL, Image>(); libraryViewer.setLabelProvider(new LibraryLabelProvider(images)); final Composite buttons = new Composite(projectPart, SWT.NONE); projectPart.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { for (Image m : images.values()) { m.dispose(); } } }); libraryViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 0; buttons.setLayout(layout); select = new Button(buttons, SWT.NONE); select.setText(Messages.LibrariesPage_selectAll); select.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); deselect = new Button(buttons, SWT.NONE); deselect.setText(Messages.LibrariesPage_deselectAll); deselect.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL)); customLibsButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { boolean selection = customLibsButton.getSelection(); libraryViewer.getControl().setEnabled(selection); select.setEnabled(selection); deselect.setEnabled(selection); } }); select.addSelectionListener(new SelectAction(true)); deselect.addSelectionListener(new SelectAction(false)); item.setControl(projectPart); } private void createDirectoryPart(TabItem item) { TabFolder parent2 = item.getParent(); Composite projectPart = new Composite(parent2, SWT.NONE); projectPart.setLayout(new GridLayout(2, false)); directoryViewer = new TableViewer(projectPart, SWT.BORDER | SWT.MULTI); directoryViewer.setLabelProvider(new LabelProvider() { @Override public Image getImage(Object element) { return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER); } @Override public String getText(Object element) { File fl = (File) element; return fl.getAbsolutePath(); } }); directoryViewer.setContentProvider(new ArrayContentProvider()); directoryViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); Composite buttonsComp = new Composite(projectPart, SWT.NONE); buttonsComp.setLayoutData(new GridData(GridData.FILL_VERTICAL)); buttonsComp.setLayout(new GridLayout(1, false)); Button add = new Button(buttonsComp, SWT.NONE); add.setText(Messages.BuildPathEditingComposite_AddDirectory); add.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { DirectoryDialog dialog = new DirectoryDialog(Display.getCurrent().getActiveShell(), SWT.NONE); dialog.setText(Messages.BuildPathEditingComposite_AddDirectoryDescription); String open = dialog.open(); if (open != null) { addWithValidation(directoryViewer, new File(open)); } } }); add.setLayoutData(GridDataFactory.fillDefaults().hint(100, -1).create()); final Button remove = new Button(buttonsComp, SWT.NONE); remove.setText(Messages.BuildPathEditingComposite_RemoveDirectory); remove.setLayoutData(GridDataFactory.fillDefaults().hint(100, -1).create()); directoryViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { remove.setEnabled(!event.getSelection().isEmpty()); } }); remove.setEnabled(false); remove.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IStructuredSelection sel = (IStructuredSelection) directoryViewer.getSelection(); Object[] selections = sel.toArray(); for (Object selected : selections) { directoryViewer.remove(selected); } } }); directoryViewer.setSorter(new ViewerSorter()); item.setControl(projectPart); } private void createWorkspacePart(TabItem item) { TabFolder parent2 = item.getParent(); Composite projectPart = new Composite(parent2, SWT.NONE); item.setControl(projectPart); projectPart.setLayout(new GridLayout(2, false)); workspaceViewer = new TableViewer(projectPart, SWT.BORDER | SWT.MULTI); final FullPathWorkbenchLabelProvider workbenchLabelProvider = new FullPathWorkbenchLabelProvider(project); workspaceViewer.setLabelProvider(workbenchLabelProvider); workspaceViewer.getControl().addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { workbenchLabelProvider.doDispose(); } }); workspaceViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); workspaceViewer.setContentProvider(new ArrayContentProvider()); Composite buttonsComp = new Composite(projectPart, SWT.NONE); buttonsComp.setLayoutData(new GridData(GridData.FILL_VERTICAL)); buttonsComp.setLayout(new GridLayout(1, false)); Button add = new Button(buttonsComp, SWT.NONE); add.setText(Messages.BuildPathEditingComposite_AddProjectTitle); add.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { WorkspaceFolderSelectionDialog dialog = new WorkspaceFolderSelectionDialog(Display.getCurrent() .getActiveShell()); dialog.setTitle(Messages.BuildPathEditingComposite_ProjectsSelectionTitle); dialog.setMessage(Messages.BuildPathEditingComposite_AddProjectDesription); IWorkspace workspace = ResourcesPlugin.getWorkspace(); dialog.setInput(workspace); // filtering out current project and its contents dialog.addFilter(new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof IResource) { if (project.equals(((IResource) element).getProject())) { return false; } } return true; } }); if (dialog.open() == Dialog.OK) { addWithValidation(workspaceViewer, dialog.getResult()); } } }); add.setLayoutData(GridDataFactory.fillDefaults().hint(100, -1).create()); final Button remove = new Button(buttonsComp, SWT.NONE); remove.setText(Messages.BuildPathEditingComposite_RemoveProjectTitle); remove.setEnabled(false); workspaceViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { if (project != null) { // Do not allow removal in case the default project is selected remove.setEnabled(!event.getSelection().isEmpty() && !((IStructuredSelection) event.getSelection()).toList().contains(project)); } else { remove.setEnabled(!event.getSelection().isEmpty()); } } }); remove.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IStructuredSelection sel = (IStructuredSelection) workspaceViewer.getSelection(); Object[] selections = sel.toArray(); for (Object selected : selections) { workspaceViewer.remove(selected); } } }); remove.setLayoutData(GridDataFactory.fillDefaults().hint(100, -1).create()); workspaceViewer.setSorter(new ViewerSorter()); } /** * Initializes composite. * * @param workspaceResources * - workspace resources. * @param directories * - external directories. */ public void init(List<IResource> workspaceResources, List<File> directories) { if (project != null && !workspaceResources.contains(project)) { workspaceResources.add(0, project); } workspaceViewer.setInput(workspaceResources.toArray()); directoryViewer.setInput(directories.toArray()); } /** * Add an item to the table viewer after verifying that the path of that item does not exist or is not containing * the path for this item. * * @param tableViewer * @param item */ @SuppressWarnings({"unchecked", "rawtypes"}) private void addWithValidation(TableViewer tableViewer, Object item) { propertyPage.setMessage(null); TableItem[] tableItems = tableViewer.getTable().getItems(); if (tableItems == null || tableItems.length == 0) { // Just add if (item instanceof Object[]) { Object[] items = (Object[]) item; for (Object obj : items) { tableViewer.add(obj); return; } } else { if (item != null) { tableViewer.add(item); return; } } } List toAdd = new ArrayList(); boolean hasAlreadyIncludedPaths = false; if (item instanceof File) { File directoryAdded = (File) item; // Check for files that are already in the table. boolean shouldAdd = true; for (TableItem tableItem : tableItems) { Object data = tableItem.getData(); if (data instanceof File) { File existinsDirectory = (File) data; if (existinsDirectory.equals(directoryAdded) || directoryAdded.getAbsolutePath().startsWith(existinsDirectory.getAbsolutePath())) { hasAlreadyIncludedPaths = true; shouldAdd = false; break; } } } if (shouldAdd) { toAdd.add(directoryAdded); } } else if (item instanceof Object[]) { Object[] elements = (Object[]) item; for (Object element : elements) { boolean shouldAdd = true; for (TableItem tableItem : tableItems) { if (element instanceof IResource && tableItem.getData() instanceof IResource) { IResource resource = (IResource) element; IResource resourceInTable = (IResource) tableItem.getData(); if ((resourceInTable).getFullPath().isPrefixOf(resource.getFullPath())) { hasAlreadyIncludedPaths = true; shouldAdd = false; break; } } } if (shouldAdd) { toAdd.add(element); } } } tableViewer.add(toAdd.toArray()); if (hasAlreadyIncludedPaths) { propertyPage.setMessage(Messages.BuildPathEditingComposite_selectionIncludedNotice, DialogPage.INFORMATION); Job job = new UIJob("Build-Path::Remove message") //$NON-NLS-1$ { public IStatus runInUIThread(IProgressMonitor monitor) { if (propertyPage != null && !propertyPage.getControl().isDisposed()) { propertyPage.setMessage(null); } return Status.OK_STATUS; } }; job.schedule(4000); // wait 4 seconds before removing the message } } /** * Fills composite result. * * @param workspaceResources * - workspace resource to fill. * @param fileList * - external folders to fill. */ public void fillResult(List<IResource> workspaceResources, List<File> fileList) { TableItem[] items = workspaceViewer.getTable().getItems(); for (TableItem i : items) { IResource resource = (IResource) i.getData(); if (resource != project) { workspaceResources.add(resource); } } items = directoryViewer.getTable().getItems(); for (TableItem i : items) { fileList.add((File) i.getData()); } } public void init(ProjectDependencies buildPath) { init(buildPath.getWorkspaceResources(), buildPath.getDirectories()); usesCustomLibs = buildPath.isUsesCustomLibs(); List<String> notUsedLibrariesIds = buildPath.getNotUsedLibrariesIds(); notusedLibraries = new HashSet<String>(notUsedLibrariesIds); customLibsButton.setSelection(usesCustomLibs); for (IPHPLibrary l : LibraryManager.getInstance().getAllLibraries()) { if (!notusedLibraries.contains(l.getId())) { libraryViewer.setChecked(l, true); } } libraryViewer.getControl().setEnabled(usesCustomLibs); select.setEnabled(usesCustomLibs); deselect.setEnabled(usesCustomLibs); } public void fillResult(ProjectDependencies bp) { List<IResource> ps = new ArrayList<IResource>(); List<File> fs = new ArrayList<File>(); fillResult(ps, fs); bp.set(ps, fs); bp.setUsesCustomLibs(customLibsButton.getSelection()); List<String> notUsed = new ArrayList<String>(); for (IPHPLibrary l : LibraryManager.getInstance().getAllLibraries()) { if (!libraryViewer.getChecked(l)) { notUsed.add(l.getId()); } } bp.setNotUsedLibrariesIds(notUsed); } private final class SelectAction implements SelectionListener { boolean select; private SelectAction(boolean doSelect) { this.select = doSelect; } public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { libraryViewer.setAllChecked(select); } } }