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