name.schedenig.eclipse.grepconsole.view.styles.StylesPanel.java Source code

Java tutorial

Introduction

Here is the source code for name.schedenig.eclipse.grepconsole.view.styles.StylesPanel.java

Source

/*******************************************************************************
 * Copyright (c) 2008 - 2014 Marian Schedenig
 * 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:
 *    Marian Schedenig - initial API and implementation
 *******************************************************************************/

package name.schedenig.eclipse.grepconsole.view.styles;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import name.schedenig.eclipse.grepconsole.Activator;
import name.schedenig.eclipse.grepconsole.i18n.Messages;
import name.schedenig.eclipse.grepconsole.model.GrepExpressionItem;
import name.schedenig.eclipse.grepconsole.model.GrepExpressionRootFolder;
import name.schedenig.eclipse.grepconsole.model.GrepGroup;
import name.schedenig.eclipse.grepconsole.model.GrepStyle;
import name.schedenig.eclipse.grepconsole.util.GridLayoutBuilder;
import name.schedenig.eclipse.grepconsole.view.ReadOnlyListDialog;
import name.schedenig.eclipse.grepconsole.view.colors.ColorRegistry;
import name.schedenig.eclipse.grepconsole.view.items.ItemLabelProvider;
import name.schedenig.eclipse.grepconsole.view.items.PreviewColorHandler;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.LineStyleEvent;
import org.eclipse.swt.custom.LineStyleListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.dialogs.ListDialog;

/**
 * A panel that lists all configured styles and lets the user manage them.
 * 
 * @author msched
 */
public class StylesPanel extends Composite {
    /**
     * Interface for listeners to style changes.
     * 
     * @author msched
     */
    public static interface IStylesListener {
        /**
         * Called when the user created a new style.
         * 
         * @param panel Source panel.
         * @param style The new style.
         */
        void onNewStyle(StylesPanel panel, GrepStyle style);

        /**
         * Called when the user deleted a style.
         * 
         * @param panel Source panel.
         * @param style The deleted style.
         */
        void onStyleDeleted(StylesPanel panel, GrepStyle style);

        /**
         * Called when the user changed a style.
         * 
         * @param panel Source panel.
         * @param style The changed style.
         */
        void onStyleChanged(StylesPanel panel, GrepStyle style);

        /**
         * Called when the user selected a style.
         * 
         * @param panel Source panel.
         * @param style Selected style.
         */
        void onStyleSelected(StylesPanel panel, GrepStyle style);

        /**
         * Called when the user double clicked a style.
         * 
         * @param panel Source panel.
         * @param style Double clicked style.
         * 
         * @return <code>true</code> if processing of the event should stop after
         *       this listener. 
         */
        boolean onStyleDoubleClicked(StylesPanel panel, GrepStyle style);
    }

    /** Set of listeners. */
    private LinkedHashSet<IStylesListener> listeners = new LinkedHashSet<IStylesListener>();

    /** Model tree root. Source of the managed styles. */
    private GrepExpressionRootFolder root;

    /** Colour registry used for preview. */
    private ColorRegistry colorRegistry;

    /** GUI variables. */
    private Table table;
    private TableViewer viewer;
    private StyledText stPreview;
    @SuppressWarnings("unused")
    private Button btnNew;
    private Button btnEdit;
    private Button btnDelete;
    private Composite panelButtons;

    /**
     * Creates a new instance.
     * 
     * @param parent Parent component.
     * @param style Style flags.
     */
    public StylesPanel(Composite parent, int style) {
        super(parent, style);

        init();
    }

    /**
     * Called when the panel is disposed.
     */
    protected void onDispose() {
        colorRegistry.disposeColors();
    }

    /**
     * Initialises the GUI.
     */
    protected void init() {
        addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
                onDispose();
            }
        });

        colorRegistry = new ColorRegistry(Activator.getDefault().getColorRegistry());

        new GridLayoutBuilder(this, 1, true).setMargins(0).apply();

        table = new Table(this, SWT.BORDER | SWT.MULTI);
        table.setHeaderVisible(true);
        table.setLinesVisible(false);
        table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));

        viewer = new TableViewer(table);
        viewer.setContentProvider(new StyleContentProvider(false));
        viewer.setComparator(new StyleComparator());

        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                doStylesSelected(getSelectedStyles());
            }
        });

        viewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(DoubleClickEvent event) {
                doStyleDoubleClicked(getSelectedStyle((IStructuredSelection) event.getSelection()));
            }
        });

        TableViewerColumn colAvailableStyle = new TableViewerColumn(viewer, SWT.LEFT);
        colAvailableStyle.getColumn().setText(Messages.StylesPanel_available_styles);
        colAvailableStyle.getColumn().setWidth(150);
        colAvailableStyle.setLabelProvider(new StyleLabelProvider(viewer));

        table.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.character == SWT.DEL) {
                    doDeleteStyles();
                    e.doit = false;
                } else if (e.keyCode == SWT.F2) {
                    doEditStyle();
                    e.doit = false;
                }
            }
        });

        stPreview = new StyledText(this, SWT.BORDER);
        stPreview.setText(Messages.StylesPanel_style_preview);
        stPreview.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1));
        stPreview.setFont(JFaceResources.getTextFont());

        new PreviewColorHandler(stPreview);

        stPreview.addLineStyleListener(new LineStyleListener() {
            @Override
            public void lineGetStyle(LineStyleEvent event) {
                GrepStyle grepStyle = getSelectedStyle();

                if (grepStyle != null) {
                    StyleRange style = new StyleRange();
                    style.start = event.lineOffset;
                    style.length = event.lineText.length();
                    fillStyleRange(style, grepStyle);
                    event.styles = new StyleRange[] { style };
                }
            }
        });

        ColumnViewerToolTipSupport.enableFor(viewer);

        panelButtons = new Composite(this, SWT.NONE);
        panelButtons.setLayout(new FillLayout(SWT.HORIZONTAL));
        panelButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));

        createButtons(panelButtons);

        if (root != null) {
            viewer.setInput(root);
        }
    }

    /**
     * Handles style double clicks.
     * 
     * @param style Selected style.
     */
    protected void doStyleDoubleClicked(GrepStyle style) {
        boolean done = false;

        for (IStylesListener listener : listeners) {
            done |= listener.onStyleDoubleClicked(this, style);
        }

        if (!done) {
            doEditStyle(style);
        }
    }

    /**
     * Creates buttons for the button panel.
     * 
     * @param Button panel.
     */
    protected void createButtons(Composite parent) {
        btnNew = createNewButton(parent);
        btnEdit = createEditButton(parent);
        btnDelete = createDeleteButton(parent);
    }

    /**
     * Creates the "new" button.
     * 
     * @param parent Parent panel.
     * 
     * @return Button.
     */
    protected Button createNewButton(Composite parent) {
        Button btn = new Button(parent, SWT.PUSH);
        btn.setText(Messages.StylesPanel_new);
        btn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                doNewStyle();
            }
        });

        return btn;
    }

    /**
     * Creates the "edit" button.
     * 
     * @param parent Parent panel.
     * 
     * @return Button.
     */
    protected Button createEditButton(Composite parent) {
        Button btn = new Button(parent, SWT.PUSH);
        btn.setText(Messages.StylesPanel_edit);
        btn.setEnabled(false);
        btn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                doEditStyle();
            }
        });

        return btn;
    }

    /**
     * Creates the "delete" button.
     * 
     * @param parent Parent panel.
     * 
     * @return Button.
     */
    protected Button createDeleteButton(Composite parent) {
        Button btn = new Button(parent, SWT.PUSH);
        btn.setText(Messages.StylesPanel_delete);
        btn.setEnabled(false);
        btn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                doDeleteStyles();
            }
        });

        return btn;
    }

    /**
     * Adds a listener to the panel.
     * 
     * @param listener Listener.
     */
    public void addListener(IStylesListener listener) {
        listeners.add(listener);
    }

    /**
     * Removes a listener from the panel.
     * 
     * @param listener Listener.
     */
    public void removeListener(IStylesListener listener) {
        listeners.remove(listener);
    }

    /**
     * Sets the root of the model tree to be used.
     * 
     * @param root Model tree root.
     */
    public void setRoot(GrepExpressionRootFolder root) {
        this.root = root;

        if (viewer != null) {
            viewer.setInput(root);
        }
    }

    /**
     * Sets whether to show the null style in the list.
     * 
     * @param includeNull Whether to show the null style.
     */
    public void setIncludeNullStyle(boolean includeNull) {
        ((StyleContentProvider) viewer.getContentProvider()).setIncludeNull(includeNull);
        viewer.refresh();
    }

    /**
     * Called when the "new" button is clicked.
     */
    public void doNewStyle() {
        GrepStyle newStyle = new GrepStyle();
        newStyle.setName(Messages.StylesPanel_new_style);

        StyleDialog dlg = new StyleDialog(getShell(), true);
        dlg.setGrepStyle(newStyle);

        if (dlg.open() == StyleDialog.OK) {
            root.addStyle(newStyle);
            viewer.refresh();
            viewer.setSelection(new StructuredSelection(newStyle));

            for (IStylesListener listener : listeners) {
                listener.onNewStyle(this, newStyle);
            }
        }
    }

    /**
     * Caled when the "edit" button is clicked. Edits the selected style.
     */
    public void doEditStyle() {
        doEditStyle(getSelectedStyle());
    }

    /**
     * Opens the edit dialog for the specified style.
     */
    public void doEditStyle(GrepStyle style) {
        if (style == null) {
            return;
        }

        StyleDialog dlg = new StyleDialog(getShell(), false);
        dlg.setGrepStyle(style);

        if (dlg.open() == StyleDialog.OK) {
            viewer.refresh();
            stPreview.redraw();

            for (IStylesListener listener : listeners) {
                listener.onStyleChanged(this, style);
            }
        }
    }

    /**
     * Called when the "delete" button is clicked.
     * 
     * @param style Style that should be deleted.
     */
    public void doDeleteStyles() {
        Collection<GrepStyle> styles = getSelectedStyles();

        if (styles.isEmpty()) {
            return;
        }

        Set<GrepExpressionItem> items = new LinkedHashSet<GrepExpressionItem>();

        for (GrepStyle style : styles) {
            root.findStyleUses(style, items);
        }

        GrepStyle singleStyle = styles.size() == 1 ? styles.iterator().next() : null;
        boolean doIt;

        if (items.isEmpty()) {
            String msg;

            if (singleStyle != null) {
                String styleName = singleStyle.getName();
                msg = MessageFormat.format(Messages.StylesPanel_delete_style_confirm_single,
                        styleName == null ? Messages.StylesPanel_unnamed : styleName);
            } else {
                msg = MessageFormat.format(Messages.StylesPanel_delete_style_confirm_multi, styles.size());
            }

            doIt = MessageDialog.openConfirm(getShell(), Messages.StylesPanel_delete_style_title, msg);
        } else {
            String msg;

            if (singleStyle != null) {
                String styleName = singleStyle.getName();
                msg = MessageFormat.format(Messages.StylesPanel_delete_style_still_used_confirm_single,
                        styleName == null ? Messages.StylesPanel_unnamed : styleName);
            } else {
                msg = MessageFormat.format(Messages.StylesPanel_delete_style_still_used_confirm_multi,
                        styles.size());
            }

            ReadOnlyListDialog dlg = new ReadOnlyListDialog(getShell());
            dlg.setTitle(Messages.StylesPanel_delete_style_title);
            dlg.setMessage(msg);
            dlg.setContentProvider(new IStructuredContentProvider() {
                @Override
                public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
                }

                @Override
                public void dispose() {
                }

                @Override
                public Object[] getElements(Object inputElement) {
                    return ((Collection<?>) inputElement).toArray();
                }
            });

            dlg.setLabelProvider(new ItemLabelProvider());
            dlg.setInput(items);

            doIt = dlg.open() == ListDialog.OK;
        }

        if (!doIt) {
            return;
        }

        int index = viewer.getTable().getSelectionIndex();

        for (GrepStyle style : styles) {
            root.removeStyle(style);

            for (GrepExpressionItem item : items) {
                GrepGroup[] groups = item.getGroups();

                for (int i = 0; i < groups.length; i++) {
                    if (groups[i].getStyle() == style) {
                        groups[i].setStyle(null);
                    }
                }
            }

            for (IStylesListener listener : listeners) {
                listener.onStyleDeleted(this, style);
            }
        }

        viewer.refresh();
        viewer.getTable().select(Math.min(index, root.getStyles().size() - 1));
    }

    /**
     * Called when a style is selected. Updates the preview and buttons and calls
     * the listeners (only if exactly one style is selected).
     * 
     * @param styles Selected styles.
     */
    protected void doStylesSelected(Collection<GrepStyle> styles) {
        stPreview.redraw();

        btnEdit.setEnabled(styles.size() == 1);
        btnDelete.setEnabled(!styles.isEmpty());

        GrepStyle style = styles.size() == 1 ? styles.iterator().next() : null;

        for (IStylesListener listener : listeners) {
            listener.onStyleSelected(this, style);
        }
    }

    /**
     * Fills a style range's properties from a grep style.
     * 
     * @param style Style range.
     * @param grepStyle Grep style.
     */
    protected void fillStyleRange(StyleRange style, GrepStyle grepStyle) {
        RGB rgbForeground = grepStyle.getForeground();
        RGB rgbBackground = grepStyle.getBackground();
        RGB rgbUnderline = grepStyle.getUnderlineColor();
        RGB rgbStrikethrough = grepStyle.getStrikeoutColor();
        RGB rgbBorder = grepStyle.getBorderColor();

        if (rgbBackground == null) {
            rgbBackground = new RGB(255, 255, 255);
        }

        style.foreground = colorRegistry.get(rgbForeground);
        style.background = colorRegistry.get(rgbBackground);

        style.fontStyle = 0 | (grepStyle.isBold() ? SWT.BOLD : 0) | (grepStyle.isItalic() ? SWT.ITALIC : 0);

        style.underline = grepStyle.isUnderline();
        style.underlineColor = colorRegistry.get(rgbUnderline);

        style.strikeout = grepStyle.isStrikeout();
        style.strikeoutColor = colorRegistry.get(rgbStrikethrough);

        style.borderStyle = grepStyle.isBorder() ? SWT.BORDER_SOLID : SWT.NONE;
        style.borderColor = colorRegistry.get(rgbBorder);
    }

    /**
     * Returns the selected style.
     * 
     * @return Style. May be <code>null</code>.
     */
    public GrepStyle getSelectedStyle() {
        return getSelectedStyle((IStructuredSelection) viewer.getSelection());
    }

    /**
     * Returns the selected styles.
     * 
     * @return Styles. May be empty.
     */
    public Collection<GrepStyle> getSelectedStyles() {
        List<GrepStyle> styles = new LinkedList<GrepStyle>();
        IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();

        if (selection != null) {
            for (Object o : selection.toList()) {
                if (o instanceof GrepStyle) {
                    styles.add((GrepStyle) o);
                }
            }
        }

        return styles;
    }

    /**
     * Reads the selected style from a selection.
     * 
     * @param selection Selection.
     * 
     * @return Style. May be <code>null</code>.
     */
    protected GrepStyle getSelectedStyle(IStructuredSelection selection) {
        Object o = selection == null || selection.isEmpty() ? null : selection.getFirstElement();
        return (GrepStyle) (o instanceof GrepStyle ? o : null);
    }

    /**
     * Selects the specified style.
     * 
     * @param style Style.
     */
    public void setSelection(GrepStyle style) {
        viewer.setSelection(style == null ? null : new StructuredSelection(style));
    }

    /**
     * Refreshes the tree.
     */
    public void refresh() {
        viewer.refresh();
    }
}