--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2006 Sybase, Inc. and others.\r
+ *\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * Sybase, Inc. - initial API and implementation\r
+ *******************************************************************************/\r
+package org.eclipse.jst.pagedesigner.editors;\r
+\r
+import java.io.File;\r
+import java.io.InputStream;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.resources.IFile;\r
+import org.eclipse.core.resources.IResource;\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.core.runtime.IConfigurationElement;\r
+import org.eclipse.core.runtime.IExtension;\r
+import org.eclipse.core.runtime.IExtensionPoint;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.eclipse.core.runtime.Platform;\r
+import org.eclipse.gef.DefaultEditDomain;\r
+import org.eclipse.gef.EditPart;\r
+import org.eclipse.gef.ui.views.palette.PalettePage;\r
+import org.eclipse.gef.ui.views.palette.PaletteViewerPage;\r
+import org.eclipse.jface.preference.IPreferenceStore;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.TextSelection;\r
+import org.eclipse.jface.viewers.IPostSelectionProvider;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jst.jsf.common.ui.internal.logging.Logger;\r
+import org.eclipse.jst.jsf.common.ui.internal.utils.ResourceUtils;\r
+import org.eclipse.jst.pagedesigner.IJMTConstants;\r
+import org.eclipse.jst.pagedesigner.PDPlugin;\r
+import org.eclipse.jst.pagedesigner.dnd.internal.DesignerSourceMouseTrackAdapter;\r
+import org.eclipse.jst.pagedesigner.editors.pagedesigner.PageDesignerResources;\r
+import org.eclipse.jst.pagedesigner.jsp.core.pagevar.IPageVariablesProvider;\r
+import org.eclipse.jst.pagedesigner.jsp.core.pagevar.adapter.IDocumentPageVariableAdapter;\r
+import org.eclipse.jst.pagedesigner.parts.DocumentEditPart;\r
+import org.eclipse.jst.pagedesigner.preview.PreviewHandlerNew;\r
+import org.eclipse.jst.pagedesigner.preview.WindowsIEBrowser;\r
+import org.eclipse.jst.pagedesigner.properties.WPETabbedPropertySheetPage;\r
+import org.eclipse.jst.pagedesigner.tools.RangeSelectionTool;\r
+import org.eclipse.jst.pagedesigner.ui.common.PartActivationHandler;\r
+import org.eclipse.jst.pagedesigner.ui.common.sash.SashEditorPart;\r
+import org.eclipse.jst.pagedesigner.ui.preferences.PDPreferences;\r
+import org.eclipse.jst.pagedesigner.utils.EditorUtil;\r
+import org.eclipse.jst.pagedesigner.utils.PreviewUtil;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.ui.IEditorInput;\r
+import org.eclipse.ui.IEditorPart;\r
+import org.eclipse.ui.IEditorSite;\r
+import org.eclipse.ui.IFileEditorInput;\r
+import org.eclipse.ui.IPropertyListener;\r
+import org.eclipse.ui.IStorageEditorInput;\r
+import org.eclipse.ui.IWorkbench;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.contexts.IContextService;\r
+import org.eclipse.ui.part.FileEditorInput;\r
+import org.eclipse.ui.part.MultiPageEditorPart;\r
+import org.eclipse.ui.part.MultiPageEditorSite;\r
+import org.eclipse.ui.part.MultiPageSelectionProvider;\r
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;\r
+import org.eclipse.ui.views.properties.IPropertySheetPage;\r
+import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;\r
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;\r
+import org.eclipse.wst.sse.ui.StructuredTextEditor;\r
+import org.eclipse.wst.sse.ui.internal.provisional.extensions.ISourceEditingTextTools;\r
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;\r
+import org.eclipse.wst.xml.ui.internal.provisional.IDOMSourceEditingTextTools;\r
+import org.w3c.dom.Document;\r
+\r
+/**\r
+ * The HTMLEditor is a multi paged editor. It will use the StructuredTextEditor\r
+ * as the chief editor, and delegate most operations to it.\r
+ * \r
+ * @author mengbo\r
+ */\r
+public final class HTMLEditor extends MultiPageEditorPart implements\r
+ IPropertyListener, ITabbedPropertySheetPageContributor {\r
+ // private static final String PAGE_NAME_DESIGN = "Design"; //$NON-NLS-1$\r
+ // private static final String PAGE_NAME_SOURCE = "Source"; //$NON-NLS-1$\r
+ /**\r
+ * Tabbed property contributor id for WPE\r
+ */\r
+ public final static String TABBED_PROPERTIES_CONTRIBUTOR_ID = "org.eclipse.jst.pagedesigner.tabPropertyContributor"; //$NON-NLS-1$\r
+\r
+ // four different modes for the designer when displayed in a sash editor.\r
+ /**\r
+ * editor split is vertical\r
+ */\r
+ public static final int MODE_SASH_VERTICAL = 0;\r
+\r
+ /**\r
+ * editor split is horizontal\r
+ */\r
+ public static final int MODE_SASH_HORIZONTAL = 1;\r
+\r
+ /**\r
+ * no split, only designer canvas\r
+ */\r
+ public static final int MODE_DESIGNER = 2;\r
+\r
+ /**\r
+ * no split, only SSE source\r
+ */\r
+ public static final int MODE_SOURCE = 3;\r
+\r
+ private Logger _log = PDPlugin.getLogger(HTMLEditor.class);\r
+\r
+ private boolean _sash = true;\r
+\r
+ private int _mode = 0;\r
+\r
+ private SashEditorPart _sashEditorPart = null;\r
+\r
+ private int _previewPageIndex;\r
+\r
+ /** The design viewer */\r
+ private SimpleGraphicalEditor _designViewer;\r
+\r
+ /** The text editor. */\r
+ private StructuredTextEditor _textEditor;\r
+\r
+ private PartActivationHandler _partListener;\r
+\r
+ private PaletteViewerPage _paletteViewerPage;\r
+\r
+ private DefaultEditDomain _editDomain;\r
+\r
+ private WindowsIEBrowser _browser;\r
+ \r
+ private Composite _previewComposite;\r
+\r
+ private List PREVIEW_FILES_LIST = new ArrayList();\r
+\r
+ private IPropertySheetPage _tabbedPropSheet;\r
+\r
+ private ISelectionChangedListener _selChangedListener;\r
+\r
+ // TODO:This class is never used locally\r
+// private class TextInputListener implements ITextInputListener {\r
+// public void inputDocumentAboutToBeChanged(IDocument oldInput,\r
+// IDocument newInput) {\r
+// // do nothing\r
+// }\r
+//\r
+// public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {\r
+// if (_designViewer != null && newInput != null)\r
+// _designViewer.setModel(getModel());\r
+// }\r
+// }\r
+\r
+ /**\r
+ * Default constructor\r
+ */\r
+ public HTMLEditor() {\r
+ super();\r
+ }\r
+\r
+ /*\r
+ * This method is just to make firePropertyChanged accessbible from some\r
+ * (anonomous) inner classes.\r
+ */\r
+ private void _firePropertyChange(int property) {\r
+ super.firePropertyChange(property);\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see com.ibm.xtools.common.ui.properties.ITabbedPropertySheetPageContributor#getContributorId()\r
+ */\r
+ public String getContributorId() {\r
+ return TABBED_PROPERTIES_CONTRIBUTOR_ID;\r
+ }\r
+\r
+ private void connectSashPage() {\r
+ ISelectionProvider selectionProvider = _sashEditorPart.getSite()\r
+ .getSelectionProvider();\r
+ if (selectionProvider instanceof IPostSelectionProvider) {\r
+ ((IPostSelectionProvider) selectionProvider)\r
+ .addPostSelectionChangedListener(getSelectionChangedListener(selectionProvider));\r
+ } else {\r
+ selectionProvider\r
+ .addSelectionChangedListener(getSelectionChangedListener(selectionProvider));\r
+ }\r
+ }\r
+ \r
+ private void disconnectSashPage() {\r
+ //attempted fix for bug 283569... was not able to repro, but should protect against NPE\r
+ if (_sashEditorPart != null \r
+ && _sashEditorPart.getSite() != null \r
+ && _sashEditorPart.getSite().getSelectionProvider() != null\r
+ && _selChangedListener != null) {\r
+ \r
+ final ISelectionProvider selectionProvider = _sashEditorPart.getSite()\r
+ .getSelectionProvider();\r
+ if (selectionProvider != null) {\r
+ if (selectionProvider instanceof IPostSelectionProvider) {\r
+ ((IPostSelectionProvider) selectionProvider)\r
+ .removePostSelectionChangedListener(getSelectionChangedListener(selectionProvider));\r
+ } else {\r
+ selectionProvider\r
+ .removeSelectionChangedListener(getSelectionChangedListener(selectionProvider));\r
+ }\r
+ }\r
+ } \r
+ }\r
+\r
+ private ISelectionChangedListener getSelectionChangedListener(ISelectionProvider selectionProvider) {\r
+ if (_selChangedListener == null) {\r
+ if (selectionProvider instanceof IPostSelectionProvider) {\r
+ _selChangedListener = new ISelectionChangedListener() {\r
+ public void selectionChanged(SelectionChangedEvent event) {\r
+ ((MultiPageSelectionProvider) getSite()\r
+ .getSelectionProvider())\r
+ .firePostSelectionChanged(event);\r
+ }\r
+ };\r
+ }\r
+ else {\r
+ _selChangedListener = new ISelectionChangedListener() {\r
+ public void selectionChanged(SelectionChangedEvent event) {\r
+ ((MultiPageSelectionProvider) getSite()\r
+ .getSelectionProvider())\r
+ .firePostSelectionChanged(event);\r
+ }\r
+ };\r
+ }\r
+ }\r
+ return _selChangedListener;\r
+ }\r
+\r
+ /**\r
+ * Creates the source page of the multi-page editor.\r
+ * @throws PartInitException \r
+ */\r
+ protected void sash_createAndAddDesignSourcePage() throws PartInitException {\r
+ // create source page\r
+ _textEditor = createTextEditor();\r
+ _textEditor.setEditorPart(this);\r
+ _textEditor.addPropertyListener(this);\r
+ // create design page\r
+ _designViewer = new SimpleGraphicalEditor(this, getEditDomain());\r
+\r
+ // create SashEditor\r
+ _sashEditorPart = new SashEditorPart() {\r
+ protected void createPages() throws PartInitException {\r
+ addPage(_designViewer, getEditorInput());\r
+ addPage(_textEditor, getEditorInput());\r
+ }\r
+ };\r
+ int sashIndex = addPage(_sashEditorPart, getEditorInput());\r
+\r
+ // Set the sash editor mode from the stored file property\r
+ // or the default preference\r
+ initDesignerMode();\r
+\r
+ setPageText(sashIndex, PDPlugin.getResourceString("HTMLEditor.Design")); //$NON-NLS-1$\r
+\r
+ // the update's critical, to get viewer selection manager and\r
+ // highlighting to work\r
+ _textEditor.update();\r
+\r
+ firePropertyChange(PROP_TITLE);\r
+\r
+ // Changes to the Text Viewer's document instance should also force an\r
+ // input refresh\r
+ // _textEditor.getTextViewer().addTextInputListener(new\r
+ // TextInputListener());\r
+ connectSashPage();\r
+ }\r
+\r
+ /**\r
+ * @see org.eclipse.ui.part.MultiPageEditorPart#createSite(org.eclipse.ui.IEditorPart)\r
+ */\r
+ protected IEditorSite createSite(IEditorPart editor) {\r
+ return new MultiPageEditorSite(this, editor);\r
+ }\r
+\r
+ private void tabbed_createAndAddDesignSourcePage()\r
+ throws PartInitException {\r
+ // create source page\r
+ _textEditor = createTextEditor();\r
+ _textEditor.setEditorPart(this);\r
+ _textEditor.addPropertyListener(this);\r
+\r
+ // create design page\r
+ SimpleGraphicalEditor editor = new SimpleGraphicalEditor(this,\r
+ getEditDomain());\r
+\r
+ // add design page\r
+ int designPageIndex = addPage(editor, null);\r
+\r
+ _designViewer = editor;\r
+ // // note: By adding the design page as a Control instead of an\r
+ // // IEditorPart, page switches will indicate\r
+ // // a "null" active editor when the design page is made active\r
+ setPageText(designPageIndex, PDPlugin\r
+ .getResourceString("HTMLEditor.Design")); //$NON-NLS-1$\r
+\r
+ // add source page\r
+ int sourcePageIndex = addPage(_textEditor, getEditorInput());\r
+ setPageText(sourcePageIndex, PDPlugin\r
+ .getResourceString("HTMLEditor.Source")); //$NON-NLS-1$\r
+ // the update's critical, to get viewer selection manager and\r
+ // highlighting to work\r
+ _textEditor.update();\r
+\r
+ firePropertyChange(PROP_TITLE);\r
+\r
+ // Changes to the Text Viewer's document instance should also force an\r
+ // input refresh\r
+ // _textEditor.getTextViewer().addTextInputListener(new\r
+ // TextInputListener());\r
+ }\r
+\r
+ private void createAndAddPreviewPage() {\r
+ _previewComposite = new Composite(getContainer(), 0);\r
+ FillLayout filllayout = new FillLayout();\r
+ _previewComposite.setLayout(filllayout);\r
+\r
+ _previewPageIndex = addPage(_previewComposite);\r
+ // JSPSourceEditor.Page.Preview.PageText=Preview\r
+ setPageText(_previewPageIndex, PageDesignerResources.getInstance()\r
+ .getString("JSPSourceEditor.Page.Preview.PageText")); //$NON-NLS-1$\r
+ \r
+ }\r
+\r
+ private WindowsIEBrowser getPreviewBrowser() {\r
+ if (_browser == null) {\r
+ _browser = new WindowsIEBrowser();\r
+ if (_browser != null) {\r
+ try {\r
+ // Support WEBKIT Browser\r
+ _browser.create(_previewComposite, SWT.WEBKIT);\r
+ } catch (Error e) {\r
+ // If SWTError is logged, Eclipse asks to exit workbench.\r
+ _browser.create(_previewComposite, SWT.NONE);\r
+ }\r
+ _previewComposite.layout();\r
+ }\r
+ }\r
+ return _browser;\r
+ }\r
+ /**\r
+ * Connects the design viewer with the viewer selection manager. Should be\r
+ * done after createSourcePage() is done because we need to get the\r
+ * ViewerSelectionManager from the TextEditor. setModel is also done here\r
+ * because getModel() needs to reference the TextEditor.\r
+ */\r
+ protected void connectDesignPage() {\r
+ if (_designViewer != null) {\r
+ _designViewer.setModel(getModel());\r
+ // _designViewer.getSynchronizer().listenToModel(getModel());\r
+ ISelectionProvider designSelectionProvider = _designViewer\r
+ .getSite().getSelectionProvider();\r
+ if (designSelectionProvider instanceof IPostSelectionProvider) {\r
+ ((IPostSelectionProvider) designSelectionProvider)\r
+ .addPostSelectionChangedListener(new ISelectionChangedListener() {\r
+ public void selectionChanged(\r
+ SelectionChangedEvent event) {\r
+ if (getActiveEditor() != _textEditor) {\r
+ _designViewer.getSynchronizer()\r
+ .selectionChanged(event);\r
+ }\r
+ }\r
+ });\r
+ } else {\r
+ designSelectionProvider\r
+ .addSelectionChangedListener(new ISelectionChangedListener() {\r
+ public void selectionChanged(\r
+ SelectionChangedEvent event) {\r
+ if (getActiveEditor() != _textEditor) {\r
+ _designViewer.getSynchronizer()\r
+ .selectionChanged(event);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ ISelectionProvider textSelectionProvider = _textEditor.getSite()\r
+ .getSelectionProvider();\r
+ if (textSelectionProvider instanceof IPostSelectionProvider) {\r
+ ((IPostSelectionProvider) textSelectionProvider)\r
+ .addPostSelectionChangedListener(new ISelectionChangedListener() {\r
+ public void selectionChanged(\r
+ SelectionChangedEvent event) {\r
+ if (event.getSelection() instanceof TextSelection) {\r
+ TextSelection textSelection = ((TextSelection) event\r
+ .getSelection());\r
+ _designViewer\r
+ .getSynchronizer()\r
+ .textSelectionChanged(\r
+ textSelection.getOffset(),\r
+ textSelection.getOffset()\r
+ + textSelection\r
+ .getLength());\r
+ }\r
+ }\r
+ });\r
+ } else {\r
+ textSelectionProvider\r
+ .addSelectionChangedListener(new ISelectionChangedListener() {\r
+ public void selectionChanged(\r
+ SelectionChangedEvent event) {\r
+ TextSelection textSelection = ((TextSelection) event\r
+ .getSelection());\r
+ _designViewer.getSynchronizer()\r
+ .textSelectionChanged(\r
+ textSelection.getOffset(),\r
+ textSelection.getOffset()\r
+ + textSelection\r
+ .getLength());\r
+ }\r
+ });\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates the pages of this multi-page editor.\r
+ * <p>\r
+ * Subclasses of <code>MultiPageEditor</code> must implement this method.\r
+ * </p>\r
+ */\r
+ protected void createPages() {\r
+ try {\r
+ // source page MUST be created before design page, now\r
+ if (_sash) {\r
+ sash_createAndAddDesignSourcePage();\r
+ } else {\r
+ tabbed_createAndAddDesignSourcePage();\r
+ }\r
+ connectDesignPage();\r
+ createAndAddPreviewPage();\r
+ DesignerSourceMouseTrackAdapter adapter = new DesignerSourceMouseTrackAdapter(\r
+ _textEditor, getEditDomain());\r
+ _textEditor.getTextViewer().getTextWidget().addMouseListener(\r
+ adapter);\r
+ _textEditor.getTextViewer().getTextWidget().addMouseMoveListener(\r
+ adapter);\r
+ } catch (PartInitException exception) {\r
+ //$NON-NLS-1$ = "An error has occurred when initializing the input for the the editor's source page."\r
+ if (_log != null) {\r
+ // throw new SourceEditingRuntimeException(\r
+ // "An error has occurred when initializing the input for the\r
+ // the editor's source page.");\r
+ }\r
+ }\r
+ // TODO: add a catch block here for any exception the design\r
+ // page throws and convert it into a more informative message.\r
+ }\r
+\r
+ /**\r
+ * Method createTextEditor.\r
+ * \r
+ * @return StructuredTextEditor\r
+ */\r
+ protected StructuredTextEditor createTextEditor() {\r
+ return new DesignerStructuredTextEditorJSP();\r
+ }\r
+\r
+ private void disconnectDesignPage() {\r
+ if (_designViewer != null) {\r
+ _designViewer.setModel(null);\r
+ _designViewer.dispose();\r
+ }\r
+ }\r
+\r
+ public void dispose() {\r
+ //System.out.println("dispose of HTML Editor");\r
+ deletePreviewFiles();\r
+ \r
+ disconnectSashPage();\r
+ disconnectDesignPage();\r
+ \r
+ IWorkbenchWindow window = getSite().getWorkbenchWindow();\r
+ window.getPartService().removePartListener(_partListener);\r
+ window.getShell().removeShellListener(_partListener);\r
+ getSite().getPage().removePartListener(_partListener);\r
+\r
+ if (_textEditor != null) {\r
+ _textEditor.removePropertyListener(this);\r
+ _textEditor.setEditorPart(null);\r
+ _textEditor.dispose();\r
+ }\r
+ \r
+ // moved to last when added window ... seems like\r
+ // we'd be in danger of losing some data, like site,\r
+ // or something.\r
+ _sashEditorPart = null;\r
+ _tabbedPropSheet = null;\r
+ _partListener = null;\r
+ _editDomain = null;\r
+ _designViewer = null;\r
+ _browser = null;\r
+ _previewComposite = null;\r
+ _paletteViewerPage = null;\r
+ _log = null;\r
+ _selChangedListener = null;\r
+ _textEditor = null;\r
+ \r
+ super.dispose();\r
+ \r
+ }\r
+\r
+ public void doSave(IProgressMonitor monitor) {\r
+ _textEditor.doSave(monitor);\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc) Saves the contents of this editor to another object. <p>\r
+ * Subclasses must override this method to implement the open-save-close\r
+ * lifecycle for an editor. For greater details, see <code> IEditorPart\r
+ * </code></p>\r
+ * \r
+ * @see IEditorPart\r
+ */\r
+ public void doSaveAs() {\r
+ _textEditor.doSaveAs();\r
+ }\r
+\r
+ private void editorInputIsAcceptable(IEditorInput input)\r
+ throws PartInitException {\r
+ if (input instanceof IFileEditorInput) {\r
+ // verify that it can be opened\r
+ CoreException[] coreExceptionArray = new CoreException[1];\r
+ if (fileDoesNotExist((IFileEditorInput) input, coreExceptionArray)) {\r
+ // todo use message formatter for {0}\r
+ Throwable coreException = coreExceptionArray[0];\r
+\r
+ // C.B: this is a strange piece of logic. It was referenceing\r
+ // the internal sub-class of CoreException, ResourceException.\r
+ // need to review fileDoesNotExist.\r
+ if (coreException instanceof CoreException) {\r
+ // I'm assuming this is always 'does not exist'\r
+ // we'll refresh local go mimic behavior of default\r
+ // editor, where the\r
+ // troublesome file is refreshed (and will cause it to\r
+ // 'disappear' from Navigator.\r
+ try {\r
+ ((IFileEditorInput) input).getFile()\r
+ .refreshLocal(IResource.DEPTH_ZERO,\r
+ new NullProgressMonitor());\r
+ } catch (CoreException ce) {\r
+ if (_log != null) {\r
+ _log.error("Error.HTMLEditor.0", ce); //$NON-NLS-1$\r
+ }\r
+ }\r
+ throw new PartInitException("Resource " + input.getName() //$NON-NLS-1$\r
+ + " does not exist."); //$NON-NLS-1$\r
+ }\r
+ throw new PartInitException("Editor could not be open on " //$NON-NLS-1$\r
+ + input.getName());\r
+ }\r
+ } else if (input instanceof IStorageEditorInput) {\r
+ InputStream contents = null;\r
+ try {\r
+ contents = ((IStorageEditorInput) input).getStorage()\r
+ .getContents();\r
+ if (contents == null) {\r
+ throw new PartInitException("Editor could not be open on " //$NON-NLS-1$\r
+ + input.getName());\r
+ }\r
+ } catch (CoreException noStorageExc) {\r
+ // Error in geting storage contents\r
+ _log.error("Error.HTMLEditor.1", noStorageExc); //$NON-NLS-1$\r
+ }\r
+ finally\r
+ {\r
+ ResourceUtils.ensureClosed(contents);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Initializes the editor part with a site and input. <p>\r
+ * Subclasses of <code> EditorPart </code> must implement this method.\r
+ * Within the implementation subclasses should verify that the input type is\r
+ * acceptable and then save the site and input. Here is sample code: </p><pre>\r
+ * if (!(input instanceof IFileEditorInput)) throw new\r
+ * PartInitException("Invalid Input: Must be IFileEditorInput");\r
+ * setSite(site); setInput(editorInput); </pre>\r
+ * @param input \r
+ * @param coreException \r
+ * @return true if the input doesn't exist \r
+ */\r
+ protected boolean fileDoesNotExist(IFileEditorInput input,\r
+ Throwable[] coreException) {\r
+ boolean result = false;\r
+ InputStream inStream = null;\r
+ if ((!(input.exists())) || (!(input.getFile().exists()))) {\r
+ result = true;\r
+ } else {\r
+ try \r
+ {\r
+ inStream = input.getFile().getContents(true);\r
+ } \r
+ catch (CoreException e) \r
+ {\r
+ // very likely to be file not found\r
+ result = true;\r
+ coreException[0] = e;\r
+ // The core has exception\r
+ _log.error("Error.HTMLEditor.3", e); //$NON-NLS-1$\r
+ } \r
+ finally \r
+ {\r
+ ResourceUtils.ensureClosed(inStream);\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ public Object getAdapter(Class key) {\r
+ Object result = null;\r
+ if (key == IDesignViewer.class) {\r
+ result = _designViewer;\r
+ } else if (key == PalettePage.class) {\r
+ return getPaletteViewerPage();\r
+ } else if (key == IPropertySheetPage.class) {\r
+ // XXX: we can delegate this to the fTextEditor, but that use some\r
+ // more\r
+ // complicate mechanism, and don't work with page designer well, so\r
+ // do it simple now, fix later.\r
+ // return _textEditor.getAdapter(key);\r
+ return getPropertySheetPage();\r
+ } else if (key == IContentOutlinePage.class) {\r
+ if (_textEditor != null) {\r
+ result = _textEditor.getAdapter(key);\r
+ }\r
+ } else if (key == IPageVariablesProvider.class) {\r
+ Object obj = ((IDOMModel) getModel()).getDocument().getAdapterFor(\r
+ IDocumentPageVariableAdapter.class);\r
+ if (obj instanceof IPageVariablesProvider) {\r
+ return obj;\r
+ }\r
+ return null;\r
+ } else {\r
+ // DMW: I'm bullet-proofing this because\r
+ // its been reported (on 4.03 version) a null pointer sometimes\r
+ // happens here on startup, when an editor has been left\r
+ // open when workbench shutdown.\r
+ if (_textEditor != null) {\r
+ result = _textEditor.getAdapter(key);\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+\r
+ /**\r
+ * IExtendedSimpleEditor method\r
+ * @return IDocument\r
+ */\r
+ public IDocument getDocument() {\r
+ if (getTextEditor() == null) {\r
+ return null;\r
+ }\r
+\r
+ Object apapter = _textEditor.getAdapter(ISourceEditingTextTools.class);\r
+ if (apapter != null) {\r
+ return ((ISourceEditingTextTools) apapter).getDocument();\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * IExtendedMarkupEditor method\r
+ * @return the dom document\r
+ */\r
+ public Document getDOMDocument() {\r
+ if (getTextEditor() == null) {\r
+ return null;\r
+ }\r
+\r
+ Object adapter = _textEditor.getAdapter(ISourceEditingTextTools.class);\r
+ if (adapter instanceof IDOMSourceEditingTextTools) {\r
+ return ((IDOMSourceEditingTextTools) adapter).getDOMDocument();\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * IExtendedSimpleEditor method\r
+ * @return the editor part\r
+ */\r
+ public IEditorPart getEditorPart() {\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * @return the structured model\r
+ */\r
+ public IStructuredModel getModel() {\r
+ IStructuredModel model = null;\r
+ if (_textEditor != null) {\r
+ model = ((DesignerStructuredTextEditorJSP) _textEditor).getModel();\r
+ }\r
+ return model;\r
+ }\r
+\r
+\r
+ /**\r
+ * @return the SSE editor delegate\r
+ */\r
+ public StructuredTextEditor getTextEditor() {\r
+ return _textEditor;\r
+ }\r
+\r
+\r
+ /*\r
+ * (non-Javadoc) Method declared on IWorkbenchPart.\r
+ */\r
+ public String getTitle() {\r
+ String title = null;\r
+ if (getTextEditor() == null) {\r
+ if (getEditorInput() != null) {\r
+ title = getEditorInput().getName();\r
+ }\r
+ } else {\r
+ title = getTextEditor().getTitle();\r
+ }\r
+ if (title == null) {\r
+ title = getPartName();\r
+ }\r
+ return title;\r
+ }\r
+\r
+ public void init(IEditorSite site, IEditorInput input)\r
+ throws PartInitException {\r
+ super.init(site, input);\r
+ editorInputIsAcceptable(input);\r
+ try {\r
+ // super.init(site, input);\r
+ // setSite(site);\r
+ setInput(input);\r
+ if (_partListener == null) {\r
+ _partListener = new PartActivationHandler(this) {\r
+ public void handleActivation() {\r
+ safelySanityCheckState();\r
+ }\r
+ };\r
+ }\r
+ // we want to listen for our own activation\r
+ IWorkbenchWindow window = getSite().getWorkbenchWindow();\r
+ window.getPartService().addPartListener(_partListener);\r
+ window.getShell().addShellListener(_partListener);\r
+ \r
+ // TODO: is this the right place to do this?\r
+ // enable our editor context\r
+ IContextService contextService = (IContextService) getSite()\r
+ .getService(IContextService.class);\r
+ contextService.activateContext("org.eclipse.jst.pagedesigner.editorContext"); //$NON-NLS-1$\r
+\r
+ } catch (Exception e) {\r
+ // Error in editor initialization\r
+ _log.error("Error.HTMLEditor.5", e); //$NON-NLS-1$\r
+ }\r
+ setPartName(input.getName());\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc) Returns whether the "save as" operation is supported by\r
+ * this editor. <p> Subclasses must override this method to implement the\r
+ * open-save-close lifecycle for an editor. For greater details, see <code>\r
+ * IEditorPart </code></p>\r
+ * \r
+ * @see IEditorPart\r
+ */\r
+ public boolean isSaveAsAllowed() {\r
+ return _textEditor != null && _textEditor.isSaveAsAllowed();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc) Returns whether the contents of this editor should be saved\r
+ * when the editor is closed. <p> This method returns <code> true </code> if\r
+ * and only if the editor is dirty ( <code> isDirty </code> ). </p>\r
+ */\r
+ public boolean isSaveOnCloseNeeded() {\r
+ // overriding super class since it does a lowly isDirty!\r
+ if (_textEditor != null) {\r
+ return _textEditor.isSaveOnCloseNeeded();\r
+ }\r
+ return isDirty();\r
+ }\r
+\r
+ /**\r
+ * Posts the update code "behind" the running operation.\r
+ */\r
+ private void postOnDisplayQue(Runnable runnable) {\r
+ IWorkbench workbench = PlatformUI.getWorkbench();\r
+ IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();\r
+ if (windows != null && windows.length > 0) {\r
+ Display display = windows[0].getShell().getDisplay();\r
+ display.asyncExec(runnable);\r
+ } else {\r
+ runnable.run();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Indicates that a property has changed.\r
+ * \r
+ * @param source\r
+ * the object whose property has changed\r
+ * @param propId\r
+ * the id of the property which has changed; property ids are\r
+ * generally defined as constants on the source class\r
+ */\r
+ public void propertyChanged(Object source, int propId) {\r
+ switch (propId) {\r
+ // had to implement input changed "listener" so that\r
+ // strucutedText could tell it containing editor that\r
+ // the input has change, when a 'resource moved' event is\r
+ // found.\r
+ case IEditorPart.PROP_INPUT: {\r
+ if (source == _textEditor) {\r
+ if (_textEditor.getEditorInput() != getEditorInput()) {\r
+ setInput(_textEditor.getEditorInput());\r
+ // title should always change when input changes.\r
+ // create runnable for following post call\r
+ Runnable runnable = new Runnable() {\r
+ public void run() {\r
+ _firePropertyChange(IWorkbenchPart.PROP_TITLE);\r
+ }\r
+ };\r
+ // Update is just to post things on the display queue\r
+ // (thread). We have to do this to get the dirty\r
+ // property to get updated after other things on the\r
+ // queue are executed.\r
+ postOnDisplayQue(runnable);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case IWorkbenchPart.PROP_TITLE: {\r
+ // // update the input if the title is changed. why? It seems input\r
+ // change event will be fired at last.\r
+ // if (source == _textEditor)\r
+ // {\r
+ // if (_textEditor.getEditorInput() != getEditorInput())\r
+ // {\r
+ // setInput(_textEditor.getEditorInput());\r
+ // }\r
+ // }\r
+ // break;\r
+ }\r
+ default: {\r
+ // propagate changes. Is this needed? Answer: Yes.\r
+ // PROP_PART_NAME, PROP_DIRTY etc.\r
+ if (source == _textEditor) {\r
+ firePropertyChange(propId);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ private void safelySanityCheckState() {\r
+ // If we're called before editor is created, simply ignore since we\r
+ // delegate this function to our embedded TextEditor\r
+ if (getTextEditor() == null) {\r
+ return;\r
+ }\r
+\r
+ getTextEditor().safelySanityCheckState(getEditorInput());\r
+\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)\r
+ */\r
+ protected void setInput(IEditorInput input) {\r
+ // If driven from the Source page, it's "model" may not be up to date\r
+ // with the input just yet. We'll rely on later notification from the\r
+ // TextViewer to set us straight\r
+ super.setInput(input);\r
+ if (_designViewer != null) {\r
+\r
+ _designViewer.setModel(getModel());\r
+ }\r
+ setPartName(input.getName());\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.part.EditorPart#isDirty()\r
+ */\r
+ public boolean isDirty() {\r
+ if (getTextEditor() == null) {\r
+ return false;\r
+ }\r
+ return getTextEditor().isDirty();\r
+ }\r
+\r
+ private IPropertySheetPage getPropertySheetPage()\r
+ {\r
+ if (_tabbedPropSheet == null || _tabbedPropSheet.getControl() == null \r
+ || _tabbedPropSheet.getControl().isDisposed())\r
+ {\r
+ IPropertySheetPageFactory factory = getPageFactory();\r
+ if (factory != null)\r
+ {\r
+ final IFile file = ((IFileEditorInput)getEditorInput()).getFile();\r
+ _tabbedPropSheet = factory.createPage(file);\r
+ }\r
+ else\r
+ {\r
+ _tabbedPropSheet = new WPETabbedPropertySheetPage(this,this);\r
+ }\r
+ }\r
+ return _tabbedPropSheet;\r
+ }\r
+\r
+ private IPropertySheetPageFactory getPageFactory()\r
+ {\r
+ //List<IElementEditFactory> result = new ArrayList<IElementEditFactory>();\r
+ IExtensionPoint extensionPoint = Platform.getExtensionRegistry()\r
+ .getExtensionPoint(PDPlugin.getPluginId(),\r
+ IJMTConstants.EXTENSION_POINT_PAGEDESIGNER);\r
+ IExtension[] extensions = extensionPoint.getExtensions();\r
+\r
+ for (int i = 0; i < extensions.length; i++)\r
+ {\r
+ IExtension ext = extensions[i];\r
+ IConfigurationElement[] elementEditElement = ext\r
+ .getConfigurationElements();\r
+\r
+ for (int j = 0; j < elementEditElement.length; j++)\r
+ {\r
+ final IConfigurationElement element = elementEditElement[j];\r
+ if (element.getName().equals(\r
+ IJMTConstants.PROPERTY_PAGE_FACTORY))\r
+ {\r
+ elementEditElement[j].getAttribute("class"); //$NON-NLS-1$\r
+ Object obj;\r
+ try\r
+ {\r
+ obj = elementEditElement[j]\r
+ .createExecutableExtension("class"); //$NON-NLS-1$\r
+\r
+ // TODO: we need a policy based solution here,\r
+ // but this will do for now\r
+ if (obj instanceof IPropertySheetPageFactory)\r
+ {\r
+ return (IPropertySheetPageFactory) obj;\r
+ }\r
+ } \r
+ catch (CoreException e)\r
+ {\r
+ PDPlugin.log("Problem loading element edit extension for "+element.toString(), e); //$NON-NLS-1$\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * @return PaletteViewerPage\r
+ */\r
+ private PaletteViewerPage getPaletteViewerPage()\r
+ {\r
+ if (_paletteViewerPage == null)\r
+ {\r
+ _paletteViewerPage = _designViewer.createPaletteViewerPage();\r
+ }\r
+ return _paletteViewerPage;\r
+ }\r
+\r
+ /**\r
+ * @return the edit domain\r
+ */\r
+ public DefaultEditDomain getEditDomain() {\r
+ if (_editDomain == null) {\r
+ _editDomain = new DefaultEditDomain(this);\r
+\r
+ // XXX: if i don't do the following line, system will default use\r
+ // SelectionTool. Don't know where else to set this. Since it is\r
+ // kind of duplicate\r
+ // to the DesignerPaletteRoot.\r
+ _editDomain.setDefaultTool(new RangeSelectionTool());\r
+ _editDomain.loadDefaultTool();\r
+\r
+ // next config the _editDomain\r
+ // _editDomain.setPaletteRoot(new JSFPaletteRoot());\r
+ }\r
+ return _editDomain;\r
+ }\r
+\r
+ /**\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.part.MultiPageEditorPart#pageChange(int)\r
+ */\r
+ protected void pageChange(int newPageIndex) {\r
+ super.pageChange(newPageIndex);\r
+\r
+ if (newPageIndex == _previewPageIndex) {\r
+ // preview page activate, set the absoulte path of the current page URL.\r
+ IEditorInput editorInput = this.getEditorInput();\r
+ if (!(editorInput instanceof IFileEditorInput)) {\r
+ return;\r
+ }\r
+\r
+ FileEditorInput fileInput = (FileEditorInput)editorInput;\r
+ IFile file = fileInput.getFile();\r
+ if (!file.exists()) {\r
+ return;\r
+ }\r
+\r
+ try {\r
+ String url = file.getLocationURI().toURL().toString();\r
+ getPreviewBrowser().getBrowser().setUrl(url);\r
+ } catch (Exception e) {\r
+ getPreviewBrowser().getBrowser().setUrl("about:blank"); //$NON-NLS-1$\r
+ }\r
+ }\r
+\r
+ /*\r
+ deletePreviewFiles();\r
+\r
+ if (newPageIndex == _previewPageIndex) {\r
+ // preview page activate, need to regenerate the preview text and\r
+ // display it.\r
+ StringBuffer result = new StringBuffer();\r
+ try {\r
+ // PreviewHandler.generatePreview(this.getModel(),\r
+ // this.getEditorInput(), result);\r
+ DocumentEditPart part = (DocumentEditPart) this._designViewer\r
+ .getGraphicViewer().getContents();\r
+ PreviewHandlerNew.generatePreview(part, result);\r
+ } catch (Exception ex) {\r
+ result = new StringBuffer();\r
+ result\r
+ .append(this.getModel().getStructuredDocument()\r
+ .getText());\r
+ // Error in page changing\r
+ _log.info("Error.HTMLEditor.6", ex); //$NON-NLS-1$\r
+ ex.printStackTrace();\r
+ }\r
+ File file = PreviewUtil.toFile(result, getEditorInput());\r
+ if (file != null) {\r
+ PREVIEW_FILES_LIST.add(file);\r
+ getPreviewBrowser().loadFile(file);\r
+ } else {\r
+ getPreviewBrowser().getBrowser().setUrl("about:blank"); //$NON-NLS-1$\r
+ }\r
+ }\r
+ */\r
+ }\r
+\r
+ /**\r
+ * @return Returns the _designViewer.\r
+ */\r
+ public IDesignViewer getDesignViewer() {\r
+ return _designViewer;\r
+ }\r
+\r
+ /**\r
+ * @param mode\r
+ */\r
+ public void setDesignerMode(int mode) {\r
+ boolean requiresResynch = (_mode == MODE_SOURCE);\r
+ if (_sashEditorPart != null && _mode != mode) {\r
+ switch (mode) {\r
+ case MODE_SASH_HORIZONTAL:\r
+ _sashEditorPart.setOrientation(SWT.HORIZONTAL);\r
+ break;\r
+ case MODE_DESIGNER:\r
+ _sashEditorPart.setMaximizedEditor(this._designViewer);\r
+ break;\r
+ case MODE_SOURCE:\r
+ _sashEditorPart.setMaximizedEditor(this._textEditor);\r
+ break;\r
+ case MODE_SASH_VERTICAL:\r
+ default:\r
+ _sashEditorPart.setOrientation(SWT.VERTICAL);\r
+ }\r
+ if (getEditorInput() != null) {\r
+ EditorUtil.setEditorInputDesignModeProperty(getEditorInput(), String.valueOf(mode));\r
+ }\r
+ }\r
+ this._mode = mode;\r
+ if (requiresResynch) {\r
+ resynch();\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Set the sash editor mode from the stored file property\r
+ * or the default preference.\r
+ */\r
+ private void initDesignerMode() {\r
+ int preferredMode = MODE_SASH_VERTICAL;\r
+\r
+ // If the user has already selected a mode for the file, use it.\r
+ String prop = null;\r
+ if (getEditorInput() != null) {\r
+ prop = EditorUtil.getEditorInputDesignModeProperty(getEditorInput());\r
+ }\r
+ if (prop != null) {\r
+ try {\r
+ preferredMode = Integer.parseInt(prop);\r
+ } catch (NumberFormatException e) {\r
+ // do nothing;\r
+ }\r
+ } else {\r
+ // Otherwise, get the default mode from preferences.\r
+ IPreferenceStore pStore = PDPlugin.getDefault().getPreferenceStore();\r
+ preferredMode = pStore.getInt(PDPreferences.SASH_EDITOR_MODE_PREF);\r
+ }\r
+\r
+ setDesignerMode(preferredMode);\r
+ }\r
+\r
+ /**\r
+ * @return the current design mode\r
+ */\r
+ public int getDesignerMode() {\r
+ return this._mode;\r
+ }\r
+\r
+ private void resynch() {\r
+ if (_textEditor != null && _designViewer != null) {\r
+ ISelectionProvider provider = _textEditor.getSelectionProvider();\r
+ if (provider != null) {\r
+ ISelection selection = provider.getSelection();\r
+ if (selection instanceof TextSelection) {\r
+ TextSelection textSelection = (TextSelection)selection;\r
+ SelectionSynchronizer synchronizer = _designViewer.getSynchronizer();\r
+ if (synchronizer != null) {\r
+ synchronizer.textSelectionChanged(\r
+ textSelection.getOffset(),\r
+ textSelection.getOffset() + textSelection.getLength());\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ public IEditorPart getActiveEditor() {\r
+ IEditorPart result = null;\r
+ if (_sash) {\r
+ result = _sashEditorPart.getActiveEditor();\r
+ } else {\r
+ if (_designViewer.getGraphicViewer().getControl().isFocusControl()) {\r
+ result = _designViewer;\r
+ } else if (_textEditor.getTextViewer().getControl()\r
+ .isFocusControl()) {\r
+ result = _textEditor;\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ public String getPartName() {\r
+ if (_textEditor != null) {\r
+ return _textEditor.getPartName();\r
+ }\r
+ return super.getPartName();\r
+ }\r
+\r
+ private void deletePreviewFiles() {\r
+ Iterator itPreviewFiles = PREVIEW_FILES_LIST.iterator();\r
+ while (itPreviewFiles.hasNext()) {\r
+ File file = (File)itPreviewFiles.next();\r
+ if (file != null && file.exists()) {\r
+ file.delete();\r
+ }\r
+ }\r
+ PREVIEW_FILES_LIST.clear();\r
+ }\r
+\r
+ /**\r
+ * Refreshes the design page. Allows an external action to force a refresh\r
+ * after an external change, such as a DT skin change.\r
+ */\r
+ public void refreshDesignViewer() {\r
+ EditPart contentEditPart = _designViewer.getGraphicViewer().getRootEditPart().getContents();\r
+ if (contentEditPart instanceof DocumentEditPart) {\r
+ ((DocumentEditPart)contentEditPart).styleChanged();\r
+ }\r
+ }\r
+\r
+}\r