org.eclipse.compare.internal.win32.WordMergeViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.compare.internal.win32.WordMergeViewer.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2011 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.compare.internal.win32;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.CompareViewerPane;
import org.eclipse.compare.IEditableContent;
import org.eclipse.compare.IPropertyChangeNotifier;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.contentmergeviewer.IFlushable;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.PageBook;

public class WordMergeViewer extends AbstractMergeViewer implements IFlushable, IPropertyChangeNotifier {

    private static final String RESOURCE_BUNDLE_NAME = "org.eclipse.compare.internal.win32.WordMergeViewer"; //$NON-NLS-1$

    private FormToolkit formToolkit;
    private PageBook composite;
    private Composite docArea;
    private Composite textArea;
    private Label description;
    private WordComparison wordArea;
    private boolean isDirty;
    private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
    private Action saveAction;
    private ResourceBundle resourceBundle;
    private Action inplaceAction;
    private long resultFileTimestamp = -1;

    public WordMergeViewer(Composite parent, CompareConfiguration configuration) {
        super(configuration);
        createContentArea(parent);
        getControl().addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                handleDispose();
            }
        });
        getControl().setData(CompareUI.COMPARE_VIEWER_TITLE, CompareWin32Messages.WordMergeViewer_1);
        IToolBarManager toolBarManager = CompareViewerPane.getToolBarManager(parent);
        if (toolBarManager != null) {
            toolBarManager.removeAll();
            initializeToolbar(toolBarManager);
        }
        updateEnablements();
    }

    private void createContentArea(Composite parent) {
        formToolkit = new FormToolkit(parent.getDisplay());
        composite = new PageBook(parent, SWT.NONE);
        createDocArea(composite);
        createTextArea(composite);
    }

    private void initializeToolbar(IToolBarManager toolBarManager) {
        toolBarManager.add(new Separator("modes")); //$NON-NLS-1$
        toolBarManager.add(new Separator("file")); //$NON-NLS-1$
        CompareConfiguration configuration = getConfiguration();
        // For now, only support saving if one side is editable
        if (configuration.isRightEditable() || configuration.isLeftEditable()
                && (configuration.isRightEditable() != configuration.isLeftEditable())) {
            saveAction = new Action() {
                public void run() {
                    saveDocument();
                }
            };
            initAction(saveAction, getResourceBundle(), "action.save."); //$NON-NLS-1$
            toolBarManager.appendToGroup("file", saveAction); //$NON-NLS-1$
        }

        inplaceAction = new Action(CompareWin32Messages.WordMergeViewer_2, Action.AS_CHECK_BOX) {
            public void run() {
                toggleInplaceExternalState();
            }
        };
        initAction(inplaceAction, getResourceBundle(), "action.inplace."); //$NON-NLS-1$
        toolBarManager.appendToGroup("modes", inplaceAction); //$NON-NLS-1$

        toolBarManager.update(true);
    }

    /*
     * Initialize the given Action from a ResourceBundle.
     */
    private static void initAction(IAction a, ResourceBundle bundle, String prefix) {

        String labelKey = "label"; //$NON-NLS-1$
        String tooltipKey = "tooltip"; //$NON-NLS-1$
        String imageKey = "image"; //$NON-NLS-1$
        String descriptionKey = "description"; //$NON-NLS-1$

        if (prefix != null && prefix.length() > 0) {
            labelKey = prefix + labelKey;
            tooltipKey = prefix + tooltipKey;
            imageKey = prefix + imageKey;
            descriptionKey = prefix + descriptionKey;
        }

        a.setText(getString(bundle, labelKey, labelKey));
        a.setToolTipText(getString(bundle, tooltipKey, null));
        a.setDescription(getString(bundle, descriptionKey, null));

        String relPath = getString(bundle, imageKey, null);
        if (relPath != null && relPath.trim().length() > 0) {

            String dPath;
            String ePath;

            if (relPath.indexOf("/") >= 0) { //$NON-NLS-1$
                String path = relPath.substring(1);
                dPath = 'd' + path;
                ePath = 'e' + path;
            } else {
                dPath = "dlcl16/" + relPath; //$NON-NLS-1$
                ePath = "elcl16/" + relPath; //$NON-NLS-1$
            }

            ImageDescriptor id = getImageDescriptor(dPath); // we set the disabled image first (see PR 1GDDE87)
            if (id != null)
                a.setDisabledImageDescriptor(id);
            id = getImageDescriptor(ePath);
            if (id != null) {
                a.setImageDescriptor(id);
                a.setHoverImageDescriptor(id);
            }
        }
    }

    private static ImageDescriptor getImageDescriptor(String relativePath) {
        IPath path = new Path("$nl$/icons/full/").append(relativePath);
        URL url = FileLocator.find(Activator.getDefault().getBundle(), path, null);
        if (url == null)
            return null;
        return ImageDescriptor.createFromURL(url);
    }

    private static String getString(ResourceBundle bundle, String key, String dfltValue) {

        if (bundle != null) {
            try {
                return bundle.getString(key);
            } catch (MissingResourceException x) {
                // fall through
            }
        }
        return dfltValue;
    }

    private ResourceBundle getResourceBundle() {
        if (resourceBundle == null) {
            resourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE_NAME);
        }
        return resourceBundle;
    }

    private Composite createComposite(Composite parent) {
        return formToolkit.createComposite(parent);
    }

    private void updateEnablements() {
        if (saveAction != null)
            saveAction.setEnabled(isDirty());
        inplaceAction.setChecked(wordArea.isInplace());
        inplaceAction.setEnabled(wordArea.isOpen());
    }

    private void createDocArea(PageBook book) {
        docArea = createComposite(book);
        docArea.setLayout(GridLayoutFactory.fillDefaults().create());
        wordArea = new WordComparison(docArea);
        IWorkbenchPart workbenchPart = getConfiguration().getContainer().getWorkbenchPart();
        if (workbenchPart != null) {
            wordArea.initializeWorkbenchMenus(workbenchPart.getSite().getWorkbenchWindow());
        }
        wordArea.getFrame().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        wordArea.getFrame().setBackground(formToolkit.getColors().getBackground());
        updateDirtyFlag();
    }

    private void createTextArea(PageBook book) {
        textArea = createComposite(book);
        textArea.setLayout(GridLayoutFactory.fillDefaults().extendedMargins(10, 10, 10, 10).create());
        description = formToolkit.createLabel(textArea, getTextDescription(), SWT.WRAP);
        description.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    }

    protected void saveDocument() {
        try {
            File result = getResultFile();
            wordArea.saveAsDocument(result.getAbsolutePath());
            // Forward the saved content to the save target
            IEditableContent saveTarget = getSaveTarget();
            if (saveTarget == null) {
                if (MessageDialog.openQuestion(WordMergeViewer.this.composite.getShell(), "Save to File?",
                        "The compare editor is not saveable. Would you like to save your changes to another file?")) {
                    FileDialog dialog = new FileDialog(WordMergeViewer.this.composite.getShell(), SWT.SAVE);
                    String filename = dialog.open();
                    if (filename != null) {
                        wordArea.saveAsDocument(filename);
                    }
                }
            } else {
                synchronized (result) {
                    if (result.exists()) {
                        saveTarget.setContent(asBytes(result));
                        resultFileTimestamp = result.lastModified();
                    }
                }
            }
            updateEnablements();
        } catch (IOException e) {
            ErrorDialog.openError(WordMergeViewer.this.composite.getShell(), null, null,
                    new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
        } catch (SWTException e) {
            ErrorDialog.openError(WordMergeViewer.this.composite.getShell(), null, null,
                    new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
        }
    }

    public void flush(IProgressMonitor monitor) {
        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                if (isReallyDirty())
                    saveDocument();
            }
        });
    }

    protected void toggleInplaceExternalState() {
        BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
            public void run() {
                try {
                    if (isReallyDirty()) {
                        // If the file is dirty, save the result file before switching so our changes are not lost
                        try {
                            File result = getResultFile();
                            wordArea.saveAsDocument(result.getAbsolutePath());
                        } catch (IOException e) {
                            throw new CoreException(
                                    new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
                        }
                    }
                    openComparison(!wordArea.isInplace());
                } catch (CoreException e) {
                    ErrorDialog.openError(WordMergeViewer.this.composite.getShell(), null, null, e.getStatus());
                    Activator.log(e);
                }
            }
        });
    }

    private boolean isReallyDirty() {
        return isDirty() || wordArea.isDirty();
    }

    private void openComparison(boolean inplace) throws CoreException {
        try {
            if (isOneSided()) {
                File file = getFileForSingleSide();
                if (file != null) {
                    try {
                        wordArea.openDocument(file.getAbsolutePath(), inplace);
                    } catch (SWTException e) {
                        throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                                NLS.bind(CompareWin32Messages.WordComparison_16, file.getAbsolutePath()), e));
                    }
                }
            } else {
                File left = getFileForLeft();
                File right = getFileForRight();
                if (left != null && right != null) {
                    File result = getResultFile();
                    int direction = getCompareInput().getKind() & Differencer.DIRECTION_MASK;
                    File base, revised;
                    if (direction == Differencer.RIGHT) {
                        base = left;
                        revised = right;
                    } else {
                        base = right;
                        revised = left;
                    }
                    synchronized (result) {
                        if (!result.exists()) {
                            wordArea.createWorkingCopy(base.getAbsolutePath(), revised.getAbsolutePath(),
                                    result.getAbsolutePath());
                            resultFileTimestamp = result.lastModified();
                            description.setText(getTextDescription());
                        }
                        try {
                            wordArea.openDocument(result.getAbsolutePath(), inplace);
                        } catch (SWTException e) {
                            throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                                    NLS.bind(CompareWin32Messages.WordComparison_16, result.getAbsolutePath()), e));
                        }
                    }
                }
            }
            if (wordArea.isInplace()) {
                composite.showPage(docArea);
            } else {
                composite.showPage(textArea);
            }
        } catch (SWTException e) {
            throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
        } catch (IOException e) {
            throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e.getMessage(), e));
        }
        updateEnablements();
    }

    private String getTextDescription() {
        if (saveAction != null && hasResultFile()) {
            IEditableContent saveTarget = getSaveTarget();
            String name = CompareWin32Messages.WordMergeViewer_3;
            if (saveTarget instanceof ITypedElement) {
                ITypedElement te = (ITypedElement) saveTarget;
                name = te.getName();
            }
            try {
                return NLS.bind(CompareWin32Messages.WordMergeViewer_4, getResultFile().getName(), name);
            } catch (IOException e) {
                // This shouldn't happen since the result file has already been created
            }
        }
        return CompareWin32Messages.WordMergeViewer_5;
    }

    public Control getControl() {
        return composite;
    }

    public void setInput(Object input) {
        super.setInput(input);
        try {
            openComparison(true);
        } catch (CoreException e) {
            ErrorDialog.openError(WordMergeViewer.this.composite.getShell(), null, null, e.getStatus());
            Activator.log(e);
        }
    }

    private void updateDirtyFlag() {
        final Runnable dirtyFlagUpdater = new Runnable() {
            public void run() {
                if (wordArea.getFrame().isDisposed())
                    return;
                boolean dirty = wordArea.isDirty();
                if (hasResultFile()) {
                    try {
                        File resultFile = getResultFile();
                        synchronized (resultFile) {
                            if (resultFile.exists()) {
                                long lastModified = resultFile.lastModified();
                                if (lastModified != resultFileTimestamp) {
                                    dirty = true;
                                }
                            }
                        }
                    } catch (IOException e) {
                        // Shouldn't happen since we only get the result file if it has already been created
                    }
                }
                if (isDirty() != dirty) {
                    setDirty(dirty);
                }
                composite.getDisplay().timerExec(1000, this);
            }
        };
        dirtyFlagUpdater.run();
    }

    protected boolean isDirty() {
        return isDirty;
    }

    protected void setDirty(boolean dirty) {
        if (isDirty != dirty) {
            isDirty = dirty;
            updateEnablements();
            firePropertyChange(CompareEditorInput.DIRTY_STATE, Boolean.valueOf(!isDirty), Boolean.valueOf(isDirty));
        }
    }

    private void firePropertyChange(String property, Object oldValue, Object newValue) {
        Object[] allListeners = listeners.getListeners();
        final PropertyChangeEvent event = new PropertyChangeEvent(this, property, oldValue, newValue);
        for (int i = 0; i < allListeners.length; i++) {
            final IPropertyChangeListener listener = (IPropertyChangeListener) allListeners[i];
            SafeRunner.run(new SafeRunnable() {
                public void run() throws Exception {
                    listener.propertyChange(event);
                }
            });
        }
    }

    public void addPropertyChangeListener(IPropertyChangeListener listener) {
        listeners.add(listener);
    }

    public void removePropertyChangeListener(IPropertyChangeListener listener) {
        listeners.remove(listener);
    }

    private void handleDispose() {
        BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
            public void run() {
                wordArea.dispose();
                formToolkit.dispose();
                reset();
            }
        });
    }

    protected void reset() {
        if (wordArea.isOpen()) {
            wordArea.close();
        }
        super.reset();
    }
}