com.aptana.ide.editor.css.MultiPageCSSEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.aptana.ide.editor.css.MultiPageCSSEditor.java

Source

/**
 * This file Copyright (c) 2005-2008 Aptana, Inc. This program is
 * dual-licensed under both the Aptana Public License and the GNU General
 * Public license. You may elect to use one or the other of these licenses.
 * 
 * This program is distributed in the hope that it will be useful, but
 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
 * NONINFRINGEMENT. Redistribution, except as permitted by whichever of
 * the GPL or APL you select, is prohibited.
 *
 * 1. For the GPL license (GPL), you can redistribute and/or modify this
 * program under the terms of the GNU General Public License,
 * Version 3, as published by the Free Software Foundation.  You should
 * have received a copy of the GNU General Public License, Version 3 along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Aptana provides a special exception to allow redistribution of this file
 * with certain other free and open source software ("FOSS") code and certain additional terms
 * pursuant to Section 7 of the GPL. You may view the exception and these
 * terms on the web at http://www.aptana.com/legal/gpl/.
 * 
 * 2. For the Aptana Public License (APL), this program and the
 * accompanying materials are made available under the terms of the APL
 * v1.0 which accompanies this distribution, and is available at
 * http://www.aptana.com/legal/apl/.
 * 
 * You may view the GPL, Aptana's exception and additional terms, and the
 * APL in the file titled license.html at the root of the corresponding
 * plugin containing this source file.
 * 
 * Any modifications to this file must keep this entire header intact.
 */
package com.aptana.ide.editor.css;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
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.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.EditorSite;
import org.eclipse.ui.internal.PopupMenuExtender;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.eclipse.ui.part.MultiPageSelectionProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IElementStateListener;
import org.eclipse.ui.texteditor.IStatusField;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorExtension;

import com.aptana.ide.core.FileUtils;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.core.StringUtils;
import com.aptana.ide.core.ui.CoreUIUtils;
import com.aptana.ide.core.ui.editors.ISaveAsEvent;
import com.aptana.ide.core.ui.editors.ISaveEvent;
import com.aptana.ide.editor.css.parsing.CSSMimeType;
import com.aptana.ide.editor.css.preferences.IPreferenceConstants;
import com.aptana.ide.editor.css.preview.CSSPreviewPropertyPage;
import com.aptana.ide.editor.css.preview.PreviewConfigurationPage;
import com.aptana.ide.editors.UnifiedEditorsPlugin;
import com.aptana.ide.editors.toolbar.ToolbarWidget;
import com.aptana.ide.editors.unified.ContributedBrowser;
import com.aptana.ide.editors.unified.ContributedOutline;
import com.aptana.ide.editors.unified.EditorFileContext;
import com.aptana.ide.editors.unified.IFileServiceChangeListener;
import com.aptana.ide.editors.unified.IUnifiedEditor;
import com.aptana.ide.editors.unified.IUnifiedEditorContributor;
import com.aptana.ide.editors.unified.PairMatch;
import com.aptana.ide.editors.unified.context.IContextAwareness;
import com.aptana.ide.views.outline.UnifiedOutlinePage;
import com.aptana.ide.views.outline.UnifiedQuickOutlinePage;

/** The tabbed style CSS editor. */
public class MultiPageCSSEditor extends MultiPageEditorPart
        implements ITextEditor, ITextEditorExtension, IUnifiedEditor {

    /** CSS source editor */
    private CSSEditor editor;
    private ToolbarWidget toolbar;
    private Composite displayArea;

    private SourceEditorSite _siteEditor;

    /**
     * prevTempFile
     */
    protected File prevTempFile = null;

    private IElementStateListener elementListener = new IElementStateListener() {

        public void elementMoved(Object originalElement, Object movedElement) {

        }

        public void elementDirtyStateChanged(Object element, boolean isDirty) {

        }

        public void elementDeleted(Object element) {
            if (element.equals(getEditorInput())) {
                IWorkbenchPartSite site = MultiPageCSSEditor.this.getSite();
                if (site == null) {
                    return;
                }
                IWorkbenchWindow window = site.getWorkbenchWindow();
                if (window == null) {
                    return;
                }
                IWorkbenchPage page = window.getActivePage();
                if (page == null) {
                    return;
                }
                page.closeEditor(MultiPageCSSEditor.this, true);
            }
        }

        public void elementContentReplaced(Object element) {

        }

        public void elementContentAboutToBeReplaced(Object element) {

        }

    };

    private IPropertyListener propertyListener = new IPropertyListener() {

        public void propertyChanged(Object source, int propId) {
            if (propId == IEditorPart.PROP_INPUT && source instanceof CSSEditor) {
                IEditorInput newInput = ((CSSEditor) source).getEditorInput();
                if (newInput != null) {
                    setInput(newInput);
                    setPartName(newInput.getName());
                    setTitleToolTip(newInput.getToolTipText());
                }
            }
        }

    };

    /** Manually created preview pages */
    private Map previews;

    private String url;

    /**
     * Creates a new multi page css editor
     */
    public MultiPageCSSEditor() {
        super();
        previews = new HashMap();
        editor = new CSSEditor();

    }

    /**
     * @see org.eclipse.ui.part.MultiPageEditorPart#createSite(org.eclipse.ui.IEditorPart)
     */
    protected IEditorSite createSite(IEditorPart editor) {
        this._siteEditor = new SourceEditorSite(this, editor, getEditorSite());
        return _siteEditor;
    }

    private void createPage0() {
        try {
            addPage(editor, getEditorInput());
            setPageText(0, " Source "); //$NON-NLS-1$
            setPartName(getEditorInput().getName());
            this.editor.addPropertyListener(propertyListener);
            this.editor.getDocumentProvider().addElementStateListener(elementListener);
        } catch (PartInitException e) {
            ErrorDialog.openError(getSite().getShell(), "Error creating nested text editor", null, e.getStatus()); //$NON-NLS-1$
        }
    }

    /**
     * @see org.eclipse.ui.part.MultiPageEditorPart#createPageContainer(org.eclipse.swt.widgets.Composite)
     */
    protected Composite createPageContainer(Composite parent) {
        displayArea = new Composite(parent, SWT.NONE);
        GridLayout daLayout = new GridLayout(1, true);
        daLayout.marginHeight = 0;
        daLayout.marginWidth = 0;
        displayArea.setLayout(daLayout);
        displayArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        IPreferenceStore store = CSSPlugin.getDefault().getPreferenceStore();
        boolean show = store.getBoolean(IPreferenceConstants.SHOW_CSS_TOOLBAR);
        if (show) {
            toolbar = new ToolbarWidget(new String[] { CSSMimeType.MimeType },
                    new String[] { CSSMimeType.MimeType }, CSSPlugin.getDefault().getPreferenceStore(),
                    IPreferenceConstants.LINK_CURSOR_WITH_CSS_TOOLBAR_TAB, this);
            toolbar.createControl(displayArea);
        }
        Composite editorArea = new Composite(displayArea, SWT.NONE);
        editorArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout eaLayout = new GridLayout(1, true);
        eaLayout.marginHeight = 0;
        eaLayout.marginWidth = 0;
        editorArea.setLayout(new FillLayout());
        return editorArea;
    }

    /**
     * @see org.eclipse.ui.part.MultiPageEditorPart#createPages()
     */
    protected void createPages() {

        getSite().setSelectionProvider(new MultiPageSelectionProvider(this));
        if (getContainer() instanceof CTabFolder) {
            final CTabFolder tabs = (CTabFolder) getContainer();

            tabs.addListener(SWT.Traverse, new Listener() {

                public void handleEvent(Event event) {
                    if (tabs.getItemCount() == 1 && displayArea != null && !displayArea.isDisposed()) {
                        Composite parent = displayArea.getParent();
                        if (parent != null && parent.getParent() != null) {
                            if (event.keyCode == SWT.PAGE_UP) {
                                parent.getParent().traverse(SWT.TRAVERSE_PAGE_PREVIOUS);
                            } else if (event.keyCode == SWT.PAGE_DOWN) {
                                parent.getParent().traverse(SWT.TRAVERSE_PAGE_NEXT);
                            }
                        }
                    }
                }

            });

            Composite toolbar = new Composite(tabs, SWT.NONE);
            toolbar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END, GridData.VERTICAL_ALIGN_BEGINNING));
            GridLayout layout = new GridLayout(1, true);
            final ToolBar tb = new ToolBar(toolbar, SWT.FLAT);
            GridData tbData = new GridData(GridData.HORIZONTAL_ALIGN_END);
            tabs.setTabHeight(21);
            tb.setLayoutData(tbData);
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            toolbar.setLayout(layout);
            tb.setLayout(layout);
            tb.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
            final ToolItem configure = new ToolItem(tb, SWT.DROP_DOWN);
            configure.setImage(CSSPlugin.getImage("icons/configure.gif")); //$NON-NLS-1$
            configure.setToolTipText(Messages.MultiPageCSSEditor_TTP_ConfigureCSSPreview);
            configure.addSelectionListener(new SelectionAdapter() {

                public void widgetSelected(SelectionEvent e) {
                    if (e.detail != SWT.ARROW) {
                        PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(
                                Display.getDefault().getActiveShell(),
                                "com.aptana.ide.editor.css.preferences.PreviewPreferencePage", //$NON-NLS-1$
                                new String[] { "com.aptana.ide.editor.css.preferences.PreviewPreferencePage" }, //$NON-NLS-1$
                                null);
                        dialog.open();
                    }
                }

            });
            final Menu menu = new Menu(tabs.getShell(), SWT.POP_UP);
            MenuItem editTemplate = new MenuItem(menu, SWT.PUSH);
            editTemplate.setText(Messages.MultiPageCSSEditor_LBL_EditDefaultPreviewTemplate);
            editTemplate.addSelectionListener(new SelectionAdapter() {

                public void widgetSelected(SelectionEvent e) {
                    PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(
                            Display.getDefault().getActiveShell(),
                            "com.aptana.ide.editor.css.preferences.PreviewPreferencePage", //$NON-NLS-1$
                            new String[] { "com.aptana.ide.editor.css.preferences.PreviewPreferencePage" }, null); //$NON-NLS-1$
                    dialog.open();
                }

            });
            MenuItem editFileSettings = new MenuItem(menu, SWT.PUSH);
            if (getEditorInput() instanceof IFileEditorInput) {
                editFileSettings.setText(Messages.MultiPageCSSEditor_LB_FilePreviewSettings);
                editFileSettings.addSelectionListener(new SelectionAdapter() {

                    public void widgetSelected(SelectionEvent e) {
                        if (getEditorInput() instanceof IFileEditorInput) {
                            IFile file = ((IFileEditorInput) getEditorInput()).getFile();
                            PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(
                                    Display.getDefault().getActiveShell(), file,
                                    "com.aptana.ide.editor.css.preview.cssPreviewPropertyPage", //$NON-NLS-1$
                                    new String[] { "com.aptana.ide.editor.css.preview.cssPreviewPropertyPage" }, //$NON-NLS-1$
                                    null);
                            dialog.open();
                        }
                    }
                });
                MenuItem editProjectSettings = new MenuItem(menu, SWT.PUSH);
                editProjectSettings.setText(Messages.MultiPageCSSEditor_LBL_ProjectPreviewSettings);
                editProjectSettings.addSelectionListener(new SelectionAdapter() {

                    public void widgetSelected(SelectionEvent e) {
                        if (getEditorInput() instanceof IFileEditorInput) {
                            IFile file = ((IFileEditorInput) getEditorInput()).getFile();
                            PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(
                                    Display.getDefault().getActiveShell(), file.getProject(),
                                    "com.aptana.ide.editor.css.preview.cssPreviewPropertyPage", //$NON-NLS-1$
                                    new String[] { "com.aptana.ide.editor.css.preview.cssPreviewPropertyPage" }, //$NON-NLS-1$
                                    null);
                            dialog.open();
                        }
                    }
                });
            }
            MenuItem editWorkspaceSettings = new MenuItem(menu, SWT.PUSH);
            editWorkspaceSettings.setText(Messages.MultiPageCSSEditor_LBL_WorkspacePreviewSettings);
            editWorkspaceSettings.addSelectionListener(new SelectionAdapter() {

                public void widgetSelected(SelectionEvent e) {
                    PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(
                            Display.getDefault().getActiveShell(),
                            "com.aptana.ide.editor.css.preferences.PreviewPreferencePage", //$NON-NLS-1$
                            new String[] { "com.aptana.ide.editor.css.preferences.PreviewPreferencePage" }, null); //$NON-NLS-1$
                    dialog.open();
                }

            });
            configure.addSelectionListener(new SelectionAdapter() {

                public void widgetSelected(SelectionEvent e) {
                    if (e.detail == SWT.ARROW) {
                        Rectangle rect = configure.getBounds();
                        Point pt = new Point(rect.x, rect.y + rect.height);
                        pt = tb.toDisplay(pt);
                        menu.setLocation(pt.x, pt.y);
                        menu.setVisible(true);
                    } else {

                    }
                }

            });

            tabs.setTopRight(toolbar, SWT.RIGHT);
        }
        createPage0();
        loadBrowsers();
    }

    // private void loadPreviewPages()
    // {
    // String name = CoreUIUtils.getPathFromEditorInput(getEditorInput());
    // if (name == null)
    // {
    // return;
    // }
    // String[] pNames = PreviewPageManager.getNames(name);
    // String[] pBrowsers = PreviewPageManager.getBrowsers(name);
    // String[] pUrls = PreviewPageManager.getURLs(name);
    // if (pNames.length == pBrowsers.length && pNames.length == pUrls.length)
    // {
    // for (int i = 0; i < pNames.length; i++)
    // {
    // PreviewConfigurationPage page = new PreviewConfigurationPage(MultiPageHTMLEditor.this);
    // page.createControl(getContainer());
    // page.setURL(pUrls[i]);
    // page.setTitle(pNames[i]);
    // IExtensionRegistry reg = Platform.getExtensionRegistry();
    // IExtensionPoint ep = reg.getExtensionPoint(UnifiedEditorsPlugin.BROWSER_EXTENSION_POINT);
    // IExtension[] extensions = ep.getExtensions();
    // ContributedBrowser browser = null;
    // for (int k = 0; k < extensions.length && browser == null; k++)
    // {
    // IConfigurationElement[] ce = extensions[k].getConfigurationElements();
    // for (int j = 0; j < ce.length && browser == null; j++)
    // {
    // String browserClass = ce[j].getAttribute(UnifiedEditorsPlugin.CLASS_ATTR);
    // if (pBrowsers[i].equals(BrowserExtensionLoader.getBrowserLabel(ce[j])))
    // {
    // if (browserClass != null && name != null)
    // {
    // try
    // {
    // Object obj = ce[j].createExecutableExtension(UnifiedEditorsPlugin.CLASS_ATTR);
    // if (obj instanceof ContributedBrowser)
    // {
    // browser = (ContributedBrowser) obj;
    // }
    // }
    // catch (CoreException e)
    // {
    // }
    // }
    // }
    //
    // }
    // }
    // if (browser != null)
    // {
    // page.setBrowser(browser, pBrowsers[i]);
    // page.showBrowserArea();
    // int index = addPage(page.getControl());
    // previews.put(Integer.toString(index), page);
    // page.setIndex(index);
    // setPageText(index, page.getTitle());
    // }
    // }
    // }
    // }

    /**
     * Saves the preview pages
     */
    // public void savePreviewsPages()
    // {
    // String name = CoreUIUtils.getPathFromEditorInput(getEditorInput());
    // if (name == null)
    // {
    // return;
    // }
    // Iterator iter = previews.values().iterator();
    // StringBuffer names = new StringBuffer("");
    // StringBuffer urls = new StringBuffer("");
    // StringBuffer browser = new StringBuffer("");
    // while (iter.hasNext())
    // {
    // PreviewConfigurationPage page = (PreviewConfigurationPage) iter.next();
    // names.append(page.getTitle() + PreviewPageManager.PREFERENCE_DELIMITER);
    // urls.append(page.getURL() + PreviewPageManager.PREFERENCE_DELIMITER);
    // browser.append(page.getBrowserLabel() + PreviewPageManager.PREFERENCE_DELIMITER);
    // }
    // PreviewPageManager.setBrowser(name, browser.toString());
    // PreviewPageManager.setName(name, names.toString());
    // PreviewPageManager.setURL(name, urls.toString());
    // }
    /**
     * @param index
     * @param title
     */
    public void setPreviewPageText(int index, String title) {
        setPageText(index, title);
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#dispose()
     */
    public void dispose() {
        if (editor != null) {
            if (editor.getDocumentProvider() != null) {
                editor.getDocumentProvider().removeElementStateListener(elementListener);
            }
            editor.removePropertyListener(propertyListener);
            editor.dispose();
        }

        if (previews != null && previews.size() != 0) {
            disposePreviews();
            previews = null;
        }

        if (this.toolbar != null) {
            this.toolbar.dispose();
        }

        editor = null;
        _siteEditor = null;

        super.dispose();
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    public void doSave(IProgressMonitor monitor) {
        IEditorPart editor = getEditor(0);
        editor.doSave(monitor);
        setInput(editor.getEditorInput());
        setPartName(getEditorInput().getName());
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
     */
    public void doSaveAs() {
        IEditorPart editor = getEditor(0);
        editor.doSaveAs();
        setInput(editor.getEditorInput());
        setPartName(getEditorInput().getName());
    }

    /**
     * gotoMarker
     * 
     * @param marker
     */
    public void gotoMarker(IMarker marker) {
        setActivePage(0);
        IDE.gotoMarker(getEditor(0), marker);
    }

    /**
     * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
     */
    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
        super.init(site, editorInput);
        ICommandService commandService = (ICommandService) site.getService(ICommandService.class);
        final Command nextMultipageEditorTabCommand = commandService
                .getCommand("com.aptana.ide.editors.nextMultipageEditorTab"); //$NON-NLS-1$
        final Command previousMultipageEditorTabCommand = commandService
                .getCommand("com.aptana.ide.editors.previousMultipageEditorTab"); //$NON-NLS-1$
        IHandlerService handlerService = (IHandlerService) site.getService(IHandlerService.class);
        handlerService.activateHandler(nextMultipageEditorTabCommand.getId(), new AbstractHandler() {
            public Object execute(ExecutionEvent event) throws ExecutionException {
                gotoNextMultipageEditorTab();
                return null;
            }
        });
        handlerService.activateHandler(previousMultipageEditorTabCommand.getId(), new AbstractHandler() {
            public Object execute(ExecutionEvent event) throws ExecutionException {
                gotoPreviousMultipageEditorTab();
                return null;
            }
        });
    }

    private void gotoNextMultipageEditorTab() {
        Composite comp = getContainer();
        if (comp instanceof CTabFolder) {
            CTabFolder tabFolder = (CTabFolder) comp;
            int itemCount = tabFolder.getItemCount();
            if (itemCount > 1) {
                int selectionIndex = tabFolder.getSelectionIndex();
                selectionIndex++;
                if (selectionIndex >= itemCount) {
                    selectionIndex = 0;
                }
                setActivePage(selectionIndex);
            }
        }
    }

    private void gotoPreviousMultipageEditorTab() {
        Composite comp = getContainer();
        if (comp instanceof CTabFolder) {
            CTabFolder tabFolder = (CTabFolder) comp;
            int itemCount = tabFolder.getItemCount();
            if (itemCount > 1) {
                int selectionIndex = tabFolder.getSelectionIndex();
                selectionIndex--;
                if (selectionIndex < 0) {
                    selectionIndex = itemCount - 1;
                }
                setActivePage(selectionIndex);
            }
        }
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
     */
    public boolean isSaveAsAllowed() {
        return true;
    }

    /**
     * Change to the source editor, and move caret to the specified offset.
     * 
     * @param offset
     */
    public void setOffset(int offset) {
        setActivePage(0);
        editor.selectAndReveal(offset, 0);
    }

    /**
     * Sets the toolbar as visible or not
     * 
     * @param visible -
     *            true if visible
     */
    public void setToolbarVisible(boolean visible) {
        if (toolbar != null && visible != toolbar.isVisible()) {
            toolbar.setVisible(visible);
            displayArea.setRedraw(false);
            displayArea.layout(true, true);
            displayArea.setRedraw(true);
        }
    }

    /**
     * @see org.eclipse.ui.part.MultiPageEditorPart#pageChange(int)
     */
    protected void pageChange(int newPageIndex) {
        super.pageChange(newPageIndex);
        if (newPageIndex > 0) {
            updatePreview();
            setToolbarVisible(false);
        } else if (newPageIndex == 0) {
            setToolbarVisible(true);
        }
    }

    private String getExternalPreviewUrl(IEditorInput input) throws CoreException {

        String url = null;
        FileEditorInput fei = (FileEditorInput) input;
        IFile file = fei.getFile();
        IProject project = file.getProject();
        url = file.getPersistentProperty(new QualifiedName("", CSSPreviewPropertyPage.CSS_PREVIEW_PATH)); //$NON-NLS-1$

        // If no file url, use project url if it exists
        if (url == null) {
            url = project.getPersistentProperty(new QualifiedName("", CSSPreviewPropertyPage.CSS_PREVIEW_PATH)); //$NON-NLS-1$
        }

        return url;
    }

    private void updatePreview() {
        String url = null;
        IEditorInput input = this.editor.getEditorInput();
        try {
            if (input instanceof FileEditorInput) {
                url = getExternalPreviewUrl(input);
            }

            if (url != null && !"".equals(url)) //$NON-NLS-1$
            {
                this.setBrowserURL(url);
            } else {
                boolean useTemplate = CSSPlugin.getDefault().getPreferenceStore()
                        .getBoolean(IPreferenceConstants.CSSEDITOR_BROWSER_USE_TEMPLATE_PREFERENCE);
                if (!useTemplate) {
                    url = CSSPlugin.getDefault().getPreferenceStore()
                            .getString(IPreferenceConstants.CSSEDITOR_BROWSER_URL_PREFERENCE);
                    this.setBrowserURL(url);
                } else {
                    IDocumentProvider docProvider = editor.getDocumentProvider();
                    String css = docProvider.getDocument(input).get();
                    IPreferenceStore store = CSSPlugin.getDefault().getPreferenceStore();
                    String template = store.getString(IPreferenceConstants.CSSEDITOR_BROWSER_TEMPLATE_PREFERENCE);
                    css = "<html>" + template + "<style>" + css + "</style></html>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    String charset = null;

                    if (input instanceof IFileEditorInput) {
                        charset = ((IFileEditorInput) input).getFile().getCharset();
                    } else if (docProvider instanceof TextFileDocumentProvider) {
                        charset = ((TextFileDocumentProvider) docProvider).getEncoding(input);
                        if (charset == null) {
                            charset = ((TextFileDocumentProvider) docProvider).getDefaultEncoding();
                        }
                    }

                    File tmpFile;
                    tmpFile = writeTemporaryPreviewFile(editor, input, css, charset);
                    String tmpUrl = CoreUIUtils.getURI(tmpFile, false);

                    if (prevTempFile != null && prevTempFile.equals(tmpFile)) {
                        setBrowserURL(tmpUrl);
                    } else {
                        if (prevTempFile != null) {
                            prevTempFile.delete();
                        }
                        prevTempFile = tmpFile;
                        setBrowserURL(tmpUrl);
                    }
                }
            }
        } catch (Exception e) {
            IdeLog.logError(CSSPlugin.getDefault(), Messages.MultiPageCSSEditor_ERR_UnableToUpdatePreview, e);
        }
    }

    private File writeTemporaryPreviewFile(CSSEditor editor, IEditorInput input, String html, String charset)
            throws CoreException, FileNotFoundException, UnsupportedEncodingException {

        File tmpFile = editor.getTempFile();

        if (tmpFile.exists()) {
            tmpFile.delete();
        }

        FileOutputStream out = new FileOutputStream(tmpFile);
        PrintWriter pw = null;

        if (charset != null) {
            pw = new PrintWriter(new OutputStreamWriter(out, charset), true);
        } else {
            pw = new PrintWriter(new OutputStreamWriter(out), true);
        }

        pw.write(html);
        pw.close();

        try {
            out.close();
        } catch (IOException e) {
        }

        // Delete this file on exit, and hide it from windows
        tmpFile.deleteOnExit();
        FileUtils.setHidden(tmpFile);

        return tmpFile;
    }

    /**
     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
     */
    public Object getAdapter(Class adapter) {

        // Context is just plugin ID + name of class. Matches contexts.xml file
        if (editor != null) {
            return editor.getAdapter(adapter);
        } else {
            return null;
        }
    }

    /** IEditorSite for the source editor. */
    private static class SourceEditorSite extends MultiPageEditorSite {

        private CSSEditor _editor = null;
        private IEditorSite _site;
        private ArrayList _menuExtenders;
        private boolean isDisposing = false;

        /**
         * SourceEditorSite
         * 
         * @param multiPageEditor
         * @param editor
         * @param site
         */
        public SourceEditorSite(MultiPageEditorPart multiPageEditor, IEditorPart editor, IEditorSite site) {
            super(multiPageEditor, editor);
            this._site = site;
            this._editor = (CSSEditor) editor;
        }

        /**
         * @see org.eclipse.ui.part.MultiPageEditorSite#getId()
         */
        public String getId() {
            return _site.getId();
        }

        /**
         * @see org.eclipse.ui.IEditorSite#getActionBarContributor()
         */
        public IEditorActionBarContributor getActionBarContributor() {
            return _site.getActionBarContributor();
        }

        /**
         * @see org.eclipse.ui.IWorkbenchPartSite#registerContextMenu(java.lang.String,
         *      org.eclipse.jface.action.MenuManager, org.eclipse.jface.viewers.ISelectionProvider)
         */
        public void registerContextMenu(String menuId, MenuManager menuManager,
                ISelectionProvider selectionProvider) {
            if (_editor != null) {
                if (_menuExtenders == null) {
                    _menuExtenders = new ArrayList(1);
                }
                _menuExtenders.add(new PopupMenuExtender(menuId, menuManager, selectionProvider, _editor));
            }
        }

        /**
         * @see org.eclipse.ui.part.MultiPageEditorSite#dispose()
         */
        public void dispose() {
            if (isDisposing) {
                return;
            }
            isDisposing = true;

            super.dispose();

            if (_menuExtenders != null) {
                for (int i = 0; i < _menuExtenders.size(); i++) {
                    ((PopupMenuExtender) _menuExtenders.get(i)).dispose();
                }
                _menuExtenders = null;
            }

            _editor = null;
            if (_site != null && _site instanceof EditorSite) {
                ((EditorSite) _site).dispose();
            }
            _site = null;

        }

        /**
         * @see org.eclipse.ui.IWorkbenchPartSite#getKeyBindingService()
         */
        public IKeyBindingService getKeyBindingService() {
            return _site.getKeyBindingService();
        }

        /**
         * @see org.eclipse.ui.IWorkbenchPartSite#getPluginId()
         */
        public String getPluginId() {
            return _site.getPluginId();
        }

        /**
         * @see org.eclipse.ui.IWorkbenchPartSite#getRegisteredName()
         */
        public String getRegisteredName() {
            return _site.getRegisteredName();
        }

        /**
         * @see org.eclipse.ui.IWorkbenchPartSite#registerContextMenu(org.eclipse.jface.action.MenuManager,
         *      org.eclipse.jface.viewers.ISelectionProvider)
         */
        public void registerContextMenu(MenuManager menuManager, ISelectionProvider selProvider) {
            _site.registerContextMenu(menuManager, selProvider);
        }
    }

    private void setBrowserURL(String url) {
        String index = Integer.toString(this.getActivePage());
        if ((previews.containsKey(index))) {
            ((PreviewConfigurationPage) previews.get(index)).setURL(url);
        }
        this.url = url;
    }

    /**
     * Gets the url of this editor
     * 
     * @return - url
     */
    public String getURL() {
        return this.url;
    }

    private void loadBrowsers() {
        previews.clear();
        List browserList = BrowserExtensionLoader.loadBrowsers();
        for (int j = 0; j < browserList.size(); j++) {
            IConfigurationElement element = (IConfigurationElement) browserList.get(j);
            String name = BrowserExtensionLoader.getBrowserLabel(element);
            String outlineClass = element.getAttribute(UnifiedEditorsPlugin.OUTLINE_ATTR);
            try {
                Object obj = element.createExecutableExtension(UnifiedEditorsPlugin.CLASS_ATTR);
                if (obj instanceof ContributedBrowser) {
                    ContributedBrowser browser = (ContributedBrowser) obj;
                    PreviewConfigurationPage page = new PreviewConfigurationPage(this);
                    page.createControl(getContainer());
                    page.setBrowser(browser, name);
                    page.setTitle(StringUtils.format(Messages.MultiPageCSSEditor_TTL_Preview, name));
                    page.showBrowserArea();
                    int index = addPage(page.getControl());
                    previews.put(Integer.toString(index), page);
                    page.setIndex(index);
                    setPageText(index, StringUtils.SPACE + page.getTitle() + StringUtils.SPACE);
                    browser.getControl().addKeyListener(new KeyAdapter() {
                        public void keyReleased(KeyEvent e) {
                            ((CTabFolder) getContainer()).traverse(SWT.TRAVERSE_TAB_NEXT);
                        }
                    });

                    if (outlineClass != null) {
                        Object ol = element.createExecutableExtension(UnifiedEditorsPlugin.OUTLINE_ATTR);
                        if (ol instanceof ContributedOutline) {
                            ContributedOutline outline = (ContributedOutline) ol;
                            browser.setOutline(outline);
                            outline.setBrowser(browser);
                            editor.getOutlinePage().addOutline(outline, name);
                        }
                    }
                }
            } catch (Exception e) {
                IdeLog.logError(CSSPlugin.getDefault(),
                        StringUtils.format(Messages.MultiPageCSSEditor_ERR_UnableToCreateBrowserControl, name), e);
            } catch (Error e) {
                IdeLog.logError(CSSPlugin.getDefault(),
                        StringUtils.format(Messages.MultiPageCSSEditor_ERR_UnableToCreateBrowserControl, name), e);
            }
        }
    }

    /**
     * Saves the preview pages
     */
    public void savePreviewsPages() {
        // Does nothing
    }

    private void disposePreviews() {
        Object[] _previews = previews.values().toArray();
        for (int i = 0; i < _previews.length; i++) {
            ((PreviewConfigurationPage) _previews[i]).dispose();
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#addFileServiceChangeListener(com.aptana.ide.editors.unified.IFileServiceChangeListener)
     */
    public void addFileServiceChangeListener(IFileServiceChangeListener listener) {
        if (editor != null) {
            editor.addFileServiceChangeListener(listener);
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#close(boolean)
     */
    public void close(boolean save) {
        if (editor != null) {
            editor.close(save);
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getBaseContributor()
     */
    public IUnifiedEditorContributor getBaseContributor() {
        if (editor != null) {
            return editor.getBaseContributor();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getConfiguration()
     */
    public SourceViewerConfiguration getConfiguration() {
        if (editor != null) {
            return editor.getConfiguration();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getContextAwareness()
     */
    public IContextAwareness getContextAwareness() {
        if (editor != null) {
            return editor.getContextAwareness();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getDefaultFileExtension()
     */
    public String getDefaultFileExtension() {
        if (editor != null) {
            return editor.getDefaultFileExtension();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getDocumentProvider()
     */
    public IDocumentProvider getDocumentProvider() {
        if (editor != null) {
            return editor.getDocumentProvider();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getEditor()
     */
    public IEditorPart getEditor() {
        if (editor != null) {
            return editor.getEditor();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getFileContext()
     */
    public EditorFileContext getFileContext() {
        if (editor != null) {
            return editor.getFileContext();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getOutlinePage()
     */
    public UnifiedOutlinePage getOutlinePage() {
        if (editor != null) {
            return editor.getOutlinePage();
        }
        return null;
    }

    /**
      * {@inheritDoc}
      */
    public UnifiedQuickOutlinePage createQuickOutlinePage() {
        return editor.createQuickOutlinePage();
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getPairMatch(int)
     */
    public PairMatch getPairMatch(int offset) {
        if (editor != null) {
            return editor.getPairMatch(offset);
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getParentDirectoryHint()
     */
    public String getParentDirectoryHint() {
        if (editor != null) {
            return editor.getParentDirectoryHint();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#getViewer()
     */
    public ISourceViewer getViewer() {
        if (editor != null) {
            return editor.getViewer();
        }
        return null;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#removeFileServiceChangeListener(com.aptana.ide.editors.unified.IFileServiceChangeListener)
     */
    public void removeFileServiceChangeListener(IFileServiceChangeListener listener) {
        if (editor != null) {
            editor.removeFileServiceChangeListener(listener);
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#selectAndReveal(int, int)
     */
    public void selectAndReveal(int offset, int length) {
        if (editor != null) {
            editor.selectAndReveal(offset, length);
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#setParentDirectoryHint(java.lang.String)
     */
    public void setParentDirectoryHint(String hint) {
        if (editor != null) {
            editor.setParentDirectoryHint(hint);
        }
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#showWhitespace(boolean)
     */
    public void showWhitespace(boolean state) {
        if (editor != null) {
            editor.showWhitespace(state);
        }
    }

    /**
     * @see com.aptana.ide.core.ui.editors.ISaveEventListener#addSaveAsListener(com.aptana.ide.core.ui.editors.ISaveAsEvent)
     */
    public void addSaveAsListener(ISaveAsEvent listener) {
        if (editor != null) {
            editor.addSaveAsListener(listener);
        }
    }

    /**
     * @see com.aptana.ide.core.ui.editors.ISaveEventListener#addSaveListener(com.aptana.ide.core.ui.editors.ISaveEvent)
     */
    public void addSaveListener(ISaveEvent listener) {
        if (editor != null) {
            editor.addSaveListener(listener);
        }
    }

    /**
     * @see com.aptana.ide.core.ui.editors.ISaveEventListener#removeSaveAsListener(com.aptana.ide.core.ui.editors.ISaveAsEvent)
     */
    public void removeSaveAsListener(ISaveAsEvent listener) {
        if (editor != null) {
            editor.removeSaveAsListener(listener);
        }
    }

    /**
     * @see com.aptana.ide.core.ui.editors.ISaveEventListener#removeSaveListener(com.aptana.ide.core.ui.editors.ISaveEvent)
     */
    public void removeSaveListener(ISaveEvent listener) {
        if (editor != null) {
            editor.removeSaveListener(listener);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#doRevertToSaved()
     */
    public void doRevertToSaved() {
        if (editor != null) {
            editor.doRevertToSaved();
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#getAction(java.lang.String)
     */
    public IAction getAction(String actionId) {
        if (editor != null) {
            return editor.getAction(actionId);
        }
        return null;
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#getHighlightRange()
     */
    public IRegion getHighlightRange() {
        if (editor != null) {
            return editor.getHighlightRange();
        }
        return null;
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#getSelectionProvider()
     */
    public ISelectionProvider getSelectionProvider() {
        if (editor != null) {
            return editor.getSelectionProvider();
        }
        return null;
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#isEditable()
     */
    public boolean isEditable() {
        if (editor != null) {
            return editor.isEditable();
        }
        return false;
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#removeActionActivationCode(java.lang.String)
     */
    public void removeActionActivationCode(String actionId) {
        if (editor != null) {
            editor.removeActionActivationCode(actionId);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#resetHighlightRange()
     */
    public void resetHighlightRange() {
        if (editor != null) {
            editor.resetHighlightRange();
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#setAction(java.lang.String, org.eclipse.jface.action.IAction)
     */
    public void setAction(String actionID, IAction action) {
        if (editor != null) {
            editor.setAction(actionID, action);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#setActionActivationCode(java.lang.String, char, int, int)
     */
    public void setActionActivationCode(String actionId, char activationCharacter, int activationKeyCode,
            int activationStateMask) {
        if (editor != null) {
            editor.setActionActivationCode(actionId, activationCharacter, activationKeyCode, activationStateMask);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#setHighlightRange(int, int, boolean)
     */
    public void setHighlightRange(int offset, int length, boolean moveCursor) {
        if (editor != null) {
            editor.setHighlightRange(offset, length, moveCursor);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#showHighlightRangeOnly(boolean)
     */
    public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
        if (editor != null) {
            editor.showHighlightRangeOnly(showHighlightRangeOnly);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditor#showsHighlightRangeOnly()
     */
    public boolean showsHighlightRangeOnly() {
        if (editor != null) {
            return editor.showsHighlightRangeOnly();
        }
        return false;
    }

    /**
     * @see com.aptana.ide.editors.unified.IUnifiedEditor#showPianoKeys(boolean)
     */
    public void showPianoKeys(boolean state) {
        if (editor != null) {
            editor.showPianoKeys(state);
        }
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditorExtension#addRulerContextMenuListener(IMenuListener)
     */
    public void addRulerContextMenuListener(IMenuListener listener) {
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditorExtension#isEditorInputReadOnly()
     */
    public boolean isEditorInputReadOnly() {
        if (editor == null) {
            return false;
        }

        return editor.isEditorInputReadOnly();
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditorExtension#removeRulerContextMenuListener(IMenuListener)
     */
    public void removeRulerContextMenuListener(IMenuListener listener) {
    }

    /**
     * @see org.eclipse.ui.texteditor.ITextEditorExtension#setStatusField(IStatusField, String)
     */
    public void setStatusField(IStatusField field, String category) {
        if (editor == null) {
            return;
        }

        editor.setStatusField(field, category);
    }
}