diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java | 762 |
1 files changed, 762 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java new file mode 100644 index 000000000..388907a46 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2011 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.editors.layout.gre; + +import static com.android.SdkConstants.ANDROID_URI; +import static com.android.SdkConstants.ATTR_ID; +import static com.android.SdkConstants.AUTO_URI; +import static com.android.SdkConstants.CLASS_FRAGMENT; +import static com.android.SdkConstants.CLASS_V4_FRAGMENT; +import static com.android.SdkConstants.CLASS_VIEW; +import static com.android.SdkConstants.NEW_ID_PREFIX; +import static com.android.SdkConstants.URI_PREFIX; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.api.IClientRulesEngine; +import com.android.ide.common.api.INode; +import com.android.ide.common.api.IValidator; +import com.android.ide.common.api.IViewMetadata; +import com.android.ide.common.api.IViewRule; +import com.android.ide.common.api.Margins; +import com.android.ide.common.api.Rect; +import com.android.ide.common.layout.BaseViewRule; +import com.android.ide.common.resources.ResourceRepository; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction; +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; +import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ViewHierarchy; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.ide.eclipse.adt.internal.refactorings.core.RenameResult; +import com.android.ide.eclipse.adt.internal.resources.CyclicDependencyValidator; +import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; +import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.android.ide.eclipse.adt.internal.sdk.ProjectState; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.ide.eclipse.adt.internal.ui.MarginChooser; +import com.android.ide.eclipse.adt.internal.ui.ReferenceChooserDialog; +import com.android.ide.eclipse.adt.internal.ui.ResourceChooser; +import com.android.ide.eclipse.adt.internal.ui.ResourcePreviewHelper; +import com.android.resources.ResourceType; +import com.android.sdklib.IAndroidTarget; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.ui.IJavaElementSearchConstants; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction; +import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; +import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor; +import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; +import org.eclipse.jdt.ui.wizards.NewClassWizardPage; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.SelectionDialog; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Implementation of {@link IClientRulesEngine}. This provides {@link IViewRule} clients + * with a few methods they can use to access functionality from this {@link RulesEngine}. + */ +class ClientRulesEngine implements IClientRulesEngine { + /** The return code from the dialog for the user choosing "Clear" */ + public static final int CLEAR_RETURN_CODE = -5; + /** The dialog button ID for the user choosing "Clear" */ + private static final int CLEAR_BUTTON_ID = CLEAR_RETURN_CODE; + + private final RulesEngine mRulesEngine; + private final String mFqcn; + + public ClientRulesEngine(RulesEngine rulesEngine, String fqcn) { + mRulesEngine = rulesEngine; + mFqcn = fqcn; + } + + @Override + public @NonNull String getFqcn() { + return mFqcn; + } + + @Override + public void debugPrintf(@NonNull String msg, Object... params) { + AdtPlugin.printToConsole( + mFqcn == null ? "<unknown>" : mFqcn, + String.format(msg, params) + ); + } + + @Override + public IViewRule loadRule(@NonNull String fqcn) { + return mRulesEngine.loadRule(fqcn, fqcn); + } + + @Override + public void displayAlert(@NonNull String message) { + MessageDialog.openInformation( + AdtPlugin.getShell(), + mFqcn, // title + message); + } + + @Override + public boolean rename(INode node) { + GraphicalEditorPart editor = mRulesEngine.getEditor(); + SelectionManager manager = editor.getCanvasControl().getSelectionManager(); + RenameResult result = manager.performRename(node, null); + + return !result.isCanceled() && !result.isUnavailable(); + } + + @Override + public String displayInput(@NonNull String message, @Nullable String value, + final @Nullable IValidator filter) { + IInputValidator validator = null; + if (filter != null) { + validator = new IInputValidator() { + @Override + public String isValid(String newText) { + // IValidator has the same interface as SWT's IInputValidator + try { + return filter.validate(newText); + } catch (Exception e) { + AdtPlugin.log(e, "Custom validator failed: %s", e.toString()); + return ""; //$NON-NLS-1$ + } + } + }; + } + + InputDialog d = new InputDialog( + AdtPlugin.getShell(), + mFqcn, // title + message, + value == null ? "" : value, //$NON-NLS-1$ + validator) { + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, CLEAR_BUTTON_ID, "Clear", false /*defaultButton*/); + super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) { + super.buttonPressed(buttonId); + + if (buttonId == CLEAR_BUTTON_ID) { + assert CLEAR_RETURN_CODE != Window.OK && CLEAR_RETURN_CODE != Window.CANCEL; + setReturnCode(CLEAR_RETURN_CODE); + close(); + } + } + }; + int result = d.open(); + if (result == ResourceChooser.CLEAR_RETURN_CODE) { + return ""; + } else if (result == Window.OK) { + return d.getValue(); + } + return null; + } + + @Override + @Nullable + public Object getViewObject(@NonNull INode node) { + ViewHierarchy views = mRulesEngine.getEditor().getCanvasControl().getViewHierarchy(); + CanvasViewInfo vi = views.findViewInfoFor(node); + if (vi != null) { + return vi.getViewObject(); + } + + return null; + } + + @Override + public @NonNull IViewMetadata getMetadata(final @NonNull String fqcn) { + return new IViewMetadata() { + @Override + public @NonNull String getDisplayName() { + // This also works when there is no "." + return fqcn.substring(fqcn.lastIndexOf('.') + 1); + } + + @Override + public @NonNull FillPreference getFillPreference() { + return ViewMetadataRepository.get().getFillPreference(fqcn); + } + + @Override + public @NonNull Margins getInsets() { + return mRulesEngine.getEditor().getCanvasControl().getInsets(fqcn); + } + + @Override + public @NonNull List<String> getTopAttributes() { + return ViewMetadataRepository.get().getTopAttributes(fqcn); + } + }; + } + + @Override + public int getMinApiLevel() { + Sdk currentSdk = Sdk.getCurrent(); + if (currentSdk != null) { + IAndroidTarget target = currentSdk.getTarget(mRulesEngine.getEditor().getProject()); + if (target != null) { + return target.getVersion().getApiLevel(); + } + } + + return -1; + } + + @Override + public IValidator getResourceValidator( + @NonNull final String resourceTypeName, final boolean uniqueInProject, + final boolean uniqueInLayout, final boolean exists, final String... allowed) { + return new IValidator() { + private ResourceNameValidator mValidator; + + @Override + public String validate(@NonNull String text) { + if (mValidator == null) { + ResourceType type = ResourceType.getEnum(resourceTypeName); + if (uniqueInLayout) { + assert !uniqueInProject; + assert !exists; + Set<String> existing = new HashSet<String>(); + Document doc = mRulesEngine.getEditor().getModel().getXmlDocument(); + if (doc != null) { + addIds(doc, existing); + } + for (String s : allowed) { + existing.remove(s); + } + mValidator = ResourceNameValidator.create(false, existing, type); + } else { + assert allowed.length == 0; + IProject project = mRulesEngine.getEditor().getProject(); + mValidator = ResourceNameValidator.create(false, project, type); + if (uniqueInProject) { + mValidator.unique(); + } + } + if (exists) { + mValidator.exist(); + } + } + + return mValidator.isValid(text); + } + }; + } + + /** Find declared ids under the given DOM node */ + private static void addIds(Node node, Set<String> ids) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + String id = element.getAttributeNS(ANDROID_URI, ATTR_ID); + if (id != null && id.startsWith(NEW_ID_PREFIX)) { + ids.add(BaseViewRule.stripIdPrefix(id)); + } + } + + NodeList children = node.getChildNodes(); + for (int i = 0, n = children.getLength(); i < n; i++) { + Node child = children.item(i); + addIds(child, ids); + } + } + + @Override + public String displayReferenceInput(@Nullable String currentValue) { + GraphicalEditorPart graphicalEditor = mRulesEngine.getEditor(); + LayoutEditorDelegate delegate = graphicalEditor.getEditorDelegate(); + IProject project = delegate.getEditor().getProject(); + if (project != null) { + // get the resource repository for this project and the system resources. + ResourceRepository projectRepository = + ResourceManager.getInstance().getProjectResources(project); + Shell shell = AdtPlugin.getShell(); + if (shell == null) { + return null; + } + ReferenceChooserDialog dlg = new ReferenceChooserDialog( + project, + projectRepository, + shell); + dlg.setPreviewHelper(new ResourcePreviewHelper(dlg, graphicalEditor)); + + dlg.setCurrentResource(currentValue); + + if (dlg.open() == Window.OK) { + return dlg.getCurrentResource(); + } + } + + return null; + } + + @Override + public String displayResourceInput(@NonNull String resourceTypeName, + @Nullable String currentValue) { + return displayResourceInput(resourceTypeName, currentValue, null); + } + + private String displayResourceInput(String resourceTypeName, String currentValue, + IInputValidator validator) { + ResourceType type = ResourceType.getEnum(resourceTypeName); + GraphicalEditorPart graphicalEditor = mRulesEngine.getEditor(); + return ResourceChooser.chooseResource(graphicalEditor, type, currentValue, validator); + } + + @Override + public String[] displayMarginInput(@Nullable String all, @Nullable String left, + @Nullable String right, @Nullable String top, @Nullable String bottom) { + GraphicalEditorPart editor = mRulesEngine.getEditor(); + IProject project = editor.getProject(); + if (project != null) { + Shell shell = AdtPlugin.getShell(); + if (shell == null) { + return null; + } + AndroidTargetData data = editor.getEditorDelegate().getEditor().getTargetData(); + MarginChooser dialog = new MarginChooser(shell, editor, data, all, left, right, + top, bottom); + if (dialog.open() == Window.OK) { + return dialog.getMargins(); + } + } + + return null; + } + + @Override + public String displayIncludeSourceInput() { + AndroidXmlEditor editor = mRulesEngine.getEditor().getEditorDelegate().getEditor(); + IInputValidator validator = CyclicDependencyValidator.create(editor.getInputFile()); + return displayResourceInput(ResourceType.LAYOUT.getName(), null, validator); + } + + @Override + public void select(final @NonNull Collection<INode> nodes) { + LayoutCanvas layoutCanvas = mRulesEngine.getEditor().getCanvasControl(); + final SelectionManager selectionManager = layoutCanvas.getSelectionManager(); + selectionManager.select(nodes); + // ALSO run an async select since immediately after nodes are created they + // may not be selectable. We can't ONLY run an async exec since + // code may depend on operating on the selection. + layoutCanvas.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + selectionManager.select(nodes); + } + }); + } + + @Override + public String displayFragmentSourceInput() { + try { + // Compute a search scope: We need to merge all the subclasses + // android.app.Fragment and android.support.v4.app.Fragment + IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); + IProject project = mRulesEngine.getProject(); + final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + if (javaProject != null) { + IType oldFragmentType = javaProject.findType(CLASS_V4_FRAGMENT); + + // First check to make sure fragments are available, and if not, + // warn the user. + IAndroidTarget target = Sdk.getCurrent().getTarget(project); + // No, this should be using the min SDK instead! + if (target.getVersion().getApiLevel() < 11 && oldFragmentType == null) { + // Compatibility library must be present + MessageDialog dialog = + new MessageDialog( + Display.getCurrent().getActiveShell(), + "Fragment Warning", + null, + "Fragments require API level 11 or higher, or a compatibility " + + "library for older versions.\n\n" + + " Do you want to install the compatibility library?", + MessageDialog.QUESTION, + new String[] { "Install", "Cancel" }, + 1 /* default button: Cancel */); + int answer = dialog.open(); + if (answer == 0) { + if (!AddSupportJarAction.install(project)) { + return null; + } + } else { + return null; + } + } + + // Look up sub-types of each (new fragment class and compatibility fragment + // class, if any) and merge the two arrays - then create a scope from these + // elements. + IType[] fragmentTypes = new IType[0]; + IType[] oldFragmentTypes = new IType[0]; + if (oldFragmentType != null) { + ITypeHierarchy hierarchy = + oldFragmentType.newTypeHierarchy(new NullProgressMonitor()); + oldFragmentTypes = hierarchy.getAllSubtypes(oldFragmentType); + } + IType fragmentType = javaProject.findType(CLASS_FRAGMENT); + if (fragmentType != null) { + ITypeHierarchy hierarchy = + fragmentType.newTypeHierarchy(new NullProgressMonitor()); + fragmentTypes = hierarchy.getAllSubtypes(fragmentType); + } + IType[] subTypes = new IType[fragmentTypes.length + oldFragmentTypes.length]; + System.arraycopy(fragmentTypes, 0, subTypes, 0, fragmentTypes.length); + System.arraycopy(oldFragmentTypes, 0, subTypes, fragmentTypes.length, + oldFragmentTypes.length); + scope = SearchEngine.createJavaSearchScope(subTypes, IJavaSearchScope.SOURCES); + } + + Shell parent = AdtPlugin.getShell(); + final AtomicReference<String> returnValue = + new AtomicReference<String>(); + final AtomicReference<SelectionDialog> dialogHolder = + new AtomicReference<SelectionDialog>(); + final SelectionDialog dialog = JavaUI.createTypeDialog( + parent, + new ProgressMonitorDialog(parent), + scope, + IJavaElementSearchConstants.CONSIDER_CLASSES, false, + // Use ? as a default filter to fill dialog with matches + "?", //$NON-NLS-1$ + new TypeSelectionExtension() { + @Override + public Control createContentArea(Composite parentComposite) { + Composite composite = new Composite(parentComposite, SWT.NONE); + composite.setLayout(new GridLayout(1, false)); + Button button = new Button(composite, SWT.PUSH); + button.setText("Create New..."); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + String fqcn = createNewFragmentClass(javaProject); + if (fqcn != null) { + returnValue.set(fqcn); + dialogHolder.get().close(); + } + } + }); + return composite; + } + + @Override + public ITypeInfoFilterExtension getFilterExtension() { + return new ITypeInfoFilterExtension() { + @Override + public boolean select(ITypeInfoRequestor typeInfoRequestor) { + int modifiers = typeInfoRequestor.getModifiers(); + if (!Flags.isPublic(modifiers) + || Flags.isInterface(modifiers) + || Flags.isEnum(modifiers) + || Flags.isAbstract(modifiers)) { + return false; + } + return true; + } + }; + } + }); + dialogHolder.set(dialog); + + dialog.setTitle("Choose Fragment Class"); + dialog.setMessage("Select a Fragment class (? = any character, * = any string):"); + if (dialog.open() == IDialogConstants.CANCEL_ID) { + return null; + } + if (returnValue.get() != null) { + return returnValue.get(); + } + + Object[] types = dialog.getResult(); + if (types != null && types.length > 0) { + return ((IType) types[0]).getFullyQualifiedName(); + } + } catch (JavaModelException e) { + AdtPlugin.log(e, null); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + return null; + } + + @Override + public String displayCustomViewClassInput() { + try { + IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); + IProject project = mRulesEngine.getProject(); + final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + if (javaProject != null) { + // Look up sub-types of each (new fragment class and compatibility fragment + // class, if any) and merge the two arrays - then create a scope from these + // elements. + IType[] viewTypes = new IType[0]; + IType fragmentType = javaProject.findType(CLASS_VIEW); + if (fragmentType != null) { + ITypeHierarchy hierarchy = + fragmentType.newTypeHierarchy(new NullProgressMonitor()); + viewTypes = hierarchy.getAllSubtypes(fragmentType); + } + scope = SearchEngine.createJavaSearchScope(viewTypes, IJavaSearchScope.SOURCES); + } + + Shell parent = AdtPlugin.getShell(); + final AtomicReference<String> returnValue = + new AtomicReference<String>(); + final AtomicReference<SelectionDialog> dialogHolder = + new AtomicReference<SelectionDialog>(); + final SelectionDialog dialog = JavaUI.createTypeDialog( + parent, + new ProgressMonitorDialog(parent), + scope, + IJavaElementSearchConstants.CONSIDER_CLASSES, false, + // Use ? as a default filter to fill dialog with matches + "?", //$NON-NLS-1$ + new TypeSelectionExtension() { + @Override + public Control createContentArea(Composite parentComposite) { + Composite composite = new Composite(parentComposite, SWT.NONE); + composite.setLayout(new GridLayout(1, false)); + Button button = new Button(composite, SWT.PUSH); + button.setText("Create New..."); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + String fqcn = createNewCustomViewClass(javaProject); + if (fqcn != null) { + returnValue.set(fqcn); + dialogHolder.get().close(); + } + } + }); + return composite; + } + + @Override + public ITypeInfoFilterExtension getFilterExtension() { + return new ITypeInfoFilterExtension() { + @Override + public boolean select(ITypeInfoRequestor typeInfoRequestor) { + int modifiers = typeInfoRequestor.getModifiers(); + if (!Flags.isPublic(modifiers) + || Flags.isInterface(modifiers) + || Flags.isEnum(modifiers) + || Flags.isAbstract(modifiers)) { + return false; + } + return true; + } + }; + } + }); + dialogHolder.set(dialog); + + dialog.setTitle("Choose Custom View Class"); + dialog.setMessage("Select a Custom View class (? = any character, * = any string):"); + if (dialog.open() == IDialogConstants.CANCEL_ID) { + return null; + } + if (returnValue.get() != null) { + return returnValue.get(); + } + + Object[] types = dialog.getResult(); + if (types != null && types.length > 0) { + return ((IType) types[0]).getFullyQualifiedName(); + } + } catch (JavaModelException e) { + AdtPlugin.log(e, null); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + return null; + } + + @Override + public void redraw() { + mRulesEngine.getEditor().getCanvasControl().redraw(); + } + + @Override + public void layout() { + mRulesEngine.getEditor().recomputeLayout(); + } + + @Override + public Map<INode, Rect> measureChildren(@NonNull INode parent, + @Nullable IClientRulesEngine.AttributeFilter filter) { + RenderService renderService = RenderService.create(mRulesEngine.getEditor()); + Map<INode, Rect> map = renderService.measureChildren(parent, filter); + if (map == null) { + map = Collections.emptyMap(); + } + return map; + } + + @Override + public int pxToDp(int px) { + ConfigurationChooser chooser = mRulesEngine.getEditor().getConfigurationChooser(); + float dpi = chooser.getConfiguration().getDensity().getDpiValue(); + return (int) (px * 160 / dpi); + } + + @Override + public int dpToPx(int dp) { + ConfigurationChooser chooser = mRulesEngine.getEditor().getConfigurationChooser(); + float dpi = chooser.getConfiguration().getDensity().getDpiValue(); + return (int) (dp * dpi / 160); + } + + @Override + public int screenToLayout(int pixels) { + return (int) (pixels / mRulesEngine.getEditor().getCanvasControl().getScale()); + } + + private String createNewFragmentClass(IJavaProject javaProject) { + NewClassWizardPage page = new NewClassWizardPage(); + + IProject project = mRulesEngine.getProject(); + Sdk sdk = Sdk.getCurrent(); + if (sdk == null) { + return null; + } + IAndroidTarget target = sdk.getTarget(project); + String superClass; + if (target == null || target.getVersion().getApiLevel() < 11) { + superClass = CLASS_V4_FRAGMENT; + } else { + superClass = CLASS_FRAGMENT; + } + page.setSuperClass(superClass, true /* canBeModified */); + IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject); + if (root != null) { + page.setPackageFragmentRoot(root, true /* canBeModified */); + } + ManifestInfo manifestInfo = ManifestInfo.get(project); + IPackageFragment pkg = manifestInfo.getPackageFragment(); + if (pkg != null) { + page.setPackageFragment(pkg, true /* canBeModified */); + } + OpenNewClassWizardAction action = new OpenNewClassWizardAction(); + action.setConfiguredWizardPage(page); + action.run(); + IType createdType = page.getCreatedType(); + if (createdType != null) { + return createdType.getFullyQualifiedName(); + } else { + return null; + } + } + + private String createNewCustomViewClass(IJavaProject javaProject) { + NewClassWizardPage page = new NewClassWizardPage(); + + IProject project = mRulesEngine.getProject(); + String superClass = CLASS_VIEW; + page.setSuperClass(superClass, true /* canBeModified */); + IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject); + if (root != null) { + page.setPackageFragmentRoot(root, true /* canBeModified */); + } + ManifestInfo manifestInfo = ManifestInfo.get(project); + IPackageFragment pkg = manifestInfo.getPackageFragment(); + if (pkg != null) { + page.setPackageFragment(pkg, true /* canBeModified */); + } + OpenNewClassWizardAction action = new OpenNewClassWizardAction(); + action.setConfiguredWizardPage(page); + action.run(); + IType createdType = page.getCreatedType(); + if (createdType != null) { + return createdType.getFullyQualifiedName(); + } else { + return null; + } + } + + @Override + public @NonNull String getUniqueId(@NonNull String fqcn) { + UiDocumentNode root = mRulesEngine.getEditor().getModel(); + String prefix = fqcn.substring(fqcn.lastIndexOf('.') + 1); + prefix = Character.toLowerCase(prefix.charAt(0)) + prefix.substring(1); + return DescriptorsUtils.getFreeWidgetId(root, prefix); + } + + @Override + public @NonNull String getAppNameSpace() { + IProject project = mRulesEngine.getEditor().getProject(); + + ProjectState projectState = Sdk.getProjectState(project); + if (projectState != null && projectState.isLibrary()) { + return AUTO_URI; + } + + ManifestInfo info = ManifestInfo.get(project); + return URI_PREFIX + info.getPackage(); + } +} |