de.topicmapslab.tmcledit.model.views.widgets.AnnotationWidget.java Source code

Java tutorial

Introduction

Here is the source code for de.topicmapslab.tmcledit.model.views.widgets.AnnotationWidget.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2009 Topic Maps Lab 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:
 *     Hannes Niederhausen - initial API and implementation
 *******************************************************************************/
package de.topicmapslab.tmcledit.model.views.widgets;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
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.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
import org.eclipse.ui.forms.widgets.FormToolkit;

import de.topicmapslab.tmcledit.model.Annotation;
import de.topicmapslab.tmcledit.model.TMCLConstruct;
import de.topicmapslab.tmcledit.model.TmcleditEditPlugin;
import de.topicmapslab.tmcledit.model.annotationprovider.IAnnotationProposalProvider;
import de.topicmapslab.tmcledit.model.annotationprovider.IAnnotationValidator;
import de.topicmapslab.tmcledit.model.annotationprovider.internal.AnnotationKeyProvider;
import de.topicmapslab.tmcledit.model.annotationprovider.internal.AnnotationValueProvider;
import de.topicmapslab.tmcledit.model.commands.CreateAnnotationCommand;
import de.topicmapslab.tmcledit.model.commands.ModifyAnnotationKeyCommand;
import de.topicmapslab.tmcledit.model.commands.ModifyAnnotationValueCommand;
import de.topicmapslab.tmcledit.model.commands.RemoveAnnotationCommand;
import de.topicmapslab.tmcledit.model.util.ImageConstants;
import de.topicmapslab.tmcledit.model.util.ImageProvider;
import de.topicmapslab.tmcledit.model.util.extension.AnnotationProviderInfo;

/**
 * @author Hannes Niederhausen
 * 
 */
public class AnnotationWidget extends Composite {

    private TMCLConstruct model;
    private TableViewer viewer;
    private Adapter adapter;

    private CommandStack cmdStack;

    private FormToolkit toolkit;
    private Button addButton;
    private Button removeButton;
    private int newCounter;

    /**
     * 
     * @param parent the parent widget
     * @param style the widget style
     * @param toolkit the {@link FormToolkit} to create the widgets
     */
    public AnnotationWidget(Composite parent, int style, FormToolkit toolkit) {
        this(parent, style);
        this.toolkit = toolkit;
    }

    /**
     * @param parent the parent widget
     * @param style the widget style
     */
    public AnnotationWidget(Composite parent, int style) {
        super(parent, style);
        adapter = new Adapter();
        createControl();
    }

    private void createControl() {
        setLayout(new GridLayout(2, false));

        createTable();

        createButtonBar();
    }

    private void createButtonBar() {
        Composite comp = (toolkit == null) ? new Composite(this, SWT.NONE) : toolkit.createComposite(this);
        comp.setLayout(new GridLayout());
        comp.setLayoutData(new GridData(GridData.FILL_VERTICAL));

        addButton = createButton(comp, "");
        addButton.setImage(ImageProvider.getImage(ImageConstants.NEW));
        addButton.setToolTipText("Create new Annotation");

        removeButton = createButton(comp, "");
        removeButton.setImage(ImageProvider.getImage(ImageConstants.REMOVE));
        removeButton.setToolTipText("Remove selected Annotation");
        removeButton.setEnabled(false);

        hookButtonListeners();
    }

    private Button createButton(Composite parent, String text) {
        Button b = (toolkit == null) ? new Button(parent, SWT.PUSH) : toolkit.createButton(parent, text, SWT.PUSH);
        b.setText(text);
        b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        return b;
    }

    private void createTable() {
        Composite comp = (toolkit == null) ? new Composite(this, SWT.NONE) : toolkit.createComposite(this);
        TableColumnLayout layout = new TableColumnLayout();
        comp.setLayout(layout);
        comp.setLayoutData(new GridData(GridData.FILL_BOTH));

        Table table = null;
        if (toolkit != null) {
            table = toolkit.createTable(comp, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
        } else {
            table = new Table(comp, SWT.BORDER);
        }
        table.setHeaderVisible(true);

        viewer = new TableViewer(table);
        viewer.setColumnProperties(new String[] { "key", "value" });
        viewer.setLabelProvider(new AnnotationLabelProvider());
        viewer.setContentProvider(new ArrayContentProvider());
        // viewer.setCellEditors(new CellEditor[] { new TextCellEditor(table),
        // new TextCellEditor(table) });
        viewer.addDoubleClickListener(new IDoubleClickListener() {

            public void doubleClick(DoubleClickEvent event) {
                editAnnotation();
            }
        });
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(SelectionChangedEvent event) {
                if (!(event.getSelection() instanceof IStructuredSelection))
                    return;
                IStructuredSelection sel = (IStructuredSelection) event.getSelection();

                if (sel.isEmpty())
                    removeButton.setEnabled(false);
                else
                    removeButton.setEnabled(true);

            }
        });

        TableViewerColumn tvc = new TableViewerColumn(viewer, SWT.NONE);
        tvc.setLabelProvider(new KeyLabelProvider());
        tvc.setEditingSupport(new KeyEditingSupport(viewer));
        TableColumn tc = tvc.getColumn();
        tc.setText("Key");
        layout.setColumnData(tc, new ColumnWeightData(1));

        tvc = new TableViewerColumn(viewer, SWT.NONE);
        tvc.setLabelProvider(new ValueLabelProvider());
        tvc.setEditingSupport(new ValueEditingSupport(viewer));
        tc = tvc.getColumn();
        tc.setText("Value");
        layout.setColumnData(tc, new ColumnWeightData(1));

        if (model != null)
            viewer.setInput(model.getAnnotations());
    }

    private void hookButtonListeners() {
        addButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                addAnnotation();
            }
        });

        removeButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                removeAnnotation();
            }
        });
    }

    private void editAnnotation() {
        viewer.refresh();
    }

    private void removeAnnotation() {
        IStructuredSelection sel = (IStructuredSelection) viewer.getSelection();
        if (sel.isEmpty())
            return;
        Annotation a;
        if (sel.size() == 1) {
            a = (Annotation) sel.getFirstElement();
            cmdStack.execute(new RemoveAnnotationCommand(model, a));
        } else {
            CompoundCommand ccmd = new CompoundCommand();
            Iterator it = sel.iterator();
            while (it.hasNext()) {
                a = (Annotation) it.next();
                ccmd.append(new RemoveAnnotationCommand(model, a));
            }
            cmdStack.execute(ccmd);
        }
        viewer.refresh();
    }

    private void addAnnotation() {
        String key;
        do {
            newCounter++;
            key = "key" + newCounter;
        } while (findAnnotation(key) != null);

        cmdStack.execute(new CreateAnnotationCommand(model, key, "value"));
        viewer.refresh();

    }

    private Annotation findAnnotation(String key) {
        for (Annotation a : model.getAnnotations()) {
            if (a.getKey().equals(key))
                return a;
        }
        return null;
    }

    /**
     * Sets the model for the widget.
     * 
     * @param model the model which should be an instance of {@link TMCLConstruct}
     */
    public void setModel(Object model) {
        if (this.model != null) {
            this.model.eAdapters().remove(adapter);
            for (Annotation a : this.model.getAnnotations()) {
                a.eAdapters().remove(adapter);
            }
        }

        if (!(model instanceof TMCLConstruct)) {
            this.model = null;
            return;
        }

        this.model = (TMCLConstruct) model;
        if (this.model == null)
            return;

        this.model.eAdapters().add(adapter);
        for (Annotation a : this.model.getAnnotations()) {
            a.eAdapters().add(adapter);
        }
        updateAnnotationList();
    }

    private void updateAnnotationList() {
        if (viewer != null)
            viewer.setInput(model.getAnnotations());
    }

    private class AnnotationLabelProvider implements ITableLabelProvider {

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            Annotation a = (Annotation) element;
            if (columnIndex == 0)
                return a.getKey();
            return a.getValue();
        }

        public void addListener(ILabelProviderListener listener) {
        }

        public void dispose() {
        }

        public boolean isLabelProperty(Object element, String property) {
            return false;
        }

        public void removeListener(ILabelProviderListener listener) {
        }
    }

    private class KeyEditingSupport extends EditingSupport {

        private TextCellEditor ed;

        public KeyEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected boolean canEdit(Object element) {
            return true;
        }

        @Override
        protected CellEditor getCellEditor(Object element) {
            if (ed == null) {
                ed = new TextCellEditor((Composite) getViewer().getControl());

                new ContentAssistCommandAdapter(ed.getControl(), new TextContentAdapter(),
                        new AnnotationKeyProvider(), null, AnnotationKeyProvider.KEYS);
            }
            return ed;
        }

        @Override
        protected Object getValue(Object element) {
            return cast(element).getKey();
        }

        @Override
        protected void setValue(Object element, Object value) {
            Annotation a = cast(element);
            cmdStack.execute(new ModifyAnnotationKeyCommand(a, (String) value));
        }

        private Annotation cast(Object e) {
            return (Annotation) e;
        }

    }

    private class KeyLabelProvider extends CellLabelProvider {

        @Override
        public void update(ViewerCell cell) {
            Annotation a = (Annotation) cell.getElement();
            cell.setText(a.getKey());
        }

    }

    private class ValueEditingSupport extends EditingSupport {

        private TextCellEditor textEditor;
        private CheckboxCellEditor booleanEditor;
        private ComboBoxCellEditor comboBoxCellEditor;

        private IAnnotationValidator currValidator;
        private AnnotationValueProvider proposalProvider;

        private boolean comboUsed = false;

        public ValueEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected boolean canEdit(Object element) {
            return true;
        }

        @Override
        protected CellEditor getCellEditor(Object element) {
            comboUsed = false;
            AnnotationProviderInfo info = getInfo(element);
            if (info != null) {
                Class<?> type = getType(element);
                if (type == Boolean.class) {
                    currValidator = info.getValidator();
                    return getBooleanEditor();
                }

                IAnnotationProposalProvider proposalProvider = info.getPorposalProvider();
                if (proposalProvider != null) {
                    if (!proposalProvider.newValuesAllowed()) {
                        getComboBoxCellEditor().setItems(proposalsToArray(proposalProvider));
                        comboUsed = true;
                        return getComboBoxCellEditor();
                    }
                } else {
                    getTextEditor();
                    if (info != null) {
                        currValidator = info.getValidator();
                        this.proposalProvider.setProvider(proposalProvider);
                    }
                }
            } else {
                currValidator = null;
                if (proposalProvider != null)
                    proposalProvider.setProvider(null);
            }
            return getTextEditor();
        }

        private String[] proposalsToArray(IAnnotationProposalProvider proposalProvider) {
            List<String> list = new ArrayList<String>();

            for (String s : proposalProvider.getProposals()) {
                list.add(s);
            }

            return list.toArray(new String[list.size()]);
        }

        private Class<?> getType(Object element) {
            AnnotationProviderInfo info = getInfo(element);
            if (info == null)
                return String.class;
            return info.getValidator().getType();
        }

        private AnnotationProviderInfo getInfo(Object element) {
            String key = cast(element).getKey();

            AnnotationProviderInfo info = TmcleditEditPlugin.getPlugin().getAnnotionProviderInfo(key);
            return info;
        }

        public CheckboxCellEditor getBooleanEditor() {
            if (booleanEditor == null)
                booleanEditor = new CheckboxCellEditor((Composite) getViewer().getControl());
            return booleanEditor;
        }

        public ComboBoxCellEditor getComboBoxCellEditor() {
            if (comboBoxCellEditor == null)
                comboBoxCellEditor = new ComboBoxCellEditor((Composite) getViewer().getControl(), new String[] {});
            return comboBoxCellEditor;
        }

        private TextCellEditor getTextEditor() {
            if (textEditor == null) {
                textEditor = new TextCellEditor((Composite) getViewer().getControl());
                proposalProvider = new AnnotationValueProvider();
                new ContentAssistCommandAdapter(textEditor.getControl(), new TextContentAdapter(), proposalProvider,
                        null, AnnotationValueProvider.KEYS);
            }
            return textEditor;
        }

        @Override
        protected Object getValue(Object element) {
            String value = cast(element).getValue();
            if (getType(element) == Boolean.class)
                return Boolean.parseBoolean(value);

            if (comboUsed) {
                int i = 0;
                for (String s : getComboBoxCellEditor().getItems()) {
                    if (value.equals(s))
                        return new Integer(i);
                    i++;
                }
                return new Integer(0);

            }

            return value;
        }

        @Override
        protected void setValue(Object element, Object value) {
            Annotation a = cast(element);

            if (value instanceof Boolean)
                value = ((Boolean) value).toString();

            if (comboUsed) {
                int index = ((Integer) value).intValue();
                value = getComboBoxCellEditor().getItems()[index];
            }

            if ((currValidator != null) && (!currValidator.isValid((String) value))) {
                return;
            }

            cmdStack.execute(new ModifyAnnotationValueCommand(a, (String) value));
        }

        private Annotation cast(Object e) {
            return (Annotation) e;
        }

    }

    private class ValueLabelProvider extends CellLabelProvider {

        @Override
        public void update(ViewerCell cell) {
            Annotation a = (Annotation) cell.getElement();
            cell.setText(a.getValue());
        }

    }

    private class Adapter extends AdapterImpl {
        @Override
        public void notifyChanged(Notification msg) {
            if (msg.getEventType() == Notification.REMOVING_ADAPTER)
                return;

            if (msg.getNotifier().equals(model)) {
                if (msg.getEventType() == Notification.ADD) {
                    if (msg.getNewValue() instanceof EObject) {
                        EObject obj = (EObject) msg.getNewValue();
                        if (obj != null)
                            obj.eAdapters().add(adapter);
                    }
                }
                if (msg.getEventType() == Notification.REMOVE) {
                    if (msg.getOldValue() instanceof EObject) {
                        EObject obj = (EObject) msg.getOldValue();
                        if (obj != null)
                            obj.eAdapters().add(adapter);
                    }
                }
            }

            if (msg.getNotifier() instanceof Annotation) {
                viewer.refresh(msg.getNotifier());
                return;
            }

            viewer.refresh();
        }
    }

    /**
     * Sets the {@link CommandStack} for the operations created in this widget
     * @param commandStack the {@link CommandStack} 
     */
    public void setCommandStack(CommandStack commandStack) {
        cmdStack = commandStack;
    }

}