Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java')
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java919
1 files changed, 919 insertions, 0 deletions
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
new file mode 100644
index 00000000..89aefa69
--- /dev/null
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
@@ -0,0 +1,919 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 John Krasnay and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * John Krasnay - initial API and implementation
+ * Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325)
+ *******************************************************************************/
+package org.eclipse.vex.ui.internal.editor;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.dialogs.SaveAsDialog;
+import org.eclipse.ui.editors.text.ILocationProvider;
+import org.eclipse.ui.part.EditorPart;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.eclipse.ui.views.properties.IPropertySheetPage;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+import org.eclipse.ui.views.properties.PropertySheetPage;
+import org.eclipse.vex.core.internal.core.ListenerList;
+import org.eclipse.vex.core.internal.dom.Document;
+import org.eclipse.vex.core.internal.dom.DocumentReader;
+import org.eclipse.vex.core.internal.dom.DocumentWriter;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
+import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;
+import org.eclipse.vex.core.internal.dom.Validator;
+import org.eclipse.vex.core.internal.validator.WTPVEXValidator;
+import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
+import org.eclipse.vex.ui.internal.VexPlugin;
+import org.eclipse.vex.ui.internal.config.ConfigEvent;
+import org.eclipse.vex.ui.internal.config.DocumentType;
+import org.eclipse.vex.ui.internal.config.IConfigListener;
+import org.eclipse.vex.ui.internal.config.Style;
+import org.eclipse.vex.ui.internal.handlers.ConvertElementHandler;
+import org.eclipse.vex.ui.internal.handlers.RemoveTagHandler;
+import org.eclipse.vex.ui.internal.outline.DocumentOutlinePage;
+import org.eclipse.vex.ui.internal.property.ElementPropertySource;
+import org.eclipse.vex.ui.internal.swt.VexWidget;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Editor for editing XML file using the VexWidget.
+ */
+public class VexEditor extends EditorPart {
+
+ /**
+ * ID of this editor extension.
+ */
+ public static final String ID = "org.eclipse.vex.ui.internal.editor.VexEditor"; //$NON-NLS-1$
+
+ /**
+ * Class constructor.
+ */
+ public VexEditor() {
+ debugging = VexPlugin.getInstance().isDebugging() && "true".equalsIgnoreCase(Platform.getDebugOption(VexPlugin.ID + "/debug/layout")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Add a VexEditorListener to the notification list.
+ *
+ * @param listener
+ * VexEditorListener to be added.
+ */
+ public void addVexEditorListener(final IVexEditorListener listener) {
+ vexEditorListeners.add(listener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ if (parentControl != null)
+ // createPartControl was called, so we must de-register from config
+ // events
+ VexPlugin.getInstance().getConfigurationRegistry().removeConfigListener(configListener);
+
+ if (getEditorInput() instanceof IFileEditorInput)
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
+
+ }
+
+ @Override
+ public void doSave(final IProgressMonitor monitor) {
+
+ final IEditorInput input = getEditorInput();
+ OutputStream os = null;
+ try {
+ resourceChangeListener.setSaving(true);
+ final DocumentWriter writer = new DocumentWriter();
+ writer.setWhitespacePolicy(new CssWhitespacePolicy(style.getStyleSheet()));
+
+ if (input instanceof IFileEditorInput) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writer.write(doc, baos);
+ baos.close();
+ final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ((IFileEditorInput) input).getFile().setContents(bais, false, false, monitor);
+ } else {
+ os = new FileOutputStream(((ILocationProvider) input).getPath(input).toFile());
+ writer.write(doc, os);
+ }
+
+ savedUndoDepth = vexWidget.getUndoDepth();
+ firePropertyChange(IEditorPart.PROP_DIRTY);
+
+ } catch (final Exception ex) {
+ monitor.setCanceled(true);
+ final String title = Messages.getString("VexEditor.errorSaving.title"); //$NON-NLS-1$
+ final String message = MessageFormat.format(Messages.getString("VexEditor.errorSaving.message"), //$NON-NLS-1$
+ new Object[] { input.getName(), ex.getMessage() });
+ MessageDialog.openError(getEditorSite().getShell(), title, message);
+ VexPlugin.getInstance().log(IStatus.ERROR, message, ex);
+ } finally {
+ if (os != null)
+ try {
+ os.close();
+ } catch (final IOException e) {
+ }
+ resourceChangeListener.setSaving(false);
+ }
+ }
+
+ @Override
+ public void doSaveAs() {
+ final SaveAsDialog dlg = new SaveAsDialog(getSite().getShell());
+ final int result = dlg.open();
+ if (result == Window.OK) {
+ final IPath path = dlg.getResult();
+ try {
+ resourceChangeListener.setSaving(true);
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final DocumentWriter writer = new DocumentWriter();
+ writer.setWhitespacePolicy(new CssWhitespacePolicy(style.getStyleSheet()));
+ writer.write(doc, baos);
+ baos.close();
+
+ final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+ file.create(bais, false, null);
+
+ final IFileEditorInput input = new FileEditorInput(file);
+ setInput(input);
+ savedUndoDepth = vexWidget.getUndoDepth();
+
+ firePropertyChange(IEditorPart.PROP_DIRTY);
+ firePropertyChange(IEditorPart.PROP_INPUT);
+ firePropertyChange(IWorkbenchPart.PROP_TITLE);
+
+ } catch (final Exception ex) {
+ final String title = Messages.getString("VexEditor.errorSaving.title"); //$NON-NLS-1$
+ final String message = MessageFormat.format(Messages.getString("VexEditor.errorSaving.message"), //$NON-NLS-1$
+ new Object[] { path, ex.getMessage() });
+ MessageDialog.openError(getEditorSite().getShell(), title, message);
+ VexPlugin.getInstance().log(IStatus.ERROR, message, ex);
+ } finally {
+ resourceChangeListener.setSaving(false);
+ }
+ }
+
+ }
+
+ /**
+ * Return a reasonable style for the given doctype.
+ *
+ * @param publicId
+ * Public ID for which to return the style.
+ */
+ public static Style getPreferredStyle(final String publicId) {
+ return VexPlugin.getInstance().getConfigurationRegistry().getStyle(publicId, getPreferredStyleId(publicId));
+ }
+
+ private static String getPreferredStyleId(final String publicId) {
+ final Preferences prefs = new InstanceScope().getNode(VexPlugin.ID);
+ final String preferredStyleId = prefs.get(getStylePreferenceKey(publicId), null);
+ return preferredStyleId;
+ }
+
+ /**
+ * Returns the DocumentType associated with this editor.
+ */
+ public DocumentType getDocumentType() {
+ return doctype;
+ }
+
+ /**
+ * Returns the Style currently associated with the editor. May be null.
+ */
+ public Style getStyle() {
+ return style;
+ }
+
+ /**
+ * Returns the VexWidget that implements this editor.
+ */
+ public VexWidget getVexWidget() {
+ return vexWidget;
+ }
+
+ public void gotoMarker(final IMarker marker) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
+
+ setSite(site);
+ setInput(input);
+
+ getEditorSite().setSelectionProvider(selectionProvider);
+ getEditorSite().getSelectionProvider().addSelectionChangedListener(selectionChangedListener);
+
+ if (input instanceof IFileEditorInput)
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
+ }
+
+ protected void loadInput() {
+
+ if (vexWidget != null)
+ vexEditorListeners.fireEvent("documentUnloaded", new VexEditorEvent(this)); //$NON-NLS-1$
+
+ loaded = false;
+
+ final IEditorInput input = getEditorInput();
+
+ try {
+ final long start = System.currentTimeMillis();
+
+ IFile file = null;
+
+ if (input instanceof IFileEditorInput)
+ file = ((IFileEditorInput) input).getFile();
+ else {
+ final String msg = MessageFormat.format(Messages.getString("VexEditor.unknownInputClass"), //$NON-NLS-1$
+ new Object[] { input.getClass() });
+ showLabel(msg);
+ return;
+ }
+
+ final DocumentReader reader = new DocumentReader();
+ reader.setDebugging(debugging);
+ reader.setEntityResolver(entityResolver);
+ reader.setWhitespacePolicyFactory(wsFactory);
+ doctype = null; // must be null to set it to a new value via
+ // entityResolveras by following read():
+ doc = reader.read(file.getLocationURI().toURL());
+
+ if (debugging) {
+ final long end = System.currentTimeMillis();
+ final String message = "Parsed document in " //$NON-NLS-1$
+ + (end - start) + "ms"; //$NON-NLS-1$
+ System.out.println(message);
+ }
+
+ if (doc == null) {
+ showLabel(MessageFormat.format(Messages.getString("VexEditor.noContent"), file));
+ return;
+ }
+
+ // this.doctype is set either by wsPolicyFactory or entityResolver
+ // this.style is set by wsPolicyFactory
+ // Otherwise, a PartInitException would have been thrown by now
+
+ //IValidator validator = this.doctype.getValidator();
+ final Validator validator = new WTPVEXValidator(doctype.getResourceUrl());
+ if (validator != null) {
+ doc.setValidator(validator);
+ if (debugging) {
+ final long end = System.currentTimeMillis();
+ System.out.println("Got validator in " + (end - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ showVexWidget();
+
+ vexWidget.setDebugging(debugging);
+ vexWidget.setDocument(doc, style.getStyleSheet());
+
+ if (updateDoctypeDecl) {
+ doc.setPublicID(doctype.getPublicId());
+ ((Document) doc).setSystemID(doctype.getSystemId());
+ doSave(null);
+ }
+
+ loaded = true;
+ savedUndoDepth = vexWidget.getUndoDepth();
+ firePropertyChange(IEditorPart.PROP_DIRTY);
+ wasDirty = isDirty();
+
+ vexEditorListeners.fireEvent("documentLoaded", new VexEditorEvent(this)); //$NON-NLS-1$
+
+ } catch (final SAXParseException ex) {
+
+ if (ex.getException() instanceof NoRegisteredDoctypeException) {
+ // TODO doc did not have document type and the user
+ // declined to select another one. Should fail silently.
+ String msg;
+ final NoRegisteredDoctypeException ex2 = (NoRegisteredDoctypeException) ex.getException();
+ if (ex2.getPublicId() == null)
+ msg = Messages.getString("VexEditor.noDoctype"); //$NON-NLS-1$
+ else
+ msg = MessageFormat.format(Messages.getString("VexEditor.unknownDoctype"), //$NON-NLS-1$
+ new Object[] { ex2.getPublicId() });
+ showLabel(msg);
+ } else if (ex.getException() instanceof NoStyleForDoctypeException) {
+ final String msg = MessageFormat.format(Messages.getString("VexEditor.noStyles"), //$NON-NLS-1$
+ new Object[] { doctype.getPublicId() });
+ showLabel(msg);
+ } else {
+ String file = ex.getSystemId();
+ if (file == null)
+ file = input.getName();
+
+ final String msg = MessageFormat.format(Messages.getString("VexEditor.parseError"), //$NON-NLS-1$
+ new Object[] { Integer.valueOf(ex.getLineNumber()), file, ex.getLocalizedMessage() });
+
+ showLabel(msg);
+
+ VexPlugin.getInstance().log(IStatus.ERROR, msg, ex);
+ }
+
+ } catch (final Exception ex) {
+
+ final String msg = MessageFormat.format(Messages.getString("VexEditor.unexpectedError"), //$NON-NLS-1$
+ new Object[] { input.getName() });
+
+ VexPlugin.getInstance().log(IStatus.ERROR, msg, ex);
+
+ showLabel(msg);
+ }
+ }
+
+ @Override
+ public boolean isDirty() {
+ if (vexWidget != null)
+ return savedUndoDepth != vexWidget.getUndoDepth();
+ else
+ return false;
+ }
+
+ /**
+ * Returns true if this editor has finished loading its document.
+ */
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ @Override
+ public void createPartControl(final Composite parent) {
+
+ parentControl = parent;
+
+ VexPlugin.getInstance().getConfigurationRegistry().addConfigListener(configListener);
+ if (VexPlugin.getInstance().getConfigurationRegistry().isLoaded())
+ loadInput();
+ else
+ showLabel(Messages.getString("VexEditor.loading")); //$NON-NLS-1$
+ }
+
+ /**
+ * Remove a VexEditorListener from the notification list.
+ *
+ * @param listener
+ * VexEditorListener to be removed.
+ */
+ public void removeVexEditorListener(final IVexEditorListener listener) {
+ vexEditorListeners.remove(listener);
+ }
+
+ @Override
+ public void setFocus() {
+ if (vexWidget != null) {
+ vexWidget.setFocus();
+ setStatus(getLocation());
+ }
+ }
+
+ @Override
+ protected void setInput(final IEditorInput input) {
+ super.setInput(input);
+ setPartName(input.getName());
+ setContentDescription(input.getName());
+ //this.setTitleToolTip(input.getToolTipText());
+ }
+
+ public void setStatus(final String text) {
+ // this.statusLabel.setText(text);
+ getEditorSite().getActionBars().getStatusLineManager().setMessage(text);
+ }
+
+ /**
+ * Sets the style for this editor.
+ *
+ * @param style
+ * Style to use.
+ */
+ public void setStyle(final Style style) {
+ this.style = style;
+ if (vexWidget != null) {
+ vexWidget.setStyleSheet(style.getStyleSheet());
+ setPreferredStyleId(doc.getPublicID(), style.getUniqueId());
+ }
+ }
+
+ private static void setPreferredStyleId(final String publicId, final String styleId) {
+ final Preferences prefs = new InstanceScope().getNode(VexPlugin.ID);
+ final String key = getStylePreferenceKey(publicId);
+ prefs.put(key, styleId);
+ try {
+ prefs.flush();
+ } catch (final BackingStoreException e) {
+ VexPlugin.getInstance().log(IStatus.ERROR, Messages.getString("VexEditor.errorSavingStylePreference"), e); //$NON-NLS-1$
+ }
+ }
+
+ // ========================================================= PRIVATE
+
+ private final boolean debugging;
+
+ private Composite parentControl;
+ private Label loadingLabel;
+
+ private boolean loaded;
+ private DocumentType doctype;
+ private Document doc;
+ private Style style;
+
+ private VexWidget vexWidget;
+
+ private int savedUndoDepth;
+ private boolean wasDirty;
+ // private Label statusLabel;
+
+ // This is true if the document's doctype decl is missing or unrecognized
+ // AND the user selected a new document type
+ // AND the user wants to always use the doctype for this document
+ private boolean updateDoctypeDecl;
+
+ private final ListenerList<IVexEditorListener, VexEditorEvent> vexEditorListeners = new ListenerList<IVexEditorListener, VexEditorEvent>(
+ IVexEditorListener.class);
+
+ private final SelectionProvider selectionProvider = new SelectionProvider();
+
+ /**
+ * Returns the preference key used to access the style ID for documents with
+ * the same public ID as the current document.
+ */
+ private static String getStylePreferenceKey(final String publicId) {
+ return publicId + ".style"; //$NON-NLS-1$
+ }
+
+ private void showLabel(final String message) {
+ if (loadingLabel == null) {
+ if (vexWidget != null) {
+ vexWidget.dispose();
+ vexWidget = null;
+ }
+ loadingLabel = new Label(parentControl, SWT.WRAP);
+ }
+ loadingLabel.setText(message);
+ parentControl.layout(true);
+ }
+
+ private void showVexWidget() {
+
+ if (vexWidget != null)
+ return;
+
+ if (loadingLabel != null) {
+ loadingLabel.dispose();
+ loadingLabel = null;
+ }
+
+ final GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ layout.verticalSpacing = 0;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ parentControl.setLayout(layout);
+ GridData gd;
+
+ // StatusPanel statusPanel = new StatusPanel(this.parentControl);
+
+ // Composite statusPanel = new Composite(this.parentControl, SWT.NONE);
+ // statusPanel.setLayout(new GridLayout());
+ // gd = new GridData();
+ // gd.grabExcessHorizontalSpace = true;
+ // gd.horizontalAlignment = GridData.FILL;
+ // statusPanel.setLayoutData(gd);
+
+ // this.statusLabel = new Label(statusPanel, SWT.NONE);
+ // gd = new GridData();
+ // gd.grabExcessHorizontalSpace = true;
+ // gd.horizontalAlignment = GridData.FILL;
+ // this.statusLabel.setLayoutData(gd);
+
+ gd = new GridData();
+ gd.grabExcessHorizontalSpace = true;
+ gd.grabExcessVerticalSpace = true;
+ gd.horizontalAlignment = GridData.FILL;
+ gd.verticalAlignment = GridData.FILL;
+
+ vexWidget = new VexWidget(parentControl, SWT.V_SCROLL);
+ gd = new GridData();
+ gd.grabExcessHorizontalSpace = true;
+ gd.grabExcessVerticalSpace = true;
+ gd.horizontalAlignment = GridData.FILL;
+ gd.verticalAlignment = GridData.FILL;
+ vexWidget.setLayoutData(gd);
+
+ final MenuManager menuManager = new MenuManager();
+ getSite().registerContextMenu("org.eclipse.vex.ui.popup", menuManager, vexWidget);
+ vexWidget.setMenu(menuManager.createContextMenu(vexWidget));
+
+ savedUndoDepth = vexWidget.getUndoDepth();
+
+ // new for scopes
+ final IContextService cs = (IContextService) getSite().getService(IContextService.class);
+ cs.activateContext("org.eclipse.vex.ui.VexEditorContext");
+
+ vexWidget.addSelectionChangedListener(selectionProvider);
+
+ parentControl.layout(true);
+
+ }
+
+ private void handleResourceChanged(final IResourceDelta delta) {
+
+ if (delta.getKind() == IResourceDelta.CHANGED) {
+ if ((delta.getFlags() & IResourceDelta.CONTENT) != 0)
+ handleResourceContentChanged();
+ } else if (delta.getKind() == IResourceDelta.REMOVED)
+ if ((delta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
+ final IPath toPath = delta.getMovedToPath();
+ final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(toPath);
+ setInput(new FileEditorInput(file));
+ } else if (!isDirty())
+ getEditorSite().getPage().closeEditor(this, false);
+ else
+ handleResourceDeleted();
+
+ }
+
+ private void handleResourceContentChanged() {
+
+ if (!isDirty())
+ loadInput();
+ else {
+
+ final String message = MessageFormat.format(Messages.getString("VexEditor.docChanged.message"), //$NON-NLS-1$
+ new Object[] { getEditorInput().getName() });
+
+ final MessageDialog dlg = new MessageDialog(getSite().getShell(), Messages.getString("VexEditor.docChanged.title"), //$NON-NLS-1$
+ null, message, MessageDialog.QUESTION, new String[] { Messages.getString("VexEditor.docChanged.discard"), //$NON-NLS-1$
+ Messages.getString("VexEditor.docChanged.overwrite") }, //$NON-NLS-1$
+ 1);
+
+ final int result = dlg.open();
+
+ if (result == 0)
+ loadInput();
+ else
+ doSave(null);
+ }
+ }
+
+ private void handleResourceDeleted() {
+
+ final String message = MessageFormat.format(Messages.getString("VexEditor.docDeleted.message"), //$NON-NLS-1$
+ new Object[] { getEditorInput().getName() });
+
+ final MessageDialog dlg = new MessageDialog(getSite().getShell(), Messages.getString("VexEditor.docDeleted.title"), //$NON-NLS-1$
+ null, message, MessageDialog.QUESTION, new String[] { Messages.getString("VexEditor.docDeleted.discard"), //$NON-NLS-1$
+ Messages.getString("VexEditor.docDeleted.save") }, //$NON-NLS-1$
+ 1);
+
+ final int result = dlg.open();
+
+ if (result == 0)
+ getEditorSite().getPage().closeEditor(this, false);
+ else { // Save
+
+ doSaveAs();
+
+ // Check if they saved or not. If not, close the editor
+ if (!getEditorInput().exists())
+ getEditorSite().getPage().closeEditor(this, false);
+ }
+ }
+
+ // Listen for stylesheet changes and respond appropriately
+ private final IConfigListener configListener = new IConfigListener() {
+ public void configChanged(final ConfigEvent e) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if (style == null)
+ return;
+
+ final String styleId = style.getUniqueId();
+ final Style newStyle = VexPlugin.getInstance().getConfigurationRegistry().getStyle(styleId);
+ if (newStyle == null) {
+ // Oops, style went bye-bye
+ // Let's just hold on to it in case it comes back later
+ } else {
+ vexWidget.setStyleSheet(newStyle.getStyleSheet());
+ style = newStyle;
+ }
+ }
+ });
+ }
+
+ public void configLoaded(final ConfigEvent e) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ loadInput();
+ }
+ });
+ }
+ };
+
+ private final ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() {
+ public void selectionChanged(final SelectionChangedEvent event) {
+ if (isDirty() != wasDirty) {
+ firePropertyChange(IEditorPart.PROP_DIRTY);
+ wasDirty = isDirty();
+ }
+ setStatus(getLocation());
+
+ // update dynamic UI element labels
+ final IEditorSite editorSite = VexEditor.this.getEditorSite();
+ final IWorkbenchWindow window = editorSite.getWorkbenchWindow();
+ if (window instanceof IServiceLocator) {
+ final IServiceLocator serviceLocator = window;
+ final ICommandService commandService = (ICommandService) serviceLocator.getService(ICommandService.class);
+ commandService.refreshElements(ConvertElementHandler.COMMAND_ID, null);
+ commandService.refreshElements(RemoveTagHandler.COMMAND_ID, null);
+ }
+
+ // update context service
+ final ISourceProviderService service = (ISourceProviderService) window.getService(ISourceProviderService.class);
+ final DocumentContextSourceProvider contextProvider = (DocumentContextSourceProvider) service
+ .getSourceProvider(DocumentContextSourceProvider.IS_COLUMN);
+ contextProvider.fireUpdate(vexWidget);
+ }
+ };
+
+ private final EntityResolver entityResolver = new EntityResolver() {
+ public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
+
+ // System.out.println("### Resolving publicId " + publicId +
+ // ", systemId " + systemId);
+
+ if (doctype == null) {
+ //
+ // If doctype hasn't already been set, this must be the doctype
+ // decl.
+ //
+ if (publicId != null)
+ doctype = VexPlugin.getInstance().getConfigurationRegistry().getDocumentType(publicId);
+
+ if (doctype == null) {
+ final DocumentTypeSelectionDialog dlg = DocumentTypeSelectionDialog.create(getSite().getShell(), publicId);
+ dlg.open();
+ doctype = dlg.getDoctype();
+ updateDoctypeDecl = dlg.alwaysUseThisDoctype();
+
+ if (doctype == null)
+ throw new NoRegisteredDoctypeException(publicId);
+ }
+
+ final URL url = doctype.getResourceUrl();
+
+ if (url == null) {
+ final String message = MessageFormat.format(Messages.getString("VexEditor.noUrlForDoctype"), //$NON-NLS-1$
+ new Object[] { publicId });
+ throw new RuntimeException(message);
+ }
+
+ return new InputSource(url.toString());
+ } else
+ return null;
+ }
+ };
+
+ private final IWhitespacePolicyFactory wsFactory = new IWhitespacePolicyFactory() {
+ public IWhitespacePolicy getPolicy(final String publicId) {
+ if (doctype == null) {
+ final DocumentTypeSelectionDialog dlg = DocumentTypeSelectionDialog.create(getSite().getShell(), publicId);
+ dlg.open();
+ doctype = dlg.getDoctype();
+ updateDoctypeDecl = dlg.alwaysUseThisDoctype();
+
+ if (doctype == null)
+ throw new NoRegisteredDoctypeException(null);
+ }
+
+ style = VexEditor.getPreferredStyle(doctype.getPublicId());
+ if (style == null)
+ throw new NoStyleForDoctypeException();
+
+ return new CssWhitespacePolicy(style.getStyleSheet());
+ }
+
+ };
+
+ private class ResourceChangeListener implements IResourceChangeListener {
+
+ public void resourceChanged(final IResourceChangeEvent event) {
+
+ if (saving)
+ return;
+
+ final IPath path = ((IFileEditorInput) getEditorInput()).getFile().getFullPath();
+ final IResourceDelta delta = event.getDelta().findMember(path);
+ if (delta != null)
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ handleResourceChanged(delta);
+ }
+ });
+ }
+
+ public void setSaving(final boolean saving) {
+ this.saving = saving;
+ }
+
+ // Set to true so we can ignore change events while we're saving.
+ private boolean saving;
+ };
+
+ private final ResourceChangeListener resourceChangeListener = new ResourceChangeListener();
+
+ //
+ // wsFactory communicates failures back to init() through the XML parser
+ // by throwing one of these exceptions
+ //
+
+ /**
+ * Indicates that no document type is registered for the public ID in the
+ * document, or that the document does not have a PUBLIC DOCTYPE decl, in
+ * which case publicId is null.
+ */
+ private static class NoRegisteredDoctypeException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public NoRegisteredDoctypeException(final String publicId) {
+ this.publicId = publicId;
+ }
+
+ public String getPublicId() {
+ return publicId;
+ }
+
+ private final String publicId;
+ }
+
+ /**
+ * Indicates that the document was matched to a registered doctype, but that
+ * the given doctype does not have a matching style.
+ */
+ private static class NoStyleForDoctypeException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ private String getLocation() {
+ final List<String> path = new ArrayList<String>();
+ Element element = vexWidget.getCurrentElement();
+ while (element != null) {
+ path.add(element.getPrefixedName());
+ element = element.getParent();
+ }
+ Collections.reverse(path);
+ final StringBuilder sb = new StringBuilder(path.size() * 15);
+ for (final String part : path) {
+ sb.append("/"); //$NON-NLS-1$
+ sb.append(part);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public Object getAdapter(final Class adapter) {
+
+ if (adapter == IContentOutlinePage.class)
+ return new DocumentOutlinePage();
+ else if (adapter == IPropertySheetPage.class) {
+
+ final PropertySheetPage page = new PropertySheetPage();
+ page.setPropertySourceProvider(new IPropertySourceProvider() {
+ public IPropertySource getPropertySource(final Object object) {
+ if (object instanceof Element) {
+ final IStructuredSelection sel = (IStructuredSelection) vexWidget.getSelection();
+ final boolean multi = sel != null && sel.size() > 1;
+ final Validator validator = vexWidget.getDocument().getValidator();
+ return new ElementPropertySource((Element) object, validator, multi);
+ } else
+ return null;
+ }
+ });
+ return page;
+
+ } else if (adapter == IFindReplaceTarget.class)
+ return new AbstractRegExFindReplaceTarget() {
+
+ @Override
+ protected int getSelectionStart() {
+ return getVexWidget().getSelectionStart();
+ }
+
+ @Override
+ protected int getSelectionEnd() {
+ return getVexWidget().getSelectionEnd();
+ }
+
+ @Override
+ protected void setSelection(final int start, final int end) {
+ getVexWidget().moveTo(start);
+ getVexWidget().moveTo(end, true);
+ }
+
+ @Override
+ protected CharSequence getDocument() {
+ return new CharSequence() {
+
+ public CharSequence subSequence(final int start, final int end) {
+ return doc.getRawText(start, end);
+ }
+
+ public int length() {
+ return doc.getLength();
+ }
+
+ public char charAt(final int index) {
+ return doc.getCharacterAt(index);
+ }
+ };
+ }
+
+ @Override
+ protected void inDocumentReplaceSelection(final CharSequence text) {
+ final VexWidget vexWidget = getVexWidget();
+
+ // because of Undo this action must be atomic
+ vexWidget.beginWork();
+ try {
+ vexWidget.deleteSelection();
+ vexWidget.insertText(text.toString());
+ } finally {
+ vexWidget.endWork(true);
+ }
+ }
+
+ };
+ else
+ return super.getAdapter(adapter);
+ }
+
+}

Back to the top