diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java')
-rwxr-xr-x | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java new file mode 100755 index 000000000..be06d38e2 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2012 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.common; + +import com.android.ide.common.resources.ResourceFolder; +import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtUtils; +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.animator.AnimationEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.color.ColorEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate.IDelegateCreator; +import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.menu.MenuEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.otherxml.OtherXmlEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.otherxml.PlainXmlEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; +import com.android.ide.eclipse.adt.internal.editors.values.ValuesEditorDelegate; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; +import com.android.resources.ResourceFolderType; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.ISourceViewerExtension2; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IShowEditorInput; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.forms.editor.IFormPage; +import org.eclipse.ui.ide.IDE; +import org.w3c.dom.Document; + +/** + * Multi-page form editor for ALL /res XML files. + * <p/> + * This editor doesn't actually do anything. Instead, it defers actual implementation + * to {@link CommonXmlDelegate} instances. + */ +public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInput { + + public static final String ID = AdtConstants.EDITORS_NAMESPACE + ".CommonXmlEditor"; //$NON-NLS-1$ + + /** + * Registered {@link CommonXmlDelegate}s. + * All delegates must have a {@code Creator} class which is instantiated + * once here statically. All the creators are invoked in the order they + * are defined and the first one to return a non-null delegate is used. + */ + private static final IDelegateCreator[] DELEGATES = { + new LayoutEditorDelegate.Creator(), + new ValuesEditorDelegate.Creator(), + new AnimationEditorDelegate.Creator(), + new ColorEditorDelegate.Creator(), + new DrawableEditorDelegate.Creator(), + new MenuEditorDelegate.Creator(), + new OtherXmlEditorDelegate.Creator(), + }; + + /** + * IDs of legacy editors replaced by the {@link CommonXmlEditor}. + */ + public static final String[] LEGACY_EDITOR_IDS = { + LayoutEditorDelegate.LEGACY_EDITOR_ID, + ValuesEditorDelegate.LEGACY_EDITOR_ID, + AnimationEditorDelegate.LEGACY_EDITOR_ID, + ColorEditorDelegate.LEGACY_EDITOR_ID, + DrawableEditorDelegate.LEGACY_EDITOR_ID, + MenuEditorDelegate.LEGACY_EDITOR_ID, + OtherXmlEditorDelegate.LEGACY_EDITOR_ID, + }; + + private CommonXmlDelegate mDelegate = null; + + /** + * Creates the form editor for resources XML files. + */ + public CommonXmlEditor() { + super(); + } + + @Override + public void init(IEditorSite site, final IEditorInput editorInput) + throws PartInitException { + if (editorInput instanceof IFileEditorInput) { + + IFileEditorInput fileInput = (IFileEditorInput) editorInput; + IFile file = fileInput.getFile(); + + // Adjust the default file editor ID + + IEditorDescriptor file_desc = IDE.getDefaultEditor(file); + String id = file_desc == null ? null : file_desc.getId(); + boolean mustChange = id != null && + !id.equals(ID) && + id.startsWith(AdtConstants.EDITORS_NAMESPACE); + if (!mustChange) { + // Maybe this was opened by a manual Open With with a legacy ID? + id = site.getId(); + mustChange = id != null && + !id.equals(ID) && + id.startsWith(AdtConstants.EDITORS_NAMESPACE); + } + + if (mustChange) { + // It starts by our editor namespace but it's not the right ID. + // This is an old Android XML ID. Change it to our new ID. + IDE.setDefaultEditor(file, ID); + AdtPlugin.log(IStatus.INFO, + "Changed legacy editor ID %s for %s", //$NON-NLS-1$ + id, + file.getFullPath()); + } + + // Now find the delegate for the file. + + ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); + ResourceFolderType type = resFolder == null ? null : resFolder.getType(); + + if (type == null) { + // We lack any real resource information about that file. + // Let's take a guess using the actual path. + String folderName = AdtUtils.getParentFolderName(editorInput); + type = ResourceFolderType.getFolderType(folderName); + } + + if (type != null) { + for (IDelegateCreator creator : DELEGATES) { + mDelegate = creator.createForFile(this, type); + if (mDelegate != null) { + break; + } + } + } + + if (mDelegate == null) { + // We didn't find any editor. + // We'll use the PlainXmlEditorDelegate as a catch-all editor. + AdtPlugin.log(IStatus.INFO, + "No valid Android XML Editor Delegate found for file %1$s [Res %2$s, type %3$s]", + file.getFullPath(), + resFolder, + type); + mDelegate = new PlainXmlEditorDelegate(this); + } + } else if (editorInput instanceof IURIEditorInput) { + String folderName = AdtUtils.getParentFolderName(editorInput); + ResourceFolderType type = ResourceFolderType.getFolderType(folderName); + if (type == ResourceFolderType.LAYOUT) { + // The layout editor has a lot of hardcoded requirements for real IFiles + // and IProjects so for now just use a plain XML editor for project-less layout + // files + mDelegate = new OtherXmlEditorDelegate(this); + } else if (type != null) { + for (IDelegateCreator creator : DELEGATES) { + mDelegate = creator.createForFile(this, type); + if (mDelegate != null) { + break; + } + } + } + + if (mDelegate == null) { + // We didn't find any editor. + // We'll use the PlainXmlEditorDelegate as a catch-all editor. + AdtPlugin.log(IStatus.INFO, + "No valid Android XML Editor Delegate found for file %1$s [Res %2$s, type %3$s]", + ((IURIEditorInput) editorInput).getURI().toString(), + folderName, + type); + mDelegate = new PlainXmlEditorDelegate(this); + } + } + + if (mDelegate == null) { + // We can't do anything if we don't have a valid file. + AdtPlugin.log(IStatus.INFO, + "Android XML Editor cannot process non-file input %1$s", //$NON-NLS-1$ + (editorInput == null ? "null" : editorInput.toString())); //$NON-NLS-1$ + throw new PartInitException("Android XML Editor cannot process this input."); + } else { + // Invoke the editor's init after setting up the delegate. This will call setInput(). + super.init(site, editorInput); + } + } + + /** + * @return The root node of the UI element hierarchy + */ + @Override + public UiElementNode getUiRootNode() { + return mDelegate == null ? null : mDelegate.getUiRootNode(); + } + + public CommonXmlDelegate getDelegate() { + return mDelegate; + } + + // ---- Base Class Overrides ---- + + @Override + public void dispose() { + if (mDelegate != null) { + mDelegate.dispose(); + } + + super.dispose(); + } + + /** + * Save the XML. + * <p/> + * The actual save operation is done in the super class by committing + * all data to the XML model and then having the Structured XML Editor + * save the XML. + * <p/> + * Here we just need to tell the delegate that the model has + * been saved. + */ + @Override + public void doSave(IProgressMonitor monitor) { + super.doSave(monitor); + if (mDelegate != null) { + mDelegate.delegateDoSave(monitor); + } + } + + /** + * Returns whether the "save as" operation is supported by this editor. + * <p/> + * Save-As is a valid operation for the ManifestEditor since it acts on a + * single source file. + * + * @see IEditorPart + */ + @Override + public boolean isSaveAsAllowed() { + return mDelegate == null ? false : mDelegate.isSaveAsAllowed(); + } + + /** + * Create the various form pages. + */ + @Override + protected void createFormPages() { + if (mDelegate != null) { + mDelegate.delegateCreateFormPages(); + } + } + + @Override + protected void postCreatePages() { + super.postCreatePages(); + + if (mDelegate != null) { + mDelegate.delegatePostCreatePages(); + } + } + + @Override + protected void addPages() { + // Create the editor pages. + // This will also create the EditorPart. + super.addPages(); + + // When the EditorPart is being created, it configures the SourceViewer + // and will try to use our CommonSourceViewerConfig. Our config needs to + // know which ContentAssist processor to use (since we have one per resource + // folder type) but it doesn't have the necessary info to do so. + // Consequently, once the part is created, we can now unconfigure the source + // viewer and reconfigure it with the right settings. + ISourceViewer ssv = getStructuredSourceViewer(); + if (mDelegate != null && ssv instanceof ISourceViewerExtension2) { + ((ISourceViewerExtension2) ssv).unconfigure(); + ssv.configure(new CommonSourceViewerConfig( + mDelegate.getAndroidContentAssistProcessor())); + } + } + + /* (non-java doc) + * Change the tab/title name to include the name of the layout. + */ + @Override + protected void setInput(IEditorInput input) { + super.setInput(input); + assert mDelegate != null; + if (mDelegate != null) { + mDelegate.delegateSetInput(input); + } + } + + @Override + public void setInputWithNotify(IEditorInput input) { + super.setInputWithNotify(input); + if (mDelegate instanceof LayoutEditorDelegate) { + ((LayoutEditorDelegate) mDelegate).delegateSetInputWithNotify(input); + } + } + + /** + * Processes the new XML Model, which XML root node is given. + * + * @param xml_doc The XML document, if available, or null if none exists. + */ + @Override + protected void xmlModelChanged(Document xml_doc) { + if (mDelegate != null) { + mDelegate.delegateXmlModelChanged(xml_doc); + } + } + + @Override + protected Job runLint() { + if (mDelegate != null && getEditorInput() instanceof IFileEditorInput) { + return mDelegate.delegateRunLint(); + } + return null; + } + + /** + * Returns the custom IContentOutlinePage or IPropertySheetPage when asked for it. + */ + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + if (mDelegate != null) { + Object value = mDelegate.delegateGetAdapter(adapter); + if (value != null) { + return value; + } + } + + // return default + return super.getAdapter(adapter); + } + + @Override + protected void pageChange(int newPageIndex) { + if (mDelegate != null) { + mDelegate.delegatePageChange(newPageIndex); + } + + super.pageChange(newPageIndex); + + if (mDelegate != null) { + mDelegate.delegatePostPageChange(newPageIndex); + } + } + + @Override + protected int getPersistenceCategory() { + if (mDelegate != null) { + return mDelegate.delegateGetPersistenceCategory(); + } + return CATEGORY_OTHER; + } + + @Override + public void initUiRootNode(boolean force) { + if (mDelegate != null) { + mDelegate.delegateInitUiRootNode(force); + } + } + + @Override + public IFormPage setActivePage(String pageId) { + IFormPage page = super.setActivePage(pageId); + + if (mDelegate != null) { + return mDelegate.delegatePostSetActivePage(page, pageId); + } + + return page; + } + + /* Implements showEditorInput(...) in IShowEditorInput */ + @Override + public void showEditorInput(IEditorInput editorInput) { + if (mDelegate instanceof LayoutEditorDelegate) { + ((LayoutEditorDelegate) mDelegate).showEditorInput(editorInput); + } + } + + @Override + public boolean supportsFormatOnGuiEdit() { + if (mDelegate != null) { + return mDelegate.delegateSupportsFormatOnGuiEdit(); + } + return super.supportsFormatOnGuiEdit(); + } + + @Override + public void activated() { + super.activated(); + if (mDelegate != null) { + mDelegate.delegateActivated(); + } + } + + @Override + public void deactivated() { + super.deactivated(); + if (mDelegate != null) { + mDelegate.delegateDeactivated(); + } + } + + @Override + public String getPartName() { + if (mDelegate != null) { + String name = mDelegate.delegateGetPartName(); + if (name != null) { + return name; + } + } + + return super.getPartName(); + } + + // -------------------- + // Base methods exposed so that XmlEditorDelegate can access them + + @Override + public void setPartName(String partName) { + super.setPartName(partName); + } + + @Override + public void setPageText(int pageIndex, String text) { + super.setPageText(pageIndex, text); + } + + @Override + public void firePropertyChange(int propertyId) { + super.firePropertyChange(propertyId); + } + + @Override + public int getPageCount() { + return super.getPageCount(); + } + + @Override + public int getCurrentPage() { + return super.getCurrentPage(); + } +} |