| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php |
| * |
| * 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 com.android.ide.eclipse.adt.internal.wizards.newproject; |
| |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.tools.lint.detector.api.LintUtils; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.viewers.CellEditor; |
| import org.eclipse.jface.viewers.CellLabelProvider; |
| import org.eclipse.jface.viewers.CheckStateChangedEvent; |
| import org.eclipse.jface.viewers.CheckboxTableViewer; |
| import org.eclipse.jface.viewers.ColumnViewer; |
| import org.eclipse.jface.viewers.EditingSupport; |
| import org.eclipse.jface.viewers.ICheckStateListener; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.TableViewerColumn; |
| import org.eclipse.jface.viewers.TextCellEditor; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerCell; |
| import org.eclipse.jface.wizard.IWizardPage; |
| import org.eclipse.jface.wizard.WizardPage; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.ControlListener; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.events.TraverseListener; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Rectangle; |
| 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.Label; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableColumn; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkingSet; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** WizardPage for importing Android projects */ |
| class ImportPage extends WizardPage implements SelectionListener, IStructuredContentProvider, |
| ICheckStateListener, KeyListener, TraverseListener, ControlListener { |
| private static final int DIR_COLUMN = 0; |
| private static final int NAME_COLUMN = 1; |
| |
| private final NewProjectWizardState mValues; |
| private List<ImportedProject> mProjectPaths; |
| private final IProject[] mExistingProjects; |
| |
| private Text mDir; |
| private Button mBrowseButton; |
| private Button mCopyCheckBox; |
| private Button mRefreshButton; |
| private Button mDeselectAllButton; |
| private Button mSelectAllButton; |
| private Table mTable; |
| private CheckboxTableViewer mCheckboxTableViewer; |
| private WorkingSetGroup mWorkingSetGroup; |
| |
| ImportPage(NewProjectWizardState values) { |
| super("importPage"); //$NON-NLS-1$ |
| mValues = values; |
| setTitle("Import Projects"); |
| setDescription("Select a directory to search for existing Android projects"); |
| mWorkingSetGroup = new WorkingSetGroup(); |
| setWorkingSets(new IWorkingSet[0]); |
| |
| // Record all projects such that we can ensure that the project names are unique |
| IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); |
| mExistingProjects = workspaceRoot.getProjects(); |
| } |
| |
| public void init(IStructuredSelection selection, IWorkbenchPart activePart) { |
| setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart)); |
| } |
| |
| @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused |
| @Override |
| public void createControl(Composite parent) { |
| Composite container = new Composite(parent, SWT.NULL); |
| setControl(container); |
| container.setLayout(new GridLayout(3, false)); |
| |
| Label directoryLabel = new Label(container, SWT.NONE); |
| directoryLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); |
| directoryLabel.setText("Root Directory:"); |
| |
| mDir = new Text(container, SWT.BORDER); |
| mDir.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); |
| mDir.addKeyListener(this); |
| mDir.addTraverseListener(this); |
| |
| mBrowseButton = new Button(container, SWT.NONE); |
| mBrowseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); |
| mBrowseButton.setText("Browse..."); |
| mBrowseButton.addSelectionListener(this); |
| |
| Label projectsLabel = new Label(container, SWT.NONE); |
| projectsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); |
| projectsLabel.setText("Projects:"); |
| |
| mTable = new Table(container, SWT.CHECK); |
| mTable.setHeaderVisible(true); |
| mCheckboxTableViewer = new CheckboxTableViewer(mTable); |
| |
| TableViewerColumn dirViewerColumn = new TableViewerColumn(mCheckboxTableViewer, SWT.NONE); |
| TableColumn dirColumn = dirViewerColumn.getColumn(); |
| dirColumn.setWidth(200); |
| dirColumn.setText("Project to Import"); |
| TableViewerColumn nameViewerColumn = new TableViewerColumn(mCheckboxTableViewer, SWT.NONE); |
| TableColumn nameColumn = nameViewerColumn.getColumn(); |
| nameColumn.setWidth(200); |
| nameColumn.setText("New Project Name"); |
| nameViewerColumn.setEditingSupport(new ProjectNameEditingSupport(mCheckboxTableViewer)); |
| |
| mTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 4)); |
| mTable.setLinesVisible(true); |
| mTable.setHeaderVisible(true); |
| mTable.addSelectionListener(this); |
| mTable.addControlListener(this); |
| mCheckboxTableViewer.setContentProvider(this); |
| mCheckboxTableViewer.setInput(this); |
| mCheckboxTableViewer.addCheckStateListener(this); |
| mCheckboxTableViewer.setLabelProvider(new ProjectCellLabelProvider()); |
| |
| mSelectAllButton = new Button(container, SWT.NONE); |
| mSelectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); |
| mSelectAllButton.setText("Select All"); |
| mSelectAllButton.addSelectionListener(this); |
| |
| mDeselectAllButton = new Button(container, SWT.NONE); |
| mDeselectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); |
| mDeselectAllButton.setText("Deselect All"); |
| mDeselectAllButton.addSelectionListener(this); |
| |
| mRefreshButton = new Button(container, SWT.NONE); |
| mRefreshButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); |
| mRefreshButton.setText("Refresh"); |
| mRefreshButton.addSelectionListener(this); |
| new Label(container, SWT.NONE); |
| |
| mCopyCheckBox = new Button(container, SWT.CHECK); |
| mCopyCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); |
| mCopyCheckBox.setText("Copy projects into workspace"); |
| mCopyCheckBox.addSelectionListener(this); |
| |
| Composite group = mWorkingSetGroup.createControl(container); |
| group.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1)); |
| |
| updateColumnWidths(); |
| } |
| |
| private void updateColumnWidths() { |
| Rectangle r = mTable.getClientArea(); |
| int availableWidth = r.width; |
| // Add all available size to the first column |
| for (int i = 1; i < mTable.getColumnCount(); i++) { |
| TableColumn column = mTable.getColumn(i); |
| availableWidth -= column.getWidth(); |
| } |
| if (availableWidth > 100) { |
| mTable.getColumn(0).setWidth(availableWidth); |
| } |
| } |
| |
| @Override |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| validatePage(); |
| } |
| |
| private void refresh() { |
| File root = new File(mDir.getText().trim()); |
| mProjectPaths = searchForProjects(root); |
| mCheckboxTableViewer.refresh(); |
| mCheckboxTableViewer.setAllChecked(true); |
| |
| updateValidity(); |
| validatePage(); |
| } |
| |
| private void updateValidity(){ |
| List<ImportedProject> selected = new ArrayList<ImportedProject>(); |
| List<ImportedProject> disabled = new ArrayList<ImportedProject>(); |
| for (ImportedProject project : mProjectPaths) { |
| String projectName = project.getProjectName(); |
| boolean invalid = false; |
| for (IProject existingProject : mExistingProjects) { |
| if (projectName.equals(existingProject.getName())) { |
| invalid = true; |
| break; |
| } |
| } |
| if (invalid) { |
| disabled.add(project); |
| } else { |
| selected.add(project); |
| } |
| } |
| |
| mValues.importProjects = selected; |
| |
| mCheckboxTableViewer.setGrayedElements(disabled.toArray()); |
| mCheckboxTableViewer.setCheckedElements(selected.toArray()); |
| mCheckboxTableViewer.refresh(); |
| mCheckboxTableViewer.getTable().setFocus(); |
| } |
| |
| private List<ImportedProject> searchForProjects(File dir) { |
| List<ImportedProject> projects = new ArrayList<ImportedProject>(); |
| addProjects(dir, projects, dir.getPath().length() + 1); |
| return projects; |
| } |
| |
| /** Finds all project directories under the given directory */ |
| private void addProjects(File dir, List<ImportedProject> projects, int prefixLength) { |
| if (dir.isDirectory()) { |
| if (LintUtils.isManifestFolder(dir)) { |
| String relative = dir.getPath(); |
| if (relative.length() > prefixLength) { |
| relative = relative.substring(prefixLength); |
| } |
| projects.add(new ImportedProject(dir, relative)); |
| } |
| |
| File[] children = dir.listFiles(); |
| if (children != null) { |
| for (File child : children) { |
| addProjects(child, projects, prefixLength); |
| } |
| } |
| } |
| } |
| |
| private void validatePage() { |
| IStatus status = null; |
| |
| // Validate project name -- unless we're creating a sample, in which case |
| // the user will get a chance to pick the name on the Sample page |
| if (mProjectPaths == null || mProjectPaths.isEmpty()) { |
| status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, |
| "Select a directory to search for existing Android projects"); |
| } else if (mValues.importProjects == null || mValues.importProjects.isEmpty()) { |
| status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, |
| "Select at least one project"); |
| } else { |
| for (ImportedProject project : mValues.importProjects) { |
| if (mCheckboxTableViewer.getGrayed(project)) { |
| status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, |
| String.format("Cannot import %1$s because the project name is in use", |
| project.getProjectName())); |
| break; |
| } else { |
| status = ProjectNamePage.validateProjectName(project.getProjectName()); |
| if (status != null && !status.isOK()) { |
| // Need to insert project name to make it clear which project name |
| // is in violation |
| if (mValues.importProjects.size() > 1) { |
| String message = String.format("%1$s: %2$s", |
| project.getProjectName(), status.getMessage()); |
| status = new Status(status.getSeverity(), AdtPlugin.PLUGIN_ID, |
| message); |
| } |
| break; |
| } else { |
| status = null; // Don't leave non null status with isOK() == true |
| } |
| } |
| } |
| } |
| |
| // -- update UI & enable finish if there's no error |
| setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); |
| if (status != null) { |
| setMessage(status.getMessage(), |
| status.getSeverity() == IStatus.ERROR |
| ? IMessageProvider.ERROR : IMessageProvider.WARNING); |
| } else { |
| setErrorMessage(null); |
| setMessage(null); |
| } |
| } |
| |
| /** |
| * Returns the working sets to which the new project should be added. |
| * |
| * @return the selected working sets to which the new project should be added |
| */ |
| private IWorkingSet[] getWorkingSets() { |
| return mWorkingSetGroup.getSelectedWorkingSets(); |
| } |
| |
| /** |
| * Sets the working sets to which the new project should be added. |
| * |
| * @param workingSets the initial selected working sets |
| */ |
| private void setWorkingSets(IWorkingSet[] workingSets) { |
| assert workingSets != null; |
| mWorkingSetGroup.setWorkingSets(workingSets); |
| } |
| |
| @Override |
| public IWizardPage getNextPage() { |
| // Sync working set data to the value object, since the WorkingSetGroup |
| // doesn't let us add listeners to do this lazily |
| mValues.workingSets = getWorkingSets(); |
| |
| return super.getNextPage(); |
| } |
| |
| // ---- Implements SelectionListener ---- |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| Object source = e.getSource(); |
| if (source == mBrowseButton) { |
| // Choose directory |
| DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN); |
| String path = mDir.getText().trim(); |
| if (path.length() > 0) { |
| dialog.setFilterPath(path); |
| } |
| String file = dialog.open(); |
| if (file != null) { |
| mDir.setText(file); |
| refresh(); |
| } |
| } else if (source == mSelectAllButton) { |
| mCheckboxTableViewer.setAllChecked(true); |
| mValues.importProjects = mProjectPaths; |
| } else if (source == mDeselectAllButton) { |
| mCheckboxTableViewer.setAllChecked(false); |
| mValues.importProjects = Collections.emptyList(); |
| } else if (source == mRefreshButton || source == mDir) { |
| refresh(); |
| } else if (source == mCopyCheckBox) { |
| mValues.copyIntoWorkspace = mCopyCheckBox.getSelection(); |
| } |
| |
| validatePage(); |
| } |
| |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| |
| // ---- KeyListener ---- |
| |
| @Override |
| public void keyPressed(KeyEvent e) { |
| if (e.getSource() == mDir) { |
| if (e.keyCode == SWT.CR) { |
| refresh(); |
| } |
| } |
| } |
| |
| @Override |
| public void keyReleased(KeyEvent e) { |
| } |
| |
| // ---- TraverseListener ---- |
| |
| @Override |
| public void keyTraversed(TraverseEvent e) { |
| // Prevent Return from running through the wizard; return is handled by |
| // key listener to refresh project list instead |
| if (SWT.TRAVERSE_RETURN == e.detail) { |
| e.doit = false; |
| } |
| } |
| |
| // ---- Implements IStructuredContentProvider ---- |
| |
| @Override |
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { |
| } |
| |
| @Override |
| public Object[] getElements(Object inputElement) { |
| return mProjectPaths != null ? mProjectPaths.toArray() : new Object[0]; |
| } |
| |
| // ---- Implements ICheckStateListener ---- |
| |
| @Override |
| public void checkStateChanged(CheckStateChangedEvent event) { |
| // Try to disable other elements that conflict with this |
| Object[] checked = mCheckboxTableViewer.getCheckedElements(); |
| List<ImportedProject> selected = new ArrayList<ImportedProject>(checked.length); |
| for (Object o : checked) { |
| if (!mCheckboxTableViewer.getGrayed(o)) { |
| selected.add((ImportedProject) o); |
| } |
| } |
| mValues.importProjects = selected; |
| validatePage(); |
| |
| mCheckboxTableViewer.update(event.getElement(), null); |
| } |
| |
| // ---- Implements ControlListener ---- |
| |
| @Override |
| public void controlMoved(ControlEvent e) { |
| } |
| |
| @Override |
| public void controlResized(ControlEvent e) { |
| updateColumnWidths(); |
| } |
| |
| private final class ProjectCellLabelProvider extends CellLabelProvider { |
| @Override |
| public void update(ViewerCell cell) { |
| Object element = cell.getElement(); |
| int index = cell.getColumnIndex(); |
| ImportedProject project = (ImportedProject) element; |
| |
| Display display = mTable.getDisplay(); |
| Color fg; |
| if (mCheckboxTableViewer.getGrayed(element)) { |
| fg = display.getSystemColor(SWT.COLOR_DARK_GRAY); |
| } else { |
| fg = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND); |
| } |
| cell.setForeground(fg); |
| cell.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); |
| |
| switch (index) { |
| case DIR_COLUMN: { |
| // Directory name |
| cell.setText(project.getRelativePath()); |
| return; |
| } |
| |
| case NAME_COLUMN: { |
| // New name |
| cell.setText(project.getProjectName()); |
| return; |
| } |
| default: |
| assert false : index; |
| } |
| cell.setText(""); |
| } |
| } |
| |
| /** Editing support for the project name column */ |
| private class ProjectNameEditingSupport extends EditingSupport { |
| private ProjectNameEditingSupport(ColumnViewer viewer) { |
| super(viewer); |
| } |
| |
| @Override |
| protected void setValue(Object element, Object value) { |
| ImportedProject project = (ImportedProject) element; |
| project.setProjectName(value.toString()); |
| mCheckboxTableViewer.update(element, null); |
| updateValidity(); |
| validatePage(); |
| } |
| |
| @Override |
| protected Object getValue(Object element) { |
| ImportedProject project = (ImportedProject) element; |
| return project.getProjectName(); |
| } |
| |
| @Override |
| protected CellEditor getCellEditor(Object element) { |
| return new TextCellEditor(mTable); |
| } |
| |
| @Override |
| protected boolean canEdit(Object element) { |
| return true; |
| } |
| } |
| } |