Home | History | Annotate | Download | only in refactoring
      1 /*
      2  * Copyright (C) 2011 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.editors.layout.refactoring;
     18 
     19 import static com.android.SdkConstants.FQCN_GESTURE_OVERLAY_VIEW;
     20 import static com.android.SdkConstants.FQCN_LINEAR_LAYOUT;
     21 import static com.android.SdkConstants.FQCN_RADIO_BUTTON;
     22 import static com.android.SdkConstants.GESTURE_OVERLAY_VIEW;
     23 import static com.android.SdkConstants.RADIO_GROUP;
     24 import static com.android.SdkConstants.VIEW_INCLUDE;
     25 
     26 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
     27 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
     28 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder;
     29 import com.android.ide.eclipse.adt.internal.editors.layout.gre.PaletteMetadataDescriptor;
     30 import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
     31 import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
     32 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
     33 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
     34 import com.android.resources.ResourceType;
     35 import com.android.sdklib.IAndroidTarget;
     36 import com.android.utils.Pair;
     37 
     38 import org.eclipse.core.resources.IProject;
     39 import org.eclipse.swt.SWT;
     40 import org.eclipse.swt.layout.GridData;
     41 import org.eclipse.swt.layout.GridLayout;
     42 import org.eclipse.swt.widgets.Combo;
     43 import org.eclipse.swt.widgets.Composite;
     44 import org.eclipse.swt.widgets.Label;
     45 import org.eclipse.swt.widgets.Text;
     46 
     47 import java.util.ArrayList;
     48 import java.util.Collections;
     49 import java.util.List;
     50 import java.util.Set;
     51 
     52 public class WrapInWizard extends VisualRefactoringWizard {
     53     private static final String SEPARATOR_LABEL =
     54         "----------------------------------------"; //$NON-NLS-1$
     55 
     56     public WrapInWizard(WrapInRefactoring ref, LayoutEditorDelegate editor) {
     57         super(ref, editor);
     58         setDefaultPageTitle("Wrap in Container");
     59     }
     60 
     61     @Override
     62     protected void addUserInputPages() {
     63         WrapInRefactoring ref = (WrapInRefactoring) getRefactoring();
     64         String oldType = ref.getOldType();
     65         addPage(new InputPage(mDelegate.getEditor().getProject(), oldType));
     66     }
     67 
     68     /** Wizard page which inputs parameters for the {@link WrapInRefactoring} operation */
     69     private static class InputPage extends VisualRefactoringInputPage {
     70         private final IProject mProject;
     71         private final String mOldType;
     72         private Text mIdText;
     73         private Combo mTypeCombo;
     74         private List<Pair<String, ViewElementDescriptor>> mClassNames;
     75 
     76         public InputPage(IProject project, String oldType) {
     77             super("WrapInInputPage");  //$NON-NLS-1$
     78             mProject = project;
     79             mOldType = oldType;
     80         }
     81 
     82         @Override
     83         public void createControl(Composite parent) {
     84             Composite composite = new Composite(parent, SWT.NONE);
     85             composite.setLayout(new GridLayout(2, false));
     86 
     87             Label typeLabel = new Label(composite, SWT.NONE);
     88             typeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
     89             typeLabel.setText("Type of Container:");
     90 
     91             mTypeCombo = new Combo(composite, SWT.READ_ONLY);
     92             mTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
     93             mTypeCombo.addSelectionListener(mSelectionValidateListener);
     94 
     95             Label idLabel = new Label(composite, SWT.NONE);
     96             idLabel.setText("New Layout Id:");
     97             idLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
     98 
     99             mIdText = new Text(composite, SWT.BORDER);
    100             mIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
    101             mIdText.addModifyListener(mModifyValidateListener);
    102 
    103             Set<String> exclude = Collections.singleton(VIEW_INCLUDE);
    104             mClassNames = addLayouts(mProject, mOldType, mTypeCombo, exclude, true);
    105             mTypeCombo.select(0);
    106 
    107             setControl(composite);
    108             validatePage();
    109 
    110             mTypeCombo.setFocus();
    111         }
    112 
    113         @Override
    114         protected boolean validatePage() {
    115             boolean ok = true;
    116 
    117             String id = mIdText.getText().trim();
    118 
    119             if (id.length() == 0) {
    120                 setErrorMessage("ID required");
    121                 ok = false;
    122             } else {
    123                 // ...but if you do, it has to be valid!
    124                 ResourceNameValidator validator = ResourceNameValidator.create(false, mProject,
    125                         ResourceType.ID);
    126                 String message = validator.isValid(id);
    127                 if (message != null) {
    128                     setErrorMessage(message);
    129                     ok = false;
    130                 }
    131             }
    132 
    133             int selectionIndex = mTypeCombo.getSelectionIndex();
    134             String type = selectionIndex != -1 ? mClassNames.get(selectionIndex).getFirst() : null;
    135             if (type == null) {
    136                 setErrorMessage("Select a container type");
    137                 ok = false; // The user has chosen a separator
    138             }
    139 
    140             if (ok) {
    141                 setErrorMessage(null);
    142 
    143                 // Record state
    144                 WrapInRefactoring refactoring =
    145                     (WrapInRefactoring) getRefactoring();
    146                 refactoring.setId(id);
    147                 refactoring.setType(type);
    148 
    149                 ViewElementDescriptor descriptor = mClassNames.get(selectionIndex).getSecond();
    150                 if (descriptor instanceof PaletteMetadataDescriptor) {
    151                     PaletteMetadataDescriptor paletteDescriptor =
    152                         (PaletteMetadataDescriptor) descriptor;
    153                     String initializedAttributes = paletteDescriptor.getInitializedAttributes();
    154                     refactoring.setInitializedAttributes(initializedAttributes);
    155                 } else {
    156                     refactoring.setInitializedAttributes(null);
    157                 }
    158             }
    159 
    160             setPageComplete(ok);
    161             return ok;
    162         }
    163     }
    164 
    165     static List<Pair<String, ViewElementDescriptor>> addLayouts(IProject project,
    166             String oldType, Combo combo,
    167             Set<String> exclude, boolean addGestureOverlay) {
    168         List<Pair<String, ViewElementDescriptor>> classNames =
    169             new ArrayList<Pair<String, ViewElementDescriptor>>();
    170 
    171         if (oldType != null && oldType.equals(FQCN_RADIO_BUTTON)) {
    172             combo.add(RADIO_GROUP);
    173             // NOT a fully qualified name since android widgets do not include the package
    174             classNames.add(Pair.of(RADIO_GROUP, (ViewElementDescriptor) null));
    175 
    176             combo.add(SEPARATOR_LABEL);
    177             classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
    178         }
    179 
    180         Pair<List<String>,List<String>> result = CustomViewFinder.findViews(project, true);
    181         List<String> customViews = result.getFirst();
    182         List<String> thirdPartyViews = result.getSecond();
    183         if (customViews.size() > 0) {
    184             for (String view : customViews) {
    185                 combo.add(view);
    186                 classNames.add(Pair.of(view, (ViewElementDescriptor) null));
    187             }
    188             combo.add(SEPARATOR_LABEL);
    189             classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
    190         }
    191 
    192         // Populate type combo
    193         Sdk currentSdk = Sdk.getCurrent();
    194         if (currentSdk != null) {
    195             IAndroidTarget target = currentSdk.getTarget(project);
    196             if (target != null) {
    197                 AndroidTargetData targetData = currentSdk.getTargetData(target);
    198                 if (targetData != null) {
    199                     ViewMetadataRepository repository = ViewMetadataRepository.get();
    200                     List<Pair<String,List<ViewElementDescriptor>>> entries =
    201                         repository.getPaletteEntries(targetData, false, true);
    202                     // Find the layout category - it contains LinearLayout
    203                     List<ViewElementDescriptor> layoutDescriptors = null;
    204 
    205                     search: for (Pair<String,List<ViewElementDescriptor>> pair : entries) {
    206                         List<ViewElementDescriptor> list = pair.getSecond();
    207                         for (ViewElementDescriptor d : list) {
    208                             if (d.getFullClassName().equals(FQCN_LINEAR_LAYOUT)) {
    209                                 // Found - use this list
    210                                 layoutDescriptors = list;
    211                                 break search;
    212                             }
    213                         }
    214                     }
    215                     if (layoutDescriptors != null) {
    216                         for (ViewElementDescriptor d : layoutDescriptors) {
    217                             String className = d.getFullClassName();
    218                             if (exclude == null || !exclude.contains(className)) {
    219                                 combo.add(d.getUiName());
    220                                 classNames.add(Pair.of(className, d));
    221                             }
    222                         }
    223 
    224                         // SWT does not support separators in combo boxes
    225                         combo.add(SEPARATOR_LABEL);
    226                         classNames.add(null);
    227 
    228                         if (thirdPartyViews.size() > 0) {
    229                             for (String view : thirdPartyViews) {
    230                                 combo.add(view);
    231                                 classNames.add(Pair.of(view, (ViewElementDescriptor) null));
    232                             }
    233                             combo.add(SEPARATOR_LABEL);
    234                             classNames.add(null);
    235                         }
    236 
    237                         if (addGestureOverlay) {
    238                             combo.add(GESTURE_OVERLAY_VIEW);
    239                             classNames.add(Pair.<String, ViewElementDescriptor> of(
    240                                     FQCN_GESTURE_OVERLAY_VIEW, null));
    241 
    242                             combo.add(SEPARATOR_LABEL);
    243                             classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
    244                         }
    245                     }
    246 
    247                     // Now add ALL known layout descriptors in case the user has
    248                     // a special case
    249                     layoutDescriptors =
    250                         targetData.getLayoutDescriptors().getLayoutDescriptors();
    251 
    252                     for (ViewElementDescriptor d : layoutDescriptors) {
    253                         String className = d.getFullClassName();
    254                         if (exclude == null || !exclude.contains(className)) {
    255                             combo.add(d.getUiName());
    256                             classNames.add(Pair.of(className, d));
    257                         }
    258                     }
    259                 }
    260             }
    261         } else {
    262             combo.add("SDK not initialized");
    263             classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
    264         }
    265 
    266         return classNames;
    267     }
    268 }
    269