com.nokia.sdt.uidesigner.events.EventPage.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.sdt.uidesigner.events.EventPage.java

Source

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/
package com.nokia.sdt.uidesigner.events;

import com.nokia.cpp.internal.api.utils.core.Logging;
import com.nokia.cpp.internal.api.utils.core.TextUtils;
import com.nokia.sdt.datamodel.IDesignerDataModel;
import com.nokia.sdt.datamodel.adapter.*;
import com.nokia.sdt.datamodel.util.ModelUtils;
import com.nokia.sdt.editor.IDesignerEditor;
import com.nokia.sdt.editor.IDesignerDataModelEditor;
import com.nokia.sdt.uidesigner.events.EventModel.CategoryItem;
import com.nokia.sdt.uidesigner.events.EventModel.EventItem;
import com.nokia.sdt.uidesigner.ui.UIDesignerPlugin;
import com.nokia.sdt.uidesigner.ui.command.DataModelCommandWrapper;
import com.nokia.sdt.uidesigner.ui.utils.Messages;
import com.nokia.sdt.uimodel.UIModelPlugin;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.jface.action.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;

import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;

/**
 * Default implementation of the event editor UI
 */
public class EventPage extends Page implements IEventPage {

    private Shell parentShell;
    private EventView view;
    private EventTreeViewer viewer;
    private EventCellEditor cellEditor;
    EventModel model;
    private Action categoriesAction;
    private Action doubleClickAction;
    private boolean showCategories = true;
    String columnProperties[] = { "EventPage.0", "EventPage.1" }; //$NON-NLS-1$ //$NON-NLS-2$
    private IDesignerDataModelEditor designerDataModelEditor;
    private EventBindingListener eventBindingListener = new EventBindingListener();
    private IStatusLineManager statusLineManager;
    private boolean refreshModelPending;
    private final static String LAST_CONFIG = "EventPage.LastShowCategoriesSetting"; //$NON-NLS-1$
    private final static QualifiedName QUALIFIED_LAST_CONFIG = new QualifiedName(
            UIDesignerPlugin.getDefault().toString(), LAST_CONFIG);

    public EventPage(EventView view) {
        this.view = view;
    }

    public void createControl(Composite parent) {
        parentShell = parent.getShell();
        initializeTreeViewer(parent);
        viewer.setContentProvider(new ViewContentProvider());
        viewer.setLabelProvider(new ViewLabelProvider());
        viewer.setSorter(new NameSorter());
        viewer.setInput(getSite());
        makeActions();
        hookContextMenu();
        hookDoubleClickAction();
        contributeToActionBars();
        hookTreeSelection();
        hookHelp();
    }

    private void initializeTreeViewer(Composite parent) {
        viewer = new EventTreeViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE | SWT.HIDE_SELECTION | SWT.V_SCROLL);
        final Tree tree = viewer.getTree();
        tree.setLinesVisible(true);
        tree.setHeaderVisible(true);

        TreeColumn column = new TreeColumn(tree, 0);
        column.setText(Messages.getString(columnProperties[0]));
        column = new TreeColumn(tree, 1);
        column.setText(Messages.getString(columnProperties[1]));

        // install a cell editor for column 1. We never edit column 0
        cellEditor = new EventCellEditor(viewer.getTree());
        cellEditor.addListener(new ICellEditorListener() {

            public void applyEditorValue() {
                setErrorMessage(null);
            }

            public void cancelEditor() {
                setErrorMessage(null);
            }

            public void editorValueChanged(boolean oldValidState, boolean newValidState) {
                String message = null;
                if (!newValidState) {
                    message = cellEditor.getErrorMessage();
                }
                setErrorMessage(message);
            }

        });

        CellEditor editors[] = new CellEditor[2];
        editors[1] = cellEditor;
        viewer.setCellEditors(editors);
        viewer.setColumnProperties(columnProperties);
        viewer.setCellModifier(new EventCellModifier(this));

        // listen for initial resize to set column widths
        tree.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                Rectangle area = tree.getClientArea();
                TreeColumn[] columns = tree.getColumns();
                if (area.width > 0) {
                    columns[0].setWidth(area.width * 40 / 100);
                    columns[1].setWidth(area.width - columns[0].getWidth() - 4);
                    tree.removeControlListener(this);
                }
            }
        });
    }

    private IDesignerEditor getDesignerEditor() {
        if (designerDataModelEditor != null)
            return (IDesignerEditor) designerDataModelEditor.getAdapter(IDesignerEditor.class);

        return null;
    }

    /**
     * Tries to execute the command in the context of the
     * editor's GEF command stack. If not accessible
     * then it directly executes the command without undo support
     */
    boolean executeEMFCommand(Command command) {
        boolean success = true;
        try {
            org.eclipse.gef.commands.CommandStack commandStack = null;
            IDesignerEditor designerEditor = getDesignerEditor();
            if (designerEditor != null) {
                commandStack = designerEditor.getEditDomain().getCommandStack();
            }

            if (commandStack != null) {
                DataModelCommandWrapper wrapper = new DataModelCommandWrapper();
                wrapper.setDataModelCommand(command);
                commandStack.execute(wrapper);
            } else {
                if (command.canExecute()) {
                    command.execute();
                }
            }
        } catch (Exception x) {
            IStatus status = Logging.newSimpleStatus(0, x);
            UIDesignerPlugin.getDefault().log(x);
            Logging.showErrorDialog(Messages.getString("EventPage.2"), status.getMessage(), status); //$NON-NLS-1$
            success = false;
        }
        return success;
    }

    private void runAsync(Runnable r) {
        Display d = getSite().getShell().getDisplay();
        d.asyncExec(r);
    }

    private void hookTreeSelection() {
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            /* We can't invoke editing from the selection event, we
             * must do it asynchronously
             */
            Object objToEdit;
            private Runnable runnable = new Runnable() {
                public void run() {
                    if (objToEdit != null && !viewer.getControl().isDisposed()) {
                        Object tmp = objToEdit;
                        objToEdit = null;
                        cellEditor.setDescriptor(null);
                        //viewer.editElement(tmp, 1);
                        if (tmp instanceof EventModel.EventItem) {
                            EventModel.EventItem item = (EventModel.EventItem) tmp;
                            String description = item.descriptor.getDescription();
                            EventPage.this.statusLineManager.setMessage(description);
                            cellEditor.setDescriptor(item.descriptor);
                            if (item.binding == null) {
                                cellEditor.markEphemeral();
                            }
                        }

                    }
                }
            };

            public void selectionChanged(SelectionChangedEvent event) {
                objToEdit = getSelectedEventItem(event.getSelection());
                if (objToEdit != null) {
                    EventPage.this.runAsync(runnable);
                }
            }
        });
    }

    private void hookHelp() {
        viewer.getControl().addHelpListener(new HelpListener() {
            public void helpRequested(HelpEvent e) {
                EventModel.EventItem item = getSelectedEventItem(viewer.getSelection());
                if (item != null) {
                    String helpKey = item.descriptor.getHelpKey();
                    if (TextUtils.strlen(helpKey) > 0) {
                        getSite().getWorkbenchWindow().getWorkbench().getHelpSystem().displayHelp(helpKey);
                    }
                }
            }
        });
    }

    private EventModel.EventItem getSelectedEventItem(ISelection selection) {
        EventModel.EventItem result = null;
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection ss = (IStructuredSelection) selection;
            Object obj = ss.getFirstElement();
            if (obj instanceof EventModel.EventItem) {
                result = (EventItem) obj;
            }
        }
        return result;
    }

    public Control getControl() {
        Control result = null;
        if (viewer != null) {
            result = viewer.getControl();
        }
        return result;
    }

    public void setFocus() {
        if (viewer != null) {
            viewer.getControl().setFocus();
        }
    }

    /*
     * Tries to convert the object into an IComponentInstance
     */
    private static IComponentInstance convertToInstance(Object obj) {
        IComponentInstance result = null;
        if (obj instanceof IComponentInstance) {
            result = (IComponentInstance) obj;
        } else if (obj instanceof EObject) {
            result = ModelUtils.getComponentInstance((EObject) obj);
        } else if (obj instanceof IAdaptable) {
            IAdaptable adaptable = (IAdaptable) obj;
            result = (IComponentInstance) adaptable.getAdapter(IComponentInstance.class);
        }
        return result;
    }

    private IComponentInstance[] getInstancesFromSelection(ISelection selection) {
        IComponentInstance[] result = null;
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection ss = (IStructuredSelection) selection;

            // We must be able to get an IComponentInstance for each
            // object in the selection
            Object[] objects = ss.toArray();

            boolean selectionContainsNonInstance = false;
            // the same object can be selected in two parts of the editor, so use a set
            Set<IComponentInstance> instances = new HashSet<IComponentInstance>();
            for (int i = 0; i < objects.length; i++) {
                IComponentInstance ci = convertToInstance(objects[i]);
                if (ci != null) {
                    instances.add(ci);
                } else {
                    selectionContainsNonInstance = true;
                    break;
                }
            }

            if (!selectionContainsNonInstance && (instances.size() > 0)) {
                result = (IComponentInstance[]) instances.toArray(new IComponentInstance[instances.size()]);
            }
        }
        return result;
    }

    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        // the selection has changed in some other workbench part
        if (designerDataModelEditor == null) {
            return; // don't show anything if this is the default page
        }

        if (viewer != null) {
            EventModel newModel = null;
            IComponentInstance[] instances = getInstancesFromSelection(selection);
            if (instances != null) {
                newModel = new EventModel(instances);
            }
            setModel(newModel, true);
        }
    }

    class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {

        public void inputChanged(Viewer v, Object oldInput, Object newInput) {
        }

        public void dispose() {
        }

        public Object[] getElements(Object parent) {
            Object[] result = null;
            if (model != null) {
                if (parent.equals(getSite())) {
                    if (showCategories) {
                        result = model.getCategoryItems();
                    } else {
                        result = model.getEventItems();
                    }
                } else if (parent instanceof EventModel.CategoryItem) {
                    EventModel.CategoryItem item = (CategoryItem) parent;
                    result = item.events;
                }
            }

            if (result == null)
                result = new Object[0];
            return result;
        }

        public Object getParent(Object child) {
            Object result = null;
            if (showCategories && model != null && child instanceof EventModel.EventItem) {
                result = model.findCategoryItem(((EventModel.EventItem) child));
            }
            return result;
        }

        public Object[] getChildren(Object parent) {
            Object result[] = null;
            if (parent instanceof EventModel.CategoryItem) {
                EventModel.CategoryItem item = (CategoryItem) parent;
                result = item.events;
            }
            return result;
        }

        public boolean hasChildren(Object parent) {
            boolean result = false;
            if (parent instanceof EventModel.CategoryItem) {
                EventModel.CategoryItem item = (EventModel.CategoryItem) parent;
                result = item.events != null;
            }
            return result;
        }
    }

    class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {

        public String getColumnText(Object element, int columnIndex) {
            String result = null;
            if (element instanceof EventModel.CategoryItem) {
                if (columnIndex == 0) {
                    EventModel.CategoryItem item = (EventModel.CategoryItem) element;
                    result = item.category;
                }
            } else if (element instanceof EventModel.EventItem) {
                EventModel.EventItem item = (EventModel.EventItem) element;
                if (columnIndex == 0) {
                    result = item.descriptor.getDisplayText();
                } else if (item.binding != null) {
                    result = item.binding.getHandlerName();
                }
            }
            return result;
        }

        public String getText(Object element) {
            // getText is called for sorting
            return getColumnText(element, 0);
        }

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

    class NameSorter extends ViewerSorter {

    }

    public void associateDesignerEditor(IDesignerDataModelEditor editor) {
        this.designerDataModelEditor = editor;
        IDesignerEditor designerEditor = getDesignerEditor();
        boolean savedShowCategories = (designerEditor != null) && getSavedShowCategories(designerEditor);
        showCategories(savedShowCategories);
    }

    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                EventPage.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        //   getSite().registerContextMenu(menuMgr, viewer);
    }

    private void contributeToActionBars() {
        IActionBars bars = getSite().getActionBars();
        fillLocalPullDown(bars.getMenuManager());
        fillLocalToolBar(bars.getToolBarManager());

        statusLineManager = bars.getStatusLineManager();

        IDesignerEditor designerEditor = getDesignerEditor();
        if (designerEditor != null) {
            // Add the editor's revert, undo, and redo.
            ActionRegistry registry = designerEditor.getActionRegistry();
            IAction action = registry.getAction(ActionFactory.REVERT.getId());
            bars.setGlobalActionHandler(action.getId(), action);
            action = registry.getAction(ActionFactory.UNDO.getId());
            bars.setGlobalActionHandler(action.getId(), action);
            action = registry.getAction(ActionFactory.REDO.getId());
            bars.setGlobalActionHandler(action.getId(), action);
            bars.updateActionBars();
        }
    }

    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(categoriesAction);
    }

    private void fillContextMenu(IMenuManager manager) {
        manager.add(categoriesAction);
        // Other plug-ins can contribute there actions here
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(categoriesAction);
    }

    private void makeActions() {
        categoriesAction = new CategoriesAction(this);
        categoriesAction.setChecked(isShowingCategories());

        // The behavior of double-click is:
        // - create a binding if none exists
        // - navigate to binding
        doubleClickAction = new Action() {
            public void run() {
                EventModel.EventItem item = getSelectedEventItem(viewer.getSelection());
                if (item != null) {
                    viewer.cancelEditing();
                    IEventBinding binding = item.binding;
                    boolean isNewBinding = false;
                    if (binding == null) {
                        IComponentInstance instances[] = model.getInstances();
                        IDesignerDataModel model = instances[0].getDesignerDataModel();
                        isNewBinding = true;
                        Command command = EventCommands.createEventBindingCommand(instances, item.descriptor, null);
                        if (command != null) {
                            executeEMFCommand(command);
                            binding = EventCommands.getEventBindingFromCommandResult(command);

                            boolean doSave = EventCommands.userConfirmationToSaveModelDialog(parentShell, model);
                            if (!doSave || !saveDataModel()) {
                                binding = null;
                            }
                        }
                    }
                    if (binding != null) {
                        EventCommands.navigateToHandlerCode(EventPage.this, binding, isNewBinding);
                    }
                }
            }
        };
        cellEditor.setDoubleClickAction(doubleClickAction);
    }

    private void hookDoubleClickAction() {
        viewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
            }
        });
    }

    public boolean isShowingCategories() {
        return showCategories;
    }

    public void showCategories(boolean show) {
        if (show != this.showCategories) {
            this.showCategories = show;
            refresh();
            saveShowCategories(getDesignerEditor(), show);
        }
    }

    public static void saveShowCategories(IDesignerEditor designerEditor, boolean show) {
        UIModelPlugin.getDefault().getPreferenceStore().setValue(LAST_CONFIG, show);
        // save in the resource
        if (designerEditor != null) {
            IResource resource = designerEditor.getDataModelResource();
            try {
                resource.setPersistentProperty(QUALIFIED_LAST_CONFIG, String.valueOf(show));
            } catch (CoreException e) {
            } // don't do anything if this fails
        }
    }

    public static boolean getSavedShowCategories(IDesignerEditor designerEditor) {
        String savedStateString = null;

        // first try the resource
        IResource resource = designerEditor.getDataModelResource();
        try {
            savedStateString = resource.getPersistentProperty(QUALIFIED_LAST_CONFIG);
        } catch (CoreException e) {
        } // don't do anything if this fails

        // then try the plugin setting
        if ((savedStateString == null) || (savedStateString.length() == 0))
            savedStateString = UIModelPlugin.getDefault().getPreferenceStore().getString(LAST_CONFIG);

        // if still no saved setting, then default to true
        if ((savedStateString == null) || (savedStateString.length() == 0))
            return true;

        return Boolean.parseBoolean(savedStateString);
    }

    void refresh() {
        if (viewer != null) {
            viewer.refresh();
            viewer.expandAll();
        }
    }

    public void dispose() {
        setModel(null, false);
        super.dispose();
    }

    void refreshModel(IComponentInstance[] instances) {
        if (model != null) {
            EventModel newModel = new EventModel(model.getInstances());
            setModel(newModel, true);
        }
    }

    void asynchRefreshModel() {
        Runnable r = new Runnable() {
            public void run() {
                EventPage.this.refreshModelPending = false;
                if (!viewer.getControl().isDisposed()) {
                    if (model != null) {
                        // attempt to preserve selected event
                        String selectedEventID = null;
                        EventModel.EventItem currSelected = getSelectedEventItem(viewer.getSelection());
                        if (currSelected != null) {
                            selectedEventID = currSelected.descriptor.getId();
                        }

                        refreshModel(model.getInstances());

                        if (selectedEventID != null) {
                            EventItem item = model.findEventItem(selectedEventID);
                            if (item != null) {
                                selectItem(item);
                            }
                        }

                    }
                }
            }
        };
        // This is meant to avoid multiple refreshes queued on the
        // event thread (to avoid flashing). Thread safety is not needed
        if (!refreshModelPending) {
            refreshModelPending = true;
            runAsync(r);
        }
    }

    /**
     * Tell Eclipse the content changed. In the default presentation
     * this temporarily bolds the view's title tab.
     */
    private void markViewChanged() {
        IWorkbenchPartSite site = view.getSite();
        IWorkbenchSiteProgressService wsps = (IWorkbenchSiteProgressService) site
                .getAdapter(IWorkbenchSiteProgressService.class);
        if (wsps != null) {
            wsps.warnOfContentChange();
        }
    }

    private void setModel(EventModel newModel, boolean refresh) {
        IComponentInstance instances[];
        if (model != null) {
            instances = model.getInstances();
            for (int i = 0; i < instances.length; i++) {
                IComponentInstance instance = instances[i];
                instance.removeEventBindingListener(eventBindingListener);
            }
        }
        this.model = newModel;
        if (model != null) {
            instances = model.getInstances();
            for (int i = 0; i < instances.length; i++) {
                IComponentInstance instance = instances[i];
                instance.addEventBindingListener(eventBindingListener);
            }
        }
        if (refresh) {
            refresh();
        }
    }

    public void deactivateCellEditor() {
        viewer.cancelEditing();
    }

    boolean cellEditorIsDirty() {
        // we only ever edit column 1
        return viewer.getCellEditors()[1].isDirty();
    }

    void setErrorMessage(String message) {
        if (statusLineManager != null) {
            statusLineManager.setErrorMessage(message);
        }
    }

    // All view updating is driven by these events
    class EventBindingListener implements IEventBindingListener {
        public void bindingAdded(EObject instance, IEventBinding eventBinding) {
            asynchRefreshModel();
            markViewChanged();
        }

        public void bindingRemoved(EObject instance, IEventBinding eventBinding) {
            asynchRefreshModel();
        }
    }

    public Shell getParentShell() {
        return parentShell;
    }

    boolean saveDataModel() {
        /*
        UIJob job = new UIJob(Messages.getString("EventPage.3")) { //$NON-NLS-1$
           public IStatus runInUIThread(IProgressMonitor monitor) {
        designerEditor.doSave(monitor);
        return Logging.newStatus(UIDesignerPlugin.getDefault(), IStatus.OK, null);
           }
        };
        job.setUser(true);
        job.schedule();
        return true;*/
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                designerDataModelEditor.doSave(monitor);
            }
        };
        //ProgressMonitorDialog dialog = new ProgressMonitorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
        //dialog.run(false, true, runnable);
        try {
            PlatformUI.getWorkbench().getProgressService()
                    .runInUI(PlatformUI.getWorkbench().getActiveWorkbenchWindow(), runnable, null);
            return true;
        } catch (InvocationTargetException e) {
            UIDesignerPlugin.getDefault().log(e);
            return false;
        } catch (InterruptedException e) {
            return false;
        }
    }

    public void selectItem(EventItem item) {
        viewer.setSelection(new StructuredSelection(item));
    }
}