1b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll/* 2b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Copyright (C) 2010 The Android Open Source Project 3b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 4b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * you may not use this file except in compliance with the License. 6b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * You may obtain a copy of the License at 7b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 8b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * http://www.eclipse.org/org/documents/epl-v10.php 9b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 10b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Unless required by applicable law or agreed to in writing, software 11b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * distributed under the License is distributed on an "AS IS" BASIS, 12b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * See the License for the specific language governing permissions and 14b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * limitations under the License. 15b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 16b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 17b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollpackage com.android.ide.eclipse.adt.internal.editors; 18b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 19b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport com.android.ide.eclipse.adt.AdtPlugin; 20b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 21b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.internal.filebuffers.SynchronizableDocument; 22b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.IFile; 23b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.IProject; 24b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.IResource; 25b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.IResourceChangeEvent; 26b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.IResourceChangeListener; 27b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.resources.ResourcesPlugin; 28b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.runtime.CoreException; 29b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.runtime.IProgressMonitor; 30b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.core.runtime.QualifiedName; 31b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.action.IAction; 32b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.dialogs.ErrorDialog; 33b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.DocumentEvent; 34b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.DocumentRewriteSession; 35b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.DocumentRewriteSessionType; 36b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.IDocument; 37b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.IDocumentExtension4; 38b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.jface.text.IDocumentListener; 39b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.swt.widgets.Display; 40b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IActionBars; 41b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IEditorInput; 42b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IEditorPart; 43b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IEditorSite; 44b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IFileEditorInput; 45b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.IWorkbenchPage; 46b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.PartInitException; 47b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.actions.ActionFactory; 48b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.browser.IWorkbenchBrowserSupport; 49b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.editors.text.TextEditor; 50b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.IManagedForm; 51b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.editor.FormEditor; 52b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.editor.IFormPage; 53b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.events.HyperlinkAdapter; 54b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.events.HyperlinkEvent; 55b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.events.IHyperlinkListener; 56b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.forms.widgets.FormText; 57b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.internal.browser.WorkbenchBrowserSupport; 58b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.part.FileEditorInput; 59b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.part.MultiPageEditorPart; 60b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.part.WorkbenchPart; 61b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.ui.texteditor.IDocumentProvider; 62b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport org.eclipse.wst.sse.ui.StructuredTextEditor; 63b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 64b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport java.net.MalformedURLException; 65b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollimport java.net.URL; 66b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 67b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll/** 68b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Multi-page form editor for Android text files. 69b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 70b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * It is designed to work with a {@link TextEditor} that will display a text file. 71b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <br/> 72b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Derived classes must implement createFormPages to create the forms before the 73b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * source editor. This can be a no-op if desired. 74b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 754c07263da057b6014342089097a3a4c6ebe993d2Raphael@SuppressWarnings("restriction") 76b9dd664f2996e4090603e3fc224b98453a49f759Raphael Mollpublic abstract class AndroidTextEditor extends FormEditor implements IResourceChangeListener { 77b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 78b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** Preference name for the current page of this file */ 79b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private static final String PREF_CURRENT_PAGE = "_current_page"; 80b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 81b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** Id string used to create the Android SDK browser */ 8223da069e4f407df1b06e7db2324e3247496abe3dTor Norbye private static String BROWSER_ID = "android"; //$NON-NLS-1$ 83b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 84b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** Page id of the XML source editor, used for switching tabs programmatically */ 85b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public final static String TEXT_EDITOR_ID = "editor_part"; //$NON-NLS-1$ 86b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 87b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** Width hint for text fields. Helps the grid layout resize properly on smaller screens */ 88b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public static final int TEXT_WIDTH_HINT = 50; 89b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 90b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** Page index of the text editor (always the last page) */ 91b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private int mTextPageIndex; 92b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 93b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** The text editor */ 94b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private TextEditor mTextEditor; 95b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 96b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** flag set during page creation */ 97b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private boolean mIsCreatingPage = false; 98b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 99b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private IDocument mDocument; 100b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 101b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 102b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates a form editor. 103b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 104b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public AndroidTextEditor() { 105b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super(); 106b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 107b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 108b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ---- Abstract Methods ---- 109b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 110b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 111b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates the various form pages. 112b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 113b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Derived classes must implement this to add their own specific tabs. 114b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 115b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll abstract protected void createFormPages(); 116b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 117b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 118b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Called by the base class {@link AndroidTextEditor} once all pages (custom form pages 119b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * as well as text editor page) have been created. This give a chance to deriving 120b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * classes to adjust behavior once the text page has been created. 121b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 122b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void postCreatePages() { 123b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // Nothing in the base class. 124b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 125b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 126b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 127b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Subclasses should override this method to process the new text model. 128b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * This is called after the document has been edited. 129b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 130b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * The base implementation is empty. 131b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 132b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @param event Specification of changes applied to document. 133b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 134b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void onDocumentChanged(DocumentEvent event) { 135b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // pass 136b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 137b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 138b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ---- Base Class Overrides, Interfaces Implemented ---- 139b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 140b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 141b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates the pages of the multi-page editor. 142b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 143b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 144b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void addPages() { 145b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll createAndroidPages(); 146b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll selectDefaultPage(null /* defaultPageId */); 147b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 148b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 149b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 150b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates the page for the Android Editors 151b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 152b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void createAndroidPages() { 153b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mIsCreatingPage = true; 154b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll createFormPages(); 155b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll createTextEditor(); 156b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll createUndoRedoActions(); 157b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll postCreatePages(); 158b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mIsCreatingPage = false; 159b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 160b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 161b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 162b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Returns whether the editor is currently creating its pages. 163b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 164b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public boolean isCreatingPages() { 165b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return mIsCreatingPage; 166b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 167b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 168b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 169b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates undo redo actions for the editor site (so that it works for any page of this 170b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * multi-page editor) by re-using the actions defined by the {@link TextEditor} 171b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * (aka the XML text editor.) 172b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 173b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private void createUndoRedoActions() { 174b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IActionBars bars = getEditorSite().getActionBars(); 175b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (bars != null) { 176b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IAction action = mTextEditor.getAction(ActionFactory.UNDO.getId()); 177b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll bars.setGlobalActionHandler(ActionFactory.UNDO.getId(), action); 178b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 179b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll action = mTextEditor.getAction(ActionFactory.REDO.getId()); 180b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll bars.setGlobalActionHandler(ActionFactory.REDO.getId(), action); 181b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 182b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll bars.updateActionBars(); 183b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 184b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 185b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 186b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 187b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Selects the default active page. 188b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @param defaultPageId the id of the page to show. If <code>null</code> the editor attempts to 189b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * find the default page in the properties of the {@link IResource} object being edited. 190b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 191b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void selectDefaultPage(String defaultPageId) { 192b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (defaultPageId == null) { 193b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (getEditorInput() instanceof IFileEditorInput) { 194b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IFile file = ((IFileEditorInput) getEditorInput()).getFile(); 195b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 196b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, 197b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll getClass().getSimpleName() + PREF_CURRENT_PAGE); 198b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll String pageId; 199b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 200b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll pageId = file.getPersistentProperty(qname); 201b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (pageId != null) { 202b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll defaultPageId = pageId; 203b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 204b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (CoreException e) { 205b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ignored 206b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 207b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 208b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 209b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 210b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (defaultPageId != null) { 211b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 212b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll setActivePage(Integer.parseInt(defaultPageId)); 213b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (Exception e) { 214b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // We can get NumberFormatException from parseInt but also 215b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // AssertionError from setActivePage when the index is out of bounds. 216b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // Generally speaking we just want to ignore any exception and fall back on the 217b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // first page rather than crash the editor load. Logging the error is enough. 218b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll AdtPlugin.log(e, "Selecting page '%s' in AndroidXmlEditor failed", defaultPageId); 219b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 220b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 221b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 222b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 223b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 224b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Removes all the pages from the editor. 225b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 226b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void removePages() { 227b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll int count = getPageCount(); 228b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll for (int i = count - 1 ; i >= 0 ; i--) { 229b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll removePage(i); 230b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 231b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 232b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 233b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 234b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Overrides the parent's setActivePage to be able to switch to the xml editor. 235b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 236b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * If the special pageId TEXT_EDITOR_ID is given, switches to the mTextPageIndex page. 237b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * This is needed because the editor doesn't actually derive from IFormPage and thus 238b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * doesn't have the get-by-page-id method. In this case, the method returns null since 239b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * IEditorPart does not implement IFormPage. 240b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 241b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 242b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public IFormPage setActivePage(String pageId) { 243b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (pageId.equals(TEXT_EDITOR_ID)) { 244b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super.setActivePage(mTextPageIndex); 245b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return null; 246b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } else { 247b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return super.setActivePage(pageId); 248b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 249b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 250b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 251b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 252b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 253b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Notifies this multi-page editor that the page with the given id has been 254b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * activated. This method is called when the user selects a different tab. 255b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 256b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see MultiPageEditorPart#pageChange(int) 257b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 258b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 259b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll protected void pageChange(int newPageIndex) { 260b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super.pageChange(newPageIndex); 261b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 262b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // Do not record page changes during creation of pages 263b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (mIsCreatingPage) { 264b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return; 265b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 266b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 267b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (getEditorInput() instanceof IFileEditorInput) { 268b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IFile file = ((IFileEditorInput) getEditorInput()).getFile(); 269b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 270b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, 271b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll getClass().getSimpleName() + PREF_CURRENT_PAGE); 272b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 273b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll file.setPersistentProperty(qname, Integer.toString(newPageIndex)); 274b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (CoreException e) { 275b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ignore 276b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 277b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 278b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 279b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 280b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 281b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Notifies this listener that some resource changes 282b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * are happening, or have already happened. 283b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 284b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Closes all project files on project close. 285b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see IResourceChangeListener 286b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 287ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 288b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void resourceChanged(final IResourceChangeEvent event) { 289b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (event.getType() == IResourceChangeEvent.PRE_CLOSE) { 290b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll Display.getDefault().asyncExec(new Runnable() { 291ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 292b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void run() { 2934c07263da057b6014342089097a3a4c6ebe993d2Raphael @SuppressWarnings("hiding") 2944c07263da057b6014342089097a3a4c6ebe993d2Raphael IWorkbenchPage[] pages = getSite().getWorkbenchWindow().getPages(); 295b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll for (int i = 0; i < pages.length; i++) { 296b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (((FileEditorInput)mTextEditor.getEditorInput()) 297b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll .getFile().getProject().equals( 298b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll event.getResource())) { 299b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IEditorPart editorPart = pages[i].findEditor(mTextEditor 300b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll .getEditorInput()); 301b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll pages[i].closeEditor(editorPart, true); 302b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 303b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 304b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 305b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll }); 306b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 307b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 308b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 309b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 310b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Initializes the editor part with a site and input. 311b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 312b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Checks that the input is an instance of {@link IFileEditorInput}. 313b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 314b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see FormEditor 315b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 316b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 317b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException { 318b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (!(editorInput instanceof IFileEditorInput)) 319b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll throw new PartInitException("Invalid Input: Must be IFileEditorInput"); 320b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super.init(site, editorInput); 321b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 322b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 323b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 324aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll * Returns the {@link IFile} matching the editor's input or null. 325aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll * <p/> 326aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll * By construction, the editor input has to be an {@link IFileEditorInput} so it must 327aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll * have an associated {@link IFile}. Null can only be returned if this editor has no 328aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll * input somehow. 329aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll */ 330aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll public IFile getFile() { 331aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll if (getEditorInput() instanceof IFileEditorInput) { 332aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll return ((IFileEditorInput) getEditorInput()).getFile(); 333aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll } 334aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll return null; 335aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll } 336aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll 337aa80eb0797889e53c43ef91bb8e63d8d9d5f1d24Raphael Moll /** 338b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Removes attached listeners. 339b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 340b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see WorkbenchPart 341b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 342b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 343b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void dispose() { 344b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); 345b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 346b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super.dispose(); 347b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 348b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 349b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 350b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Commit all dirty pages then saves the contents of the text editor. 351b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 352b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * This works by committing all data to the XML model and then 353b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * asking the Structured XML Editor to save the XML. 354b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 355b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see IEditorPart 356b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 357b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 358b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void doSave(IProgressMonitor monitor) { 359b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll commitPages(true /* onSave */); 360b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 361b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // The actual "save" operation is done by the Structured XML Editor 362b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll getEditor(mTextPageIndex).doSave(monitor); 363b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 364b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 365b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /* (non-Javadoc) 366b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Saves the contents of this editor to another object. 367b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p> 368b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Subclasses must override this method to implement the open-save-close lifecycle 369b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * for an editor. For greater details, see <code>IEditorPart</code> 370b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * </p> 371b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 372b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see IEditorPart 373b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 374b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 375b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void doSaveAs() { 376b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll commitPages(true /* onSave */); 377b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 378b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IEditorPart editor = getEditor(mTextPageIndex); 379b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll editor.doSaveAs(); 380b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll setPageText(mTextPageIndex, editor.getTitle()); 381b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll setInput(editor.getEditorInput()); 382b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 383b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 384b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 385b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Commits all dirty pages in the editor. This method should 386b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * be called as a first step of a 'save' operation. 387b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 388b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * This is the same implementation as in {@link FormEditor} 389b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * except it fixes two bugs: a cast to IFormPage is done 390b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * from page.get(i) <em>before</em> being tested with instanceof. 391b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Another bug is that the last page might be a null pointer. 392b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 393b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * The incorrect casting makes the original implementation crash due 394b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * to our {@link StructuredTextEditor} not being an {@link IFormPage} 395b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * so we have to override and duplicate to fix it. 396b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 397b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @param onSave <code>true</code> if commit is performed as part 398b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * of the 'save' operation, <code>false</code> otherwise. 399b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @since 3.3 400b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 401b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 402b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void commitPages(boolean onSave) { 403b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (pages != null) { 404b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll for (int i = 0; i < pages.size(); i++) { 405b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll Object page = pages.get(i); 406b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (page != null && page instanceof IFormPage) { 407b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IFormPage form_page = (IFormPage) page; 408b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IManagedForm managed_form = form_page.getManagedForm(); 409b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (managed_form != null && managed_form.isDirty()) { 410b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll managed_form.commit(onSave); 411b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 412b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 413b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 414b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 415b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 416b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 417b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /* (non-Javadoc) 418b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Returns whether the "save as" operation is supported by this editor. 419b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p> 420b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Subclasses must override this method to implement the open-save-close lifecycle 421b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * for an editor. For greater details, see <code>IEditorPart</code> 422b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * </p> 423b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 424b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see IEditorPart 425b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 426b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 427b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public boolean isSaveAsAllowed() { 428b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return false; 429b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 430b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 431b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ---- Local methods ---- 432b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 433b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 434b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 435b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Helper method that creates a new hyper-link Listener. 436b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Used by derived classes which need active links in {@link FormText}. 437b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 438b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * This link listener handles two kinds of URLs: 439b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <ul> 440b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <li> Links starting with "http" are simply sent to a local browser. 441b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <li> Links starting with "file:/" are simply sent to a local browser. 442b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <li> Links starting with "page:" are expected to be an editor page id to switch to. 443b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <li> Other links are ignored. 444b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * </ul> 445b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 446b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @return A new hyper-link listener for FormText to use. 447b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 448b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public final IHyperlinkListener createHyperlinkListener() { 449b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return new HyperlinkAdapter() { 450b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 451b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Switch to the page corresponding to the link that has just been clicked. 452b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * For this purpose, the HREF of the <a> tags above is the page ID to switch to. 453b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 454b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll @Override 455b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void linkActivated(HyperlinkEvent e) { 456b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll super.linkActivated(e); 457b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll String link = e.data.toString(); 458b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (link.startsWith("http") || //$NON-NLS-1$ 459b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll link.startsWith("file:/")) { //$NON-NLS-1$ 460b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll openLinkInBrowser(link); 461b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } else if (link.startsWith("page:")) { //$NON-NLS-1$ 462b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // Switch to an internal page 463b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll setActivePage(link.substring(5 /* strlen("page:") */)); 464b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 465b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 466b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll }; 467b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 468b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 469b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 470b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Open the http link into a browser 471b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 472b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @param link The URL to open in a browser 473b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 474b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private void openLinkInBrowser(String link) { 475b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 476b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IWorkbenchBrowserSupport wbs = WorkbenchBrowserSupport.getInstance(); 477b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll wbs.createBrowser(BROWSER_ID).openURL(new URL(link)); 478b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (PartInitException e1) { 479b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // pass 480b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (MalformedURLException e1) { 481b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // pass 482b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 483b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 484b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 485b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 486b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Creates the XML source editor. 487b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 488b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Memorizes the index page of the source editor (it's always the last page, but the number 489b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * of pages before can change.) 490b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <br/> 491b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Retrieves the underlying XML model from the StructuredEditor and attaches a listener to it. 492b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Finally triggers modelChanged() on the model listener -- derived classes can use this 493b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * to initialize the model the first time. 494b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 495b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Called only once <em>after</em> createFormPages. 496b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 497b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll private void createTextEditor() { 498b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 499b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mTextEditor = new TextEditor(); 500b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll int index = addPage(mTextEditor, getEditorInput()); 501b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mTextPageIndex = index; 502b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll setPageText(index, mTextEditor.getTitle()); 503b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 504b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IDocumentProvider provider = mTextEditor.getDocumentProvider(); 505b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mDocument = provider.getDocument(getEditorInput()); 506b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 507b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll mDocument.addDocumentListener(new IDocumentListener() { 508ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 509b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void documentChanged(DocumentEvent event) { 510b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll onDocumentChanged(event); 511b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 512b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 513ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 514b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void documentAboutToBeChanged(DocumentEvent event) { 515b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // ignore 516b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 517b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll }); 518b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 519b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 520b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch (PartInitException e) { 521b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll ErrorDialog.openError(getSite().getShell(), 522b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll "Android Text Editor Error", null, e.getStatus()); 523b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 524b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 525b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 526b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 527b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Gives access to the {@link IDocument} from the {@link TextEditor}, corresponding to 528b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * the current file input. 529b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 530b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * All edits should be wrapped in a {@link #wrapRewriteSession(Runnable)}. 531b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * The actual document instance is a {@link SynchronizableDocument}, which creates a lock 532b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * around read/set operations. The base API provided by {@link IDocument} provides ways to 533b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * manipulate the document line per line or as a bulk. 534b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 535b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public IDocument getDocument() { 536b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return mDocument; 537b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 538b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 539b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 540b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Returns the {@link IProject} for the edited file. 541b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 542b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public IProject getProject() { 543b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (mTextEditor != null) { 544b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IEditorInput input = mTextEditor.getEditorInput(); 545b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (input instanceof FileEditorInput) { 546b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll FileEditorInput fileInput = (FileEditorInput)input; 547b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IFile inputFile = fileInput.getFile(); 548b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 549b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (inputFile != null) { 550b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return inputFile.getProject(); 551b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 552b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 553b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 554b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 555b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll return null; 556b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 557b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 558b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll /** 559b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Runs the given operation in the context of a document RewriteSession. 560b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * Takes care of properly starting and stopping the operation. 561b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * <p/> 562b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * The operation itself should just access {@link #getDocument()} and use the 563b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * normal document's API to manipulate it. 564b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * 565b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll * @see #getDocument() 566b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll */ 567b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll public void wrapRewriteSession(Runnable operation) { 568b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (mDocument instanceof IDocumentExtension4) { 569b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll IDocumentExtension4 doc4 = (IDocumentExtension4) mDocument; 570b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 571b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll DocumentRewriteSession session = null; 572b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll try { 573b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll session = doc4.startRewriteSession(DocumentRewriteSessionType.UNRESTRICTED_SMALL); 574b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 575b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll operation.run(); 576b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } catch(IllegalStateException e) { 577b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll AdtPlugin.log(e, "wrapRewriteSession failed"); 578b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll e.printStackTrace(); 579b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } finally { 580b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll if (session != null) { 581b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll doc4.stopRewriteSession(session); 582b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 583b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 584b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 585b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } else { 586b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll // Not an IDocumentExtension4? Unlikely. Try the operation anyway. 587b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll operation.run(); 588b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 589b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll } 590b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll 591b9dd664f2996e4090603e3fc224b98453a49f759Raphael Moll} 592