/* * Copyright (C) 2010 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; import com.android.ide.eclipse.adt.AdtPlugin; import org.eclipse.core.internal.filebuffers.SynchronizableDocument; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.DocumentRewriteSession; import org.eclipse.jface.text.DocumentRewriteSessionType; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.events.IHyperlinkListener; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.part.MultiPageEditorPart; import org.eclipse.ui.part.WorkbenchPart; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.wst.sse.ui.StructuredTextEditor; import java.net.MalformedURLException; import java.net.URL; /** * Multi-page form editor for Android text files. *
* It is designed to work with a {@link TextEditor} that will display a text file. *null
the editor attempts to
* find the default page in the properties of the {@link IResource} object being edited.
*/
protected void selectDefaultPage(String defaultPageId) {
if (defaultPageId == null) {
if (getEditorInput() instanceof IFileEditorInput) {
IFile file = ((IFileEditorInput) getEditorInput()).getFile();
QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID,
getClass().getSimpleName() + PREF_CURRENT_PAGE);
String pageId;
try {
pageId = file.getPersistentProperty(qname);
if (pageId != null) {
defaultPageId = pageId;
}
} catch (CoreException e) {
// ignored
}
}
}
if (defaultPageId != null) {
try {
setActivePage(Integer.parseInt(defaultPageId));
} catch (Exception e) {
// We can get NumberFormatException from parseInt but also
// AssertionError from setActivePage when the index is out of bounds.
// Generally speaking we just want to ignore any exception and fall back on the
// first page rather than crash the editor load. Logging the error is enough.
AdtPlugin.log(e, "Selecting page '%s' in AndroidXmlEditor failed", defaultPageId);
}
}
}
/**
* Removes all the pages from the editor.
*/
protected void removePages() {
int count = getPageCount();
for (int i = count - 1 ; i >= 0 ; i--) {
removePage(i);
}
}
/**
* Overrides the parent's setActivePage to be able to switch to the xml editor.
*
* If the special pageId TEXT_EDITOR_ID is given, switches to the mTextPageIndex page.
* This is needed because the editor doesn't actually derive from IFormPage and thus
* doesn't have the get-by-page-id method. In this case, the method returns null since
* IEditorPart does not implement IFormPage.
*/
@Override
public IFormPage setActivePage(String pageId) {
if (pageId.equals(TEXT_EDITOR_ID)) {
super.setActivePage(mTextPageIndex);
return null;
} else {
return super.setActivePage(pageId);
}
}
/**
* Notifies this multi-page editor that the page with the given id has been
* activated. This method is called when the user selects a different tab.
*
* @see MultiPageEditorPart#pageChange(int)
*/
@Override
protected void pageChange(int newPageIndex) {
super.pageChange(newPageIndex);
// Do not record page changes during creation of pages
if (mIsCreatingPage) {
return;
}
if (getEditorInput() instanceof IFileEditorInput) {
IFile file = ((IFileEditorInput) getEditorInput()).getFile();
QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID,
getClass().getSimpleName() + PREF_CURRENT_PAGE);
try {
file.setPersistentProperty(qname, Integer.toString(newPageIndex));
} catch (CoreException e) {
// ignore
}
}
}
/**
* Notifies this listener that some resource changes
* are happening, or have already happened.
*
* Closes all project files on project close.
* @see IResourceChangeListener
*/
@Override
public void resourceChanged(final IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
@SuppressWarnings("hiding")
IWorkbenchPage[] pages = getSite().getWorkbenchWindow().getPages();
for (int i = 0; i < pages.length; i++) {
if (((FileEditorInput)mTextEditor.getEditorInput())
.getFile().getProject().equals(
event.getResource())) {
IEditorPart editorPart = pages[i].findEditor(mTextEditor
.getEditorInput());
pages[i].closeEditor(editorPart, true);
}
}
}
});
}
}
/**
* Initializes the editor part with a site and input.
*
* Checks that the input is an instance of {@link IFileEditorInput}.
*
* @see FormEditor
*/
@Override
public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
if (!(editorInput instanceof IFileEditorInput))
throw new PartInitException("Invalid Input: Must be IFileEditorInput");
super.init(site, editorInput);
}
/**
* Returns the {@link IFile} matching the editor's input or null.
*
* By construction, the editor input has to be an {@link IFileEditorInput} so it must
* have an associated {@link IFile}. Null can only be returned if this editor has no
* input somehow.
*/
public IFile getFile() {
if (getEditorInput() instanceof IFileEditorInput) {
return ((IFileEditorInput) getEditorInput()).getFile();
}
return null;
}
/**
* Removes attached listeners.
*
* @see WorkbenchPart
*/
@Override
public void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
super.dispose();
}
/**
* Commit all dirty pages then saves the contents of the text editor.
*
* This works by committing all data to the XML model and then
* asking the Structured XML Editor to save the XML.
*
* @see IEditorPart
*/
@Override
public void doSave(IProgressMonitor monitor) {
commitPages(true /* onSave */);
// The actual "save" operation is done by the Structured XML Editor
getEditor(mTextPageIndex).doSave(monitor);
}
/* (non-Javadoc)
* Saves the contents of this editor to another object.
*
* Subclasses must override this method to implement the open-save-close lifecycle
* for an editor. For greater details, see IEditorPart
*
true
if commit is performed as part
* of the 'save' operation, false
otherwise.
* @since 3.3
*/
@Override
public void commitPages(boolean onSave) {
if (pages != null) {
for (int i = 0; i < pages.size(); i++) {
Object page = pages.get(i);
if (page != null && page instanceof IFormPage) {
IFormPage form_page = (IFormPage) page;
IManagedForm managed_form = form_page.getManagedForm();
if (managed_form != null && managed_form.isDirty()) {
managed_form.commit(onSave);
}
}
}
}
}
/* (non-Javadoc)
* Returns whether the "save as" operation is supported by this editor.
*
* Subclasses must override this method to implement the open-save-close lifecycle
* for an editor. For greater details, see IEditorPart
*