• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.launch;
18 
19 import com.android.ide.common.xml.ManifestData;
20 import com.android.ide.common.xml.ManifestData.Activity;
21 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
22 import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
23 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper;
24 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.IProjectChooserFilter;
25 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter;
26 
27 import org.eclipse.core.resources.IProject;
28 import org.eclipse.core.resources.IResource;
29 import org.eclipse.core.resources.IWorkspaceRoot;
30 import org.eclipse.core.resources.ResourcesPlugin;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.debug.core.ILaunchConfiguration;
33 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
34 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
35 import org.eclipse.debug.ui.ILaunchConfigurationTab;
36 import org.eclipse.jdt.core.IJavaModel;
37 import org.eclipse.jdt.core.IJavaProject;
38 import org.eclipse.jdt.core.JavaCore;
39 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.events.ModifyEvent;
42 import org.eclipse.swt.events.ModifyListener;
43 import org.eclipse.swt.events.SelectionAdapter;
44 import org.eclipse.swt.events.SelectionEvent;
45 import org.eclipse.swt.events.SelectionListener;
46 import org.eclipse.swt.graphics.Font;
47 import org.eclipse.swt.graphics.Image;
48 import org.eclipse.swt.layout.GridData;
49 import org.eclipse.swt.layout.GridLayout;
50 import org.eclipse.swt.widgets.Button;
51 import org.eclipse.swt.widgets.Combo;
52 import org.eclipse.swt.widgets.Composite;
53 import org.eclipse.swt.widgets.Group;
54 import org.eclipse.swt.widgets.Text;
55 
56 import java.util.ArrayList;
57 
58 /**
59  * Class for the main launch configuration tab.
60  */
61 public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
62 
63     /**
64      *
65      */
66     public static final String LAUNCH_TAB_IMAGE = "mainLaunchTab"; //$NON-NLS-1$
67 
68     protected static final String EMPTY_STRING = ""; //$NON-NLS-1$
69 
70     protected Text mProjText;
71     private Button mProjButton;
72 
73     private Combo mActivityCombo;
74     private final ArrayList<Activity> mActivities = new ArrayList<Activity>();
75 
76     private WidgetListener mListener = new WidgetListener();
77 
78     private Button mDefaultActionButton;
79     private Button mActivityActionButton;
80     private Button mDoNothingActionButton;
81     private int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
82 
83     private ProjectChooserHelper mProjectChooserHelper;
84 
85     /**
86      * A listener which handles widget change events for the controls in this
87      * tab.
88      */
89     private class WidgetListener implements ModifyListener, SelectionListener {
90 
91         @Override
modifyText(ModifyEvent e)92         public void modifyText(ModifyEvent e) {
93             IProject project = checkParameters();
94             loadActivities(project);
95             setDirty(true);
96         }
97 
98         @Override
widgetDefaultSelected(SelectionEvent e)99         public void widgetDefaultSelected(SelectionEvent e) {/* do nothing */
100         }
101 
102         @Override
widgetSelected(SelectionEvent e)103         public void widgetSelected(SelectionEvent e) {
104             Object source = e.getSource();
105             if (source == mProjButton) {
106                 handleProjectButtonSelected();
107             } else {
108                 checkParameters();
109             }
110         }
111     }
112 
MainLaunchConfigTab()113     public MainLaunchConfigTab() {
114     }
115 
getProjectFilter()116     protected IProjectChooserFilter getProjectFilter() {
117         return new NonLibraryProjectOnlyFilter();
118     }
119 
120     @Override
createControl(Composite parent)121     public void createControl(Composite parent) {
122         mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), getProjectFilter());
123 
124         Font font = parent.getFont();
125         Composite comp = new Composite(parent, SWT.NONE);
126         setControl(comp);
127         GridLayout topLayout = new GridLayout();
128         topLayout.verticalSpacing = 0;
129         comp.setLayout(topLayout);
130         comp.setFont(font);
131         createProjectEditor(comp);
132         createVerticalSpacer(comp, 1);
133 
134         // create the combo for the activity chooser
135         Group group = new Group(comp, SWT.NONE);
136         group.setText("Launch Action:");
137         GridData gd = new GridData(GridData.FILL_HORIZONTAL);
138         group.setLayoutData(gd);
139         GridLayout layout = new GridLayout();
140         layout.numColumns = 2;
141         group.setLayout(layout);
142         group.setFont(font);
143 
144         mDefaultActionButton = new Button(group, SWT.RADIO);
145         gd = new GridData(GridData.FILL_HORIZONTAL);
146         gd.horizontalSpan = 2;
147         mDefaultActionButton.setLayoutData(gd);
148         mDefaultActionButton.setText("Launch Default Activity");
149         mDefaultActionButton.addSelectionListener(new SelectionAdapter() {
150             @Override
151             public void widgetSelected(SelectionEvent e) {
152                 // event are received for both selection and deselection, so we only process
153                 // the selection event to avoid doing it twice.
154                 if (mDefaultActionButton.getSelection() == true) {
155                     mLaunchAction = LaunchConfigDelegate.ACTION_DEFAULT;
156                     mActivityCombo.setEnabled(false);
157                     checkParameters();
158                 }
159             }
160         });
161 
162         mActivityActionButton = new Button(group, SWT.RADIO);
163         mActivityActionButton.setText("Launch:");
164         mActivityActionButton.addSelectionListener(new SelectionAdapter() {
165             @Override
166             public void widgetSelected(SelectionEvent e) {
167                 // event are received for both selection and deselection, so we only process
168                 // the selection event to avoid doing it twice.
169                 if (mActivityActionButton.getSelection() == true) {
170                     mLaunchAction = LaunchConfigDelegate.ACTION_ACTIVITY;
171                     mActivityCombo.setEnabled(true);
172                     checkParameters();
173                 }
174             }
175         });
176 
177         mActivityCombo = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY);
178         gd = new GridData(GridData.FILL_HORIZONTAL);
179         mActivityCombo.setLayoutData(gd);
180         mActivityCombo.clearSelection();
181         mActivityCombo.setEnabled(false);
182         mActivityCombo.addSelectionListener(new SelectionAdapter() {
183             @Override
184             public void widgetSelected(SelectionEvent e) {
185                 checkParameters();
186             }
187         });
188 
189         mDoNothingActionButton = new Button(group, SWT.RADIO);
190         gd = new GridData(GridData.FILL_HORIZONTAL);
191         gd.horizontalSpan = 2;
192         mDoNothingActionButton.setLayoutData(gd);
193         mDoNothingActionButton.setText("Do Nothing");
194         mDoNothingActionButton.addSelectionListener(new SelectionAdapter() {
195             @Override
196             public void widgetSelected(SelectionEvent e) {
197                 // event are received for both selection and deselection, so we only process
198                 // the selection event to avoid doing it twice.
199                 if (mDoNothingActionButton.getSelection() == true) {
200                     mLaunchAction = LaunchConfigDelegate.ACTION_DO_NOTHING;
201                     mActivityCombo.setEnabled(false);
202                     checkParameters();
203                 }
204             }
205         });
206 
207     }
208 
209     @Override
getName()210     public String getName() {
211         return "Android";
212     }
213 
214     @Override
getImage()215     public Image getImage() {
216         return IconFactory.getInstance().getIcon(LAUNCH_TAB_IMAGE);
217     }
218 
219     @Override
performApply(ILaunchConfigurationWorkingCopy configuration)220     public void performApply(ILaunchConfigurationWorkingCopy configuration) {
221         configuration.setAttribute(
222                 IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, mProjText.getText());
223         configuration.setAttribute(
224                 IJavaLaunchConfigurationConstants.ATTR_ALLOW_TERMINATE, true);
225 
226         // add the launch mode
227         configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, mLaunchAction);
228 
229         // add the activity
230         int selection = mActivityCombo.getSelectionIndex();
231         if (mActivities != null && selection >=0 && selection < mActivities.size()) {
232             configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY,
233                     mActivities.get(selection).getName());
234         }
235 
236         // link the project and the launch config.
237         mapResources(configuration);
238     }
239 
240     @Override
setDefaults(ILaunchConfigurationWorkingCopy configuration)241     public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
242         configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
243                 LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION);
244     }
245 
246     /**
247      * Creates the widgets for specifying a main type.
248      *
249      * @param parent the parent composite
250      */
createProjectEditor(Composite parent)251     protected void createProjectEditor(Composite parent) {
252         Font font = parent.getFont();
253         Group group = new Group(parent, SWT.NONE);
254         group.setText("Project:");
255         GridData gd = new GridData(GridData.FILL_HORIZONTAL);
256         group.setLayoutData(gd);
257         GridLayout layout = new GridLayout();
258         layout.numColumns = 2;
259         group.setLayout(layout);
260         group.setFont(font);
261         mProjText = new Text(group, SWT.SINGLE | SWT.BORDER);
262         gd = new GridData(GridData.FILL_HORIZONTAL);
263         mProjText.setLayoutData(gd);
264         mProjText.setFont(font);
265         mProjText.addModifyListener(mListener);
266         mProjButton = createPushButton(group, "Browse...", null);
267         mProjButton.addSelectionListener(mListener);
268     }
269 
270     /**
271      * returns the default listener from this class. For all subclasses this
272      * listener will only provide the functi Jaonality of updating the current
273      * tab
274      *
275      * @return a widget listener
276      */
getDefaultListener()277     protected WidgetListener getDefaultListener() {
278         return mListener;
279     }
280 
281     /**
282      * Return the {@link IJavaProject} corresponding to the project name in the project
283      * name text field, or null if the text does not match a project name.
284      * @param javaModel the Java Model object corresponding for the current workspace root.
285      * @return a IJavaProject object or null.
286      */
getJavaProject(IJavaModel javaModel)287     protected IJavaProject getJavaProject(IJavaModel javaModel) {
288         String projectName = mProjText.getText().trim();
289         if (projectName.length() < 1) {
290             return null;
291         }
292         return javaModel.getJavaProject(projectName);
293     }
294 
295     /**
296      * Show a dialog that lets the user select a project. This in turn provides
297      * context for the main type, allowing the user to key a main type name, or
298      * constraining the search for main types to the specified project.
299      */
handleProjectButtonSelected()300     protected void handleProjectButtonSelected() {
301         IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
302                 mProjText.getText().trim(),
303                 "Please select a project to launch");
304         if (javaProject == null) {
305             return;
306         }// end if
307         String projectName = javaProject.getElementName();
308         mProjText.setText(projectName);
309 
310         // get the list of activities and fill the combo
311         IProject project = javaProject.getProject();
312         loadActivities(project);
313     }// end handle selected
314 
315     /**
316      * Initializes this tab's controls with values from the given
317      * launch configuration. This method is called when
318      * a configuration is selected to view or edit, after this
319      * tab's control has been created.
320      *
321      * @param config launch configuration
322      *
323      * @see ILaunchConfigurationTab
324      */
325     @Override
initializeFrom(ILaunchConfiguration config)326     public void initializeFrom(ILaunchConfiguration config) {
327         String projectName = EMPTY_STRING;
328         try {
329             projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
330                     EMPTY_STRING);
331         }// end try
332         catch (CoreException ce) {
333         }
334         mProjText.setText(projectName);
335 
336         IProject proj = mProjectChooserHelper.getAndroidProject(projectName);
337         loadActivities(proj);
338 
339         // load the launch action.
340         mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
341         try {
342             mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
343                     mLaunchAction);
344         } catch (CoreException e) {
345             // nothing to be done really. launchAction will keep its default value.
346         }
347 
348         mDefaultActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_DEFAULT);
349         mActivityActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY);
350         mDoNothingActionButton.setSelection(
351                 mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING);
352 
353         // now look for the activity and load it if present, otherwise, revert
354         // to the current one.
355         String activityName = EMPTY_STRING;
356         try {
357             activityName = config.getAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, EMPTY_STRING);
358         }// end try
359         catch (CoreException ce) {
360             // nothing to be done really. activityName will stay empty
361         }
362 
363         if (mLaunchAction != LaunchConfigDelegate.ACTION_ACTIVITY) {
364             mActivityCombo.setEnabled(false);
365             mActivityCombo.clearSelection();
366         } else {
367             mActivityCombo.setEnabled(true);
368             if (activityName == null || activityName.equals(EMPTY_STRING)) {
369                 mActivityCombo.clearSelection();
370             } else if (mActivities != null && mActivities.size() > 0) {
371                 // look for the name of the activity in the combo.
372                 boolean found = false;
373                 for (int i = 0 ; i < mActivities.size() ; i++) {
374                     if (activityName.equals(mActivities.get(i).getName())) {
375                         found = true;
376                         mActivityCombo.select(i);
377                         break;
378                     }
379                 }
380 
381                 // if we haven't found a matching activity we clear the combo selection
382                 if (found == false) {
383                     mActivityCombo.clearSelection();
384                 }
385             }
386         }
387     }
388 
389     /**
390      * Associates the launch config and the project. This allows Eclipse to delete the launch
391      * config when the project is deleted.
392      *
393      * @param config the launch config working copy.
394      */
mapResources(ILaunchConfigurationWorkingCopy config)395     protected void mapResources(ILaunchConfigurationWorkingCopy config) {
396         // get the java model
397         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
398         IJavaModel javaModel = JavaCore.create(workspaceRoot);
399 
400         // get the IJavaProject described by the text field.
401         IJavaProject javaProject = getJavaProject(javaModel);
402         IResource[] resources = null;
403         if (javaProject != null) {
404             resources = AndroidLaunchController.getResourcesToMap(javaProject.getProject());
405         }
406         config.setMappedResources(resources);
407     }
408 
409     /**
410      * Loads the ui with the activities of the specified project, and stores the
411      * activities in <code>mActivities</code>.
412      * <p/>
413      * First activity is selected by default if present.
414      *
415      * @param project The project to load the activities from.
416      */
loadActivities(IProject project)417     private void loadActivities(IProject project) {
418         if (project != null) {
419             // parse the manifest for the list of activities.
420             ManifestData manifestData = AndroidManifestHelper.parseForData(project);
421             if (manifestData != null) {
422                 Activity[] activities = manifestData.getActivities();
423 
424                 mActivities.clear();
425                 mActivityCombo.removeAll();
426 
427                 for (Activity activity : activities) {
428                     if (activity.isExported() && activity.hasAction()) {
429                         mActivities.add(activity);
430                         mActivityCombo.add(activity.getName());
431                     }
432                 }
433 
434                 if (mActivities.size() > 0) {
435                     if (mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY) {
436                         mActivityCombo.setEnabled(true);
437                     }
438                 } else {
439                     mActivityCombo.setEnabled(false);
440                 }
441 
442                 // the selection will be set when we update the ui from the current
443                 // config object.
444                 mActivityCombo.clearSelection();
445 
446                 return;
447             }
448         }
449 
450         // if we reach this point, either project is null, or we got an exception during
451         // the parsing. In either case, we empty the activity list.
452         mActivityCombo.removeAll();
453         mActivities.clear();
454     }
455 
456     /**
457      * Checks the parameters for correctness, and update the error message and buttons.
458      * @return the current IProject of this launch config.
459      */
checkParameters()460     private IProject checkParameters() {
461         try {
462             //test the project name first!
463             String text = mProjText.getText();
464             if (text.length() == 0) {
465                 setErrorMessage("Project Name is required!");
466             } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) {
467                 setErrorMessage("Project name contains unsupported characters!");
468             } else {
469                 IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null);
470                 IProject found = null;
471                 for (IJavaProject javaProject : projects) {
472                     if (javaProject.getProject().getName().equals(text)) {
473                         found = javaProject.getProject();
474                         break;
475                     }
476 
477                 }
478 
479                 if (found != null) {
480                     setErrorMessage(null);
481                 } else {
482                     setErrorMessage(String.format("There is no android project named '%1$s'",
483                             text));
484                 }
485 
486                 return found;
487             }
488         } finally {
489             updateLaunchConfigurationDialog();
490         }
491 
492         return null;
493     }
494 }
495