1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.adt.internal.project;
18 
19 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper.IProjectFilter;
20 import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
21 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
22 
23 import org.eclipse.core.resources.IProject;
24 import org.eclipse.core.resources.IWorkspaceRoot;
25 import org.eclipse.core.resources.ResourcesPlugin;
26 import org.eclipse.jdt.core.IJavaModel;
27 import org.eclipse.jdt.core.IJavaProject;
28 import org.eclipse.jdt.core.JavaCore;
29 import org.eclipse.jdt.ui.JavaElementLabelProvider;
30 import org.eclipse.jface.viewers.ILabelProvider;
31 import org.eclipse.jface.window.Window;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.SelectionEvent;
34 import org.eclipse.swt.events.SelectionListener;
35 import org.eclipse.swt.widgets.Combo;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Shell;
38 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
39 
40 /**
41  * Helper class to deal with displaying a project choosing dialog that lists only the
42  * projects with the Android nature.
43  */
44 public class ProjectChooserHelper {
45 
46     private final Shell mParentShell;
47     private final IProjectChooserFilter mFilter;
48 
49     /**
50      * List of current android projects. Since the dialog is modal, we'll just get
51      * the list once on-demand.
52      */
53     private IJavaProject[] mAndroidProjects;
54 
55     /**
56      * Interface to filter out some project displayed by {@link ProjectChooserHelper}.
57      *
58      * @see IProjectFilter
59      */
60     public interface IProjectChooserFilter extends IProjectFilter {
61         /**
62          * Whether the Project Chooser can compute the project list once and cache the result.
63          * </p>If false the project list is recomputed every time the dialog is opened.
64          */
useCache()65         boolean useCache();
66     }
67 
68     /**
69      * An implementation of {@link IProjectChooserFilter} that only displays non-library projects.
70      */
71     public final static class NonLibraryProjectOnlyFilter implements IProjectChooserFilter {
72         @Override
accept(IProject project)73         public boolean accept(IProject project) {
74             ProjectState state = Sdk.getProjectState(project);
75             if (state != null) {
76                 return state.isLibrary() == false;
77             }
78 
79             return false;
80         }
81 
82         @Override
useCache()83         public boolean useCache() {
84             return true;
85         }
86     }
87 
88     /**
89      * An implementation of {@link IProjectChooserFilter} that only displays library projects.
90      */
91     public final static class LibraryProjectOnlyFilter implements IProjectChooserFilter {
92         @Override
accept(IProject project)93         public boolean accept(IProject project) {
94             ProjectState state = Sdk.getProjectState(project);
95             if (state != null ) {
96                 return state.isLibrary();
97             }
98 
99             return false;
100         }
101 
102         @Override
useCache()103         public boolean useCache() {
104             return true;
105         }
106     }
107 
108     /**
109      * Creates a new project chooser.
110      * @param parentShell the parent {@link Shell} for the dialog.
111      * @param filter a filter to only accept certain projects. Can be null.
112      */
ProjectChooserHelper(Shell parentShell, IProjectChooserFilter filter)113     public ProjectChooserHelper(Shell parentShell, IProjectChooserFilter filter) {
114         mParentShell = parentShell;
115         mFilter = filter;
116     }
117 
118     /**
119      * Displays a project chooser dialog which lists all available projects with the Android nature.
120      * <p/>
121      * The list of project is built from Android flagged projects currently opened in the workspace.
122      *
123      * @param projectName If non null and not empty, represents the name of an Android project
124      *                    that will be selected by default.
125      * @param message Message for the dialog box. Can be null in which case a default message
126      *                is displayed.
127      * @return the project chosen by the user in the dialog, or null if the dialog was canceled.
128      */
chooseJavaProject(String projectName, String message)129     public IJavaProject chooseJavaProject(String projectName, String message) {
130         ILabelProvider labelProvider = new JavaElementLabelProvider(
131                 JavaElementLabelProvider.SHOW_DEFAULT);
132         ElementListSelectionDialog dialog = new ElementListSelectionDialog(
133                 mParentShell, labelProvider);
134         dialog.setTitle("Project Selection");
135         if (message == null) {
136             message = "Please select a project";
137         }
138         dialog.setMessage(message);
139 
140         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
141         IJavaModel javaModel = JavaCore.create(workspaceRoot);
142 
143         // set the elements in the dialog. These are opened android projects.
144         dialog.setElements(getAndroidProjects(javaModel));
145 
146         // look for the project matching the given project name
147         IJavaProject javaProject = null;
148         if (projectName != null && projectName.length() > 0) {
149             javaProject = javaModel.getJavaProject(projectName);
150         }
151 
152         // if we found it, we set the initial selection in the dialog to this one.
153         if (javaProject != null) {
154             dialog.setInitialSelections(new Object[] { javaProject });
155         }
156 
157         // open the dialog and return the object selected if OK was clicked, or null otherwise
158         if (dialog.open() == Window.OK) {
159             return (IJavaProject) dialog.getFirstResult();
160         }
161         return null;
162     }
163 
164     /**
165      * Returns the list of Android projects.
166      * <p/>
167      * Because this list can be time consuming, this class caches the list of project.
168      * It is recommended to call this method instead of
169      * {@link BaseProjectHelper#getAndroidProjects()}.
170      *
171      * @param javaModel the java model. Can be null.
172      */
getAndroidProjects(IJavaModel javaModel)173     public IJavaProject[] getAndroidProjects(IJavaModel javaModel) {
174         // recompute only if we don't have the projects already or the filter is dynamic
175         // and prevent usage of a cache.
176         if (mAndroidProjects == null || (mFilter != null && mFilter.useCache() == false)) {
177             if (javaModel == null) {
178                 mAndroidProjects = BaseProjectHelper.getAndroidProjects(mFilter);
179             } else {
180                 mAndroidProjects = BaseProjectHelper.getAndroidProjects(javaModel, mFilter);
181             }
182         }
183 
184         return mAndroidProjects;
185     }
186 
187     /**
188      * Helper method to get the Android project with the given name
189      *
190      * @param projectName the name of the project to find
191      * @return the {@link IProject} for the Android project. <code>null</code> if not found.
192      */
getAndroidProject(String projectName)193     public IProject getAndroidProject(String projectName) {
194         IProject iproject = null;
195         IJavaProject[] javaProjects = getAndroidProjects(null);
196         if (javaProjects != null) {
197             for (IJavaProject javaProject : javaProjects) {
198                 if (javaProject.getElementName().equals(projectName)) {
199                     iproject = javaProject.getProject();
200                     break;
201                 }
202             }
203         }
204         return iproject;
205     }
206 
207     /**
208      * A selector combo for showing the currently selected project and for
209      * changing the selection
210      */
211     public static class ProjectCombo extends Combo implements SelectionListener {
212         /** Currently chosen project, or null when no project has been initialized or selected */
213         private IProject mProject;
214         private IJavaProject[] mAvailableProjects;
215 
216         /**
217          * Creates a new project selector combo
218          *
219          * @param helper associated {@link ProjectChooserHelper} for looking up
220          *            projects
221          * @param parent parent composite to add the combo to
222          * @param initialProject the initial project to select, or null (which
223          *            will show a "Please Choose Project..." label instead.)
224          */
ProjectCombo(ProjectChooserHelper helper, Composite parent, IProject initialProject)225         public ProjectCombo(ProjectChooserHelper helper, Composite parent,
226                 IProject initialProject) {
227             super(parent, SWT.BORDER | SWT.FLAT | SWT.READ_ONLY);
228             mProject = initialProject;
229 
230             mAvailableProjects = helper.getAndroidProjects(null);
231             String[] items = new String[mAvailableProjects.length + 1];
232             items[0] = "--- Choose Project ---";
233 
234             ILabelProvider labelProvider = new JavaElementLabelProvider(
235                     JavaElementLabelProvider.SHOW_DEFAULT);
236             int selectionIndex = 0;
237             for (int i = 0, n = mAvailableProjects.length; i < n; i++) {
238                 IProject project = mAvailableProjects[i].getProject();
239                 items[i + 1] = labelProvider.getText(project);
240                 if (project == initialProject) {
241                     selectionIndex = i + 1;
242                 }
243             }
244             setItems(items);
245             select(selectionIndex);
246 
247             addSelectionListener(this);
248         }
249 
250         /**
251          * Returns the project selected by this chooser (or the initial project
252          * passed to the constructor if the user did not change it)
253          *
254          * @return the selected project
255          */
getSelectedProject()256         public IProject getSelectedProject() {
257             return mProject;
258         }
259 
260         /**
261          * Sets the project selected by this chooser
262          *
263          * @param project the selected project
264          */
setSelectedProject(IProject project)265         public void setSelectedProject(IProject project) {
266             mProject = project;
267 
268             int selectionIndex = 0;
269             for (int i = 0, n = mAvailableProjects.length; i < n; i++) {
270                 if (project == mAvailableProjects[i].getProject()) {
271                     selectionIndex = i + 1; // +1: Slot 0 is reserved for "Choose Project"
272                     select(selectionIndex);
273                     break;
274                 }
275             }
276         }
277 
278         /**
279          * Click handler for the button: Open the {@link ProjectChooserHelper}
280          * dialog for selecting a new project.
281          */
282         @Override
widgetSelected(SelectionEvent e)283         public void widgetSelected(SelectionEvent e) {
284             int selectionIndex = getSelectionIndex();
285             if (selectionIndex > 0 && mAvailableProjects != null
286                     && selectionIndex <= mAvailableProjects.length) {
287                 // selection index 0 is "Choose Project", all other projects are offset
288                 // by 1 from the selection index
289                 mProject = mAvailableProjects[selectionIndex - 1].getProject();
290             } else {
291                 mProject = null;
292             }
293         }
294 
295         @Override
widgetDefaultSelected(SelectionEvent e)296         public void widgetDefaultSelected(SelectionEvent e) {
297         }
298 
299         @Override
checkSubclass()300         protected void checkSubclass() {
301             // Disable the check that prevents subclassing of SWT components
302         }
303     }
304 }
305