ro.sync.ecss.extensions.commons.editor.URLChooserEditorSWT.java Source code

Java tutorial

Introduction

Here is the source code for ro.sync.ecss.extensions.commons.editor.URLChooserEditorSWT.java

Source

/*
 *  The Syncro Soft SRL License
 *
 *  Copyright (c) 1998-2012 Syncro Soft SRL, Romania.  All rights
 *  reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistribution of source or in binary form is allowed only with
 *  the prior written permission of Syncro Soft SRL.
 *
 *  2. Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *  3. Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the
 *  distribution.
 *
 *  4. The end-user documentation included with the redistribution,
 *  if any, must include the following acknowledgment:
 *  "This product includes software developed by the
 *  Syncro Soft SRL (http://www.sync.ro/)."
 *  Alternately, this acknowledgment may appear in the software itself,
 *  if and wherever such third-party acknowledgments normally appear.
 *
 *  5. The names "Oxygen" and "Syncro Soft SRL" must
 *  not be used to endorse or promote products derived from this
 *  software without prior written permission. For written
 *  permission, please contact support@oxygenxml.com.
 *
 *  6. Products derived from this software may not be called "Oxygen",
 *  nor may "Oxygen" appear in their name, without prior written
 *  permission of the Syncro Soft SRL.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED.  IN NO EVENT SHALL THE SYNCRO SOFT SRL OR
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 *  SUCH DAMAGE.
 */
package ro.sync.ecss.extensions.commons.editor;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
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.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;

import ro.sync.annotations.api.API;
import ro.sync.annotations.api.APIType;
import ro.sync.annotations.api.SourceType;
import ro.sync.ecss.extensions.api.AuthorAccess;
import ro.sync.ecss.extensions.api.access.AuthorUtilAccess;
import ro.sync.ecss.extensions.api.editor.AbstractInplaceEditor;
import ro.sync.ecss.extensions.api.editor.AuthorInplaceContext;
import ro.sync.ecss.extensions.api.editor.EditingEvent;
import ro.sync.ecss.extensions.api.editor.InplaceEditorArgumentKeys;
import ro.sync.exml.view.graphics.Color;
import ro.sync.exml.view.graphics.Font;
import ro.sync.exml.view.graphics.Point;
import ro.sync.exml.view.graphics.Rectangle;

/**
 * URL Chooser in-place editor on Eclipse.
 * 
 * @author costi
 * @author adriana
 */
@API(type = APIType.INTERNAL, src = SourceType.PUBLIC)
public class URLChooserEditorSWT extends AbstractInplaceEditor implements ITextOperationTarget {

    /**
     * URL chooser composite.
     */
    private Composite urlChooserComposite;
    /**
     * Browse URL button.
     */
    private Button browseButton;

    /**
     * Text viewer.
     */
    private SourceViewer textViewer;

    /**
     * The image on the browse button.
     */
    private Image buttonImage;

    /**
     * <code>true</code> if the user is during browsing. 
     */
    private boolean isBrowsing = false;
    /**
     * Author Util.
     */
    private AuthorUtilAccess utilAccess;
    /**
     * The imposed font.
     */
    private org.eclipse.swt.graphics.Font swtFont;
    /**
     * Foreground color.
     */
    private org.eclipse.swt.graphics.Color foregroundColor;

    /**
     * Constructor.
     */
    public URLChooserEditorSWT() {
    }

    /**
     * @see ro.sync.ecss.extensions.api.Extension#getDescription()
     */
    @Override
    public String getDescription() {
        return "A sample implementation that provides a browse button associated with a text field.";
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#getEditorComponent(ro.sync.ecss.extensions.api.editor.AuthorInplaceContext, ro.sync.exml.view.graphics.Rectangle, ro.sync.exml.view.graphics.Point)
     */
    @Override
    public Object getEditorComponent(final AuthorInplaceContext context, Rectangle allocation,
            Point mouseInvocationLocation) {
        prepareComponents(context);

        // Get the editor location to make the selected URL relative.
        final AuthorAccess authorAccess = context.getAuthorAccess();
        final URL editorLocation = authorAccess.getEditorAccess().getEditorLocation();

        // Add selection listener
        browseButton.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event e) {
                // Assign the selected value to the text viewer.
                isBrowsing = true;
                try {
                    URL chooseURL = context.getAuthorAccess().getWorkspaceAccess().chooseURL("Choose URL", null,
                            null);
                    if (chooseURL != null) {
                        String relativeURL = context.getAuthorAccess().getUtilAccess().makeRelative(editorLocation,
                                chooseURL);

                        // EXM-25327 Do not insert the username and password in the document
                        utilAccess = authorAccess.getUtilAccess();
                        try {
                            URL clearedURL = utilAccess.removeUserCredentials(new URL(relativeURL));
                            textViewer.getTextWidget().setText(clearedURL.toExternalForm());
                        } catch (MalformedURLException e1) {
                            textViewer.getTextWidget().setText(relativeURL);
                        }

                        // EXM-25433 Commit to document.
                        fireCommitValue(new EditingEvent((String) getValue()));
                    }
                } finally {
                    isBrowsing = false;
                }
            }
        });

        // Add traverse listener
        browseButton.addTraverseListener(new TraverseListener() {
            @Override
            public void keyTraversed(TraverseEvent e) {
                if (e.detail == SWT.TRAVERSE_TAB_NEXT) {
                    fireNextEditLocationRequested();
                    e.doit = false;
                }

            }
        });

        textViewer.getTextWidget().addTraverseListener(new TraverseListener() {
            @Override
            public void keyTraversed(TraverseEvent e) {
                if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
                    firePreviousEditLocationRequested();
                    e.doit = false;
                }
            }
        });

        textViewer.getTextWidget().addVerifyKeyListener(new VerifyKeyListener() {
            @Override
            public void verifyKey(VerifyEvent event) {
                switch (event.keyCode) {
                case SWT.TAB:
                    // TAB takes us to the next edit position so we don't want it in the editor.
                    event.doit = false;
                    break;
                case SWT.CR:
                case SWT.KEYPAD_CR:
                case SWT.LF:
                    if ((event.stateMask & SWT.CONTROL) == 0) {
                        // Stop editing.
                        event.doit = false;
                        stopEditing(true);
                    }
                }
            }
        });

        return urlChooserComposite;
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#getScrollRectangle()
     */
    @Override
    public Rectangle getScrollRectangle() {
        return null;
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#requestFocus()
     */
    @Override
    public void requestFocus() {
        textViewer.getTextWidget().setFocus();
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#getValue()
     */
    @Override
    public Object getValue() {
        String text = textViewer.getTextWidget().getText();
        try {
            URL clearedURL = utilAccess.removeUserCredentials(new URL(text));
            return clearedURL.toExternalForm();
        } catch (MalformedURLException e) {
            return text;
        }
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#stopEditing()
     */
    @Override
    public void stopEditing() {
        stopEditing(false);
    }

    /**
     * @param onEnter <code>true</code> if editing stopped was triggered on Enter key pressed.
     */
    private void stopEditing(boolean onEnter) {
        String text = (String) getValue();
        if (onEnter) {
            fireNextEditLocationRequested();
        } else {
            fireEditingStopped(new EditingEvent(text));
        }
        dispose();
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#cancelEditing()
     */
    @Override
    public void cancelEditing() {
        fireEditingCanceled();
        dispose();
    }

    /**
     * Initialize components.
     * 
     * @param context The current context.
     */
    private void prepareComponents(AuthorInplaceContext context) {
        dispose();
        // Create the components.
        urlChooserComposite = new Composite((Composite) context.getParentHost(), SWT.NONE);
        GridLayout gridLayout = new GridLayout(2, false);
        gridLayout.marginWidth = gridLayout.marginHeight = 0;
        urlChooserComposite.setLayout(gridLayout);
        textViewer = new SourceViewer(urlChooserComposite, null, SWT.FILL | SWT.SINGLE | SWT.BORDER);
        textViewer.configure(new TextSourceViewerConfiguration(EditorsPlugin.getDefault().getPreferenceStore()));
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalIndent = 0;
        gd.verticalIndent = 0;
        textViewer.getTextWidget().setLayoutData(gd);
        browseButton = new Button(urlChooserComposite, SWT.PUSH);
        gd = new GridData(SWT.NONE, SWT.FILL, false, true);

        // Add required listeners.
        textViewer.getTextWidget().addVerifyKeyListener(new VerifyKeyListener() {
            @Override
            public void verifyKey(VerifyEvent e) {
                switch (e.keyCode) {
                case SWT.ESC:
                    // On ESC cancel the editing and do not commit the value.
                    e.doit = false;
                    cancelEditing();
                    break;
                }
            }
        });

        // Add focus listener
        FocusListener focusListener = new FocusListener() {
            @Override
            public void focusLost(FocusEvent e) {
                Display.getDefault().asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        if (!urlChooserComposite.isDisposed() && !browseButton.isFocusControl()
                                && !textViewer.getTextWidget().isFocusControl() && !isBrowsing) {
                            // Just make sure we are in sync with the document.
                            fireCommitValue(new EditingEvent((String) getValue()));
                        }
                    }
                });
            }

            @Override
            public void focusGained(FocusEvent e) {
            }
        };
        textViewer.getTextWidget().addFocusListener(focusListener);
        browseButton.addFocusListener(focusListener);

        // Add key listener
        browseButton.addKeyListener(new KeyListener() {
            @Override
            public void keyReleased(KeyEvent e) {
            }

            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.keyCode) {
                case SWT.ESC:
                    // On ESC cancel the editing and do not commit the value.
                    e.doit = false;
                    cancelEditing();
                    break;
                }
            }
        });

        textViewer.setDocument(new Document(""));
        IDocumentListener docChangedListener = new IDocumentListener() {
            @Override
            public void documentAboutToBeChanged(DocumentEvent event) {
                // Not of interest.
            }

            @Override
            public void documentChanged(DocumentEvent event) {
                fireEditingOccured();
            }
        };
        textViewer.getDocument().addDocumentListener(docChangedListener);

        Font font = (Font) context.getArguments().get(InplaceEditorArgumentKeys.FONT);
        if (font != null) {
            swtFont = new org.eclipse.swt.graphics.Font(Display.getDefault(),
                    new FontData(font.getName(), font.getSize(), font.getStyle()));
        }

        if (swtFont != null) {
            textViewer.getTextWidget().setFont(swtFont);
        } else {
            textViewer.getTextWidget().setFont(JFaceResources.getDialogFont());
        }

        Color color = (Color) context.getArguments().get(InplaceEditorArgumentKeys.PROPERTY_COLOR);
        if (color != null) {
            foregroundColor = new org.eclipse.swt.graphics.Color(Display.getDefault(), color.getRed(),
                    color.getGreen(), color.getBlue());
            textViewer.getTextWidget().setForeground(foregroundColor);
        }

        // Assign an open icon on the browse button.
        InputStream resourceAsStream = URLChooserEditorSWT.class.getResourceAsStream("/images/Open16.gif");
        ImageData imageResource = null;
        if (resourceAsStream != null) {
            imageResource = new ImageData(resourceAsStream);
            // EXM-32124 - Make sure the stream is closed after using it
            try {
                resourceAsStream.close();
            } catch (IOException e1) {
                //Ignore
            }
        }
        // Create button image
        ImageDescriptor icon = null;
        if (imageResource != null) {
            icon = ImageDescriptor.createFromImageData(imageResource);
        }

        buttonImage = null;
        if (icon != null) {
            buttonImage = icon.createImage();
        }

        if (buttonImage != null) {
            browseButton.setImage(buttonImage);
        }
        browseButton.setLayoutData(gd);

        setInitialValue(context);
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                // Didn't work without an invoke later.
                if (textViewer.getTextWidget() != null) {
                    textViewer.getTextWidget().showSelection();
                }
            }
        });

        textViewer.getUndoManager().reset();
    }

    /**
     * Sets the initial value inside the chooser.
     * 
     * @param context Current context.
     */
    private void setInitialValue(AuthorInplaceContext context) {
        String text = (String) context.getArguments().get(InplaceEditorArgumentKeys.INITIAL_VALUE);
        if (text == null) {
            text = (String) context.getArguments().get(InplaceEditorArgumentKeys.DEFAULT_VALUE);
        }

        if (text == null) {
            text = "";
        }

        // EXM-25327 Do not insert the username and password in the document
        utilAccess = context.getAuthorAccess().getUtilAccess();
        try {
            URL clearedURL = utilAccess.removeUserCredentials(new URL(text));
            text = clearedURL.toExternalForm();
            textViewer.getTextWidget().setText(text);
        } catch (MalformedURLException e1) {
            textViewer.getTextWidget().setText(text);
        }

        textViewer.getTextWidget().setCaretOffset(text.length());
    }

    /**
     * Dispose of the editor.
     */
    private void dispose() {
        if (swtFont != null) {
            swtFont.dispose();
        }

        if (urlChooserComposite != null) {
            urlChooserComposite.dispose();
        }

        if (buttonImage != null) {
            buttonImage.dispose();
        }

        if (foregroundColor != null) {
            foregroundColor.dispose();
        }
    }

    /**
     * @see org.eclipse.jface.text.ITextOperationTarget#canDoOperation(int)
     */
    @Override
    public boolean canDoOperation(int operation) {
        return textViewer != null ? textViewer.canDoOperation(operation) : false;
    }

    /**
     * @see org.eclipse.jface.text.ITextOperationTarget#doOperation(int)
     */
    @Override
    public void doOperation(int operation) {
        textViewer.doOperation(operation);
    }

    /**
     * @see ro.sync.ecss.extensions.api.editor.InplaceEditor#refresh(ro.sync.ecss.extensions.api.editor.AuthorInplaceContext)
     */
    @Override
    public void refresh(AuthorInplaceContext context) {
        setInitialValue(context);
    }
}