org.eclipse.jubula.client.ui.rcp.views.JBPropertiesPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.ui.rcp.views.JBPropertiesPage.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 BREDEX GmbH.
 * 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:
 *     BREDEX GmbH - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.views;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.help.IContext;
import org.eclipse.help.IContextProvider;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.TreeViewerEditor;
import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jubula.client.core.businessprocess.IComponentNameCache;
import org.eclipse.jubula.client.core.events.DataChangedEvent;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IDataChangedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IParamChangedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IPartClosedListener;
import org.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.ui.constants.Constants;
import org.eclipse.jubula.client.ui.constants.ContextHelpIds;
import org.eclipse.jubula.client.ui.controllers.propertysources.IPropertyController;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.controllers.propertydescriptors.JBPropertyDescriptor;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.AbstractNodePropertySource;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ActionTypeController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ComponentNameController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ComponentTypeController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ParameterNameController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ParameterTypeController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.CapGUIPropertySource.ParameterValueController;
import org.eclipse.jubula.client.ui.rcp.controllers.propertysources.IParameterPropertyController;
import org.eclipse.jubula.client.ui.rcp.editors.AbstractJBEditor;
import org.eclipse.jubula.client.ui.rcp.editors.JBEditorHelper.EditableState;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.provider.contextprovider.JBContextProvider;
import org.eclipse.jubula.client.ui.utils.LayoutUtil;
import org.eclipse.jubula.client.ui.views.IJBPart;
import org.eclipse.jubula.toolkit.common.xml.businessprocess.ComponentBuilder;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.utils.generator.ActionInfo;
import org.eclipse.jubula.tools.internal.utils.generator.CompSystemProcessor;
import org.eclipse.jubula.tools.internal.utils.generator.ComponentInfo;
import org.eclipse.jubula.tools.internal.utils.generator.ParamInfo;
import org.eclipse.jubula.tools.internal.utils.generator.ToolkitInfo;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Action;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Component;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.help.IWorkbenchHelpSystem;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author BREDEX GmbH
 * @created 19.01.2005
 */
@SuppressWarnings("synthetic-access")
public class JBPropertiesPage extends Page implements IDataChangedListener, IParamChangedListener,
        IPartClosedListener, IPropertySheetPage, IAdaptable {

    /** the logger */
    private static final Logger LOG = LoggerFactory.getLogger(JBPropertiesPage.class);

    /** The property source */
    private IPropertySource m_propSource;

    /** The Tree Viewer of this view */
    private TreeViewer m_treeViewer;

    /** listens for selection changes that influence help context */
    private ISelectionChangedListener m_helpContextListener = new HelpContextListener();

    /** shows, if the Properties view is editable or not */
    private boolean m_isEditable;

    /** the corresponding part */
    private IWorkbenchPart m_correspondingPart;

    /**
     * Label provider for property names.
     *
     * @author BREDEX GmbH
     * @created Apr 7, 2010
     */
    private final class PropertyNameLabelProvider extends ColumnLabelProvider {
        /**
         * {@inheritDoc}
         */
        public String getText(Object element) {
            if (element instanceof IPropertyDescriptor) {
                return ((IPropertyDescriptor) element).getDisplayName();
            }
            return super.getText(element);
        }

        /**
         * {@inheritDoc}
         */
        public Image getImage(Object element) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                IPropertyDescriptor propDesc = (IPropertyDescriptor) element;
                ILabelProvider labelProvider = propDesc.getLabelProvider();
                return labelProvider.getImage(propDesc.getId());
            }

            return super.getImage(element);
        }

        /**
         * {@inheritDoc}
         */
        public Color getForeground(Object element) {
            return super.getForeground(element);
        }

        /**
         * {@inheritDoc}
         */
        public Color getBackground(Object element) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                ILabelProvider labelProvider = ((IPropertyDescriptor) element).getLabelProvider();
                if (labelProvider instanceof IColorProvider) {
                    return ((IColorProvider) labelProvider).getBackground(m_propSource);
                }
            }

            return super.getBackground(element);
        }
    }

    /**
     * Label provider for property values.
     * 
     * @author BREDEX GmbH
     * @created Apr 7, 2010
     */
    private final class PropertyValueLabelProvider extends ColumnLabelProvider {
        /**
         * {@inheritDoc}
         */
        public String getText(Object element) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                ILabelProvider labelProvider = ((IPropertyDescriptor) element).getLabelProvider();
                return labelProvider
                        .getText(m_propSource.getPropertyValue(((IPropertyDescriptor) element).getId()));
            }

            return null;
        }

        /**
         * {@inheritDoc}
         */
        public Color getForeground(Object element) {
            if (m_propSource instanceof AbstractNodePropertySource) {
                AbstractNodePropertySource guiNodePropSource = (AbstractNodePropertySource) m_propSource;
                if (guiNodePropSource.isReadOnly()) {
                    return LayoutUtil.GRAY_COLOR;
                }

            }

            if (!checkEditorPart()) {
                return LayoutUtil.GRAY_COLOR;
            }

            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                ILabelProvider labelProvider = ((IPropertyDescriptor) element).getLabelProvider();
                if (labelProvider instanceof IColorProvider) {
                    return ((IColorProvider) labelProvider).getForeground(((IPropertyDescriptor) element).getId());
                }
            }

            return super.getForeground(element);
        }

        /**
         * {@inheritDoc}
         */
        public String getToolTipText(Object element) {
            String displayedText = getText(element);
            if (displayedText != null && displayedText.length() > 0) {
                return displayedText;
            }
            return null;
        }
    }

    /**
     * @author BREDEX GmbH
     * @created Sep 20, 2010
     */
    private final class PropertiesElementComparer implements IElementComparer {
        /**
         * {@inheritDoc}
         */
        public int hashCode(Object element) {
            // ignore JBPropertyDescriptor as this leads to incorrect behavior
            // e.g. when deleting params from a spec tc via edit parameters
            if (element instanceof IPropertyDescriptor && !(element instanceof JBPropertyDescriptor)) {
                IPropertyDescriptor pd = (IPropertyDescriptor) element;
                HashCodeBuilder hb = new HashCodeBuilder();
                hb.append(pd.getCategory());
                hb.append(pd.getDisplayName());
                Object id = pd.getId();
                if (id instanceof IPropertyController) {
                    IPropertyController pdpc = (IPropertyController) id;
                    hb.append(pdpc.getProperty());
                }
                return hb.toHashCode();
            }
            return ObjectUtils.hashCode(element);
        }

        /**
         * {@inheritDoc}
         */
        public boolean equals(Object a, Object b) {
            // ignore JBPropertyDescriptor as this leads to incorrect behavior
            // e.g. when deleting params from a spec tc via edit parameters
            if (a instanceof IPropertyDescriptor && b instanceof IPropertyDescriptor
                    && !(a instanceof JBPropertyDescriptor || b instanceof JBPropertyDescriptor)) {
                IPropertyDescriptor pd1 = (IPropertyDescriptor) a;
                IPropertyDescriptor pd2 = (IPropertyDescriptor) b;
                EqualsBuilder eb = new EqualsBuilder();
                eb.append(pd1.getCategory(), pd2.getCategory());
                eb.append(pd1.getDisplayName(), pd2.getDisplayName());
                Object id1 = pd1.getId();
                Object id2 = pd2.getId();
                if (id1 instanceof IPropertyController && id2 instanceof IPropertyController) {
                    IPropertyController pd1pc = (IPropertyController) id1;
                    IPropertyController pd2pc = (IPropertyController) id2;
                    eb.append(pd1pc.getProperty(), pd2pc.getProperty());
                }
                return eb.isEquals();
            }
            return ObjectUtils.equals(a, b);
        }
    }

    /** the context provider for this view */
    private JBContextProvider m_contextProvider = new JBContextProvider();
    /** helpListener of this view */
    private ContextHelpListener m_helpListener = new ContextHelpListener();

    /** the Component Name cache to use when this page is active */
    private IComponentNameCache m_compCache;

    /** current editor */
    private AbstractJBEditor m_currentEditor = Plugin.getDefault().getActiveJBEditor();

    /** the focus manager for the tree viewer */
    private TreeViewerFocusCellManager m_focusCellManager;

    /**
     * Constructor.
     * 
     * @param isEditable <code>true</code> if the properties shown in the view
     *                   should initially be editable.
     * @param compCache the Component Name cache to use when this page is 
     *                   active. May be <code>null</code>, if no specific
     *                   mapper should be used.
     */
    public JBPropertiesPage(boolean isEditable, IComponentNameCache compCache) {
        super();
        m_compCache = compCache;
        m_isEditable = isEditable;
    }

    /** 
     * {@inheritDoc}
     */
    public void createPartControl(Composite parent) {
        buildTree(parent);

        Plugin.getHelpSystem().setHelp(m_treeViewer.getControl(), ContextHelpIds.JB_PROPERTIES_VIEW);
        final DataEventDispatcher dispatcher = DataEventDispatcher.getInstance();
        dispatcher.addDataChangedListener(this, true);
        dispatcher.addParamChangedListener(this, true);
        dispatcher.addPartClosedListener(this, true);
        m_treeViewer.getControl().addHelpListener(m_helpListener);
        getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this);
    }

    /**
     * Creates a new Tree for this View.
     * @param parent the parent composite
     */
    private void buildTree(Composite parent) {
        GridData layoutData = new GridData(GridData.FILL_BOTH);
        layoutData.grabExcessHorizontalSpace = true;
        Tree tree = new Tree(parent, SWT.BORDER | SWT.HIDE_SELECTION | SWT.FULL_SELECTION);
        tree.setLayoutData(layoutData);
        tree.setHeaderVisible(true);
        tree.setLinesVisible(true);
        m_treeViewer = new TreeViewer(tree);
        // add expand/collapse column
        TreeViewerColumn expandCollapseColumn = new TreeViewerColumn(m_treeViewer, SWT.NONE);
        expandCollapseColumn.getColumn().setText(StringConstants.EMPTY);
        expandCollapseColumn.getColumn().setWidth(20);
        expandCollapseColumn.getColumn().setResizable(false);
        expandCollapseColumn.setLabelProvider(new CellLabelProvider() {
            public void update(ViewerCell cell) {
                // Nothing to display. Nothing to update.
            }
        });
        final int width = m_treeViewer.getTree().getParent().getClientArea().width;

        /* We make sure to have an initial size, just in case. */
        final int area = (width <= 100) ? 100 : width;

        // add property name column
        TreeViewerColumn propertyNameColumn = new TreeViewerColumn(m_treeViewer, SWT.NONE);
        propertyNameColumn.getColumn().setText(Messages.JubulaPropertiesViewProperty);
        propertyNameColumn.getColumn().setWidth((int) (width * 0.36));
        propertyNameColumn.setLabelProvider(new PropertyNameLabelProvider());

        // add property value column
        TreeViewerColumn propertyValueColumn = new TreeViewerColumn(m_treeViewer, SWT.NONE);
        propertyValueColumn.getColumn().setText(Messages.JubulaPropertiesViewValue);
        propertyValueColumn.getColumn().setWidth((int) (width * 0.54));
        propertyValueColumn.setLabelProvider(new PropertyValueLabelProvider());
        propertyValueColumn.setEditingSupport(new PropertiesEditingSupport(m_treeViewer));

        m_treeViewer.addSelectionChangedListener(m_helpContextListener);
        m_treeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
        m_treeViewer.setContentProvider(new PropertiesContentProvider());
        ColumnViewerToolTipSupport.enableFor(m_treeViewer);
        m_treeViewer.setComparer(new PropertiesElementComparer());
        m_focusCellManager = new TreeViewerFocusCellManager(m_treeViewer,
                new FocusCellOwnerDrawHighlighter(m_treeViewer));
        ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(m_treeViewer) {
            protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
                return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
                        || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
                        || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED
                                && event.keyCode == SWT.CR)
                        || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
            }
        };
        TreeViewerEditor.create(m_treeViewer, m_focusCellManager, actSupport, ColumnViewerEditor.TABBING_VERTICAL
                | ColumnViewerEditor.KEYBOARD_ACTIVATION | ColumnViewerEditor.KEEP_EDITOR_ON_DOUBLE_CLICK);
    }

    /** 
     * {@inheritDoc}
     */
    public void setFocus() {
        getControl().setFocus();
    }

    /**
     * {@inheritDoc}
     */
    public void dispose() {
        if (m_treeViewer != null) {
            m_treeViewer.removeSelectionChangedListener(m_helpContextListener);
        }
        final DataEventDispatcher dispatcher = DataEventDispatcher.getInstance();
        dispatcher.removeDataChangedListener(this);
        dispatcher.removeParamChangedListener(this);
        dispatcher.removePartClosedListener(this);
        getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this);
        getSite().setSelectionProvider(null);
        setCurrentEditor(null);
    }

    /** {@inheritDoc} */
    public void handleDataChanged(DataChangedEvent... events) {
        for (DataChangedEvent e : events) {
            handleDataChanged(e.getPo(), e.getDataState());
        }
    }

    /**
     * {@inheritDoc}
     */
    public void handleDataChanged(final IPersistentObject po, final DataState dataState) {
        Plugin.getDisplay().syncExec(new Runnable() {
            public void run() {
                // indirection necessary due to Checkstyle BUG
                handleDataChangedImpl(po, dataState);
            }
        });
    }

    /**
     * @param po
     *            the po
     * @param dataState
     *            the data state
     */
    private void handleDataChangedImpl(final IPersistentObject po, final DataState dataState) {
        if (po == null) {
            return;
        }

        // Check if the patent of the current node has been changed.
        // This will happen if a child of a SpecTC is displayed
        // and the editor with that SpecTC is saved.
        boolean parentMatch = false;
        if (getCurrentPO() instanceof INodePO) {
            INodePO parent = ((INodePO) getCurrentPO()).getSpecAncestor();
            parentMatch = (parent != null) && po.equals(parent);
        }

        if (parentMatch || po.equals(getCurrentPO())) {
            switch (dataState) {
            case Added:
            case StructureModified:
                if (po != null) {
                    Plugin.getDisplay().syncExec(new Runnable() {
                        public void run() {
                            m_treeViewer.refresh();
                        }
                    });
                    expandTrackedChanges();
                }
                break;
            case Deleted:
                clearView();
                break;
            case Renamed:
                Plugin.getDisplay().syncExec(new Runnable() {
                    public void run() {
                        m_treeViewer.refresh();
                    }
                });
                expandTrackedChanges();
                break;
            default:
            }
        }
    }

    /**
     * @return the current PO
     */
    private IPersistentObject getCurrentPO() {
        return (IPersistentObject) m_treeViewer.getInput();
    }

    /**
     * Expands the tracked changes in the properties view.
     * For some reasons the view needs persuasion to expand the tracked changes sometimes.
     */
    private void expandTrackedChanges() {
        Plugin.getDisplay().syncExec(new Runnable() {
            public void run() {
                m_treeViewer.setExpandedState(Messages.SpecTestCaseGUIPropertySourceTrackedChangesCategory, true);
            }
        });
    }

    /**
     * Clears the view.
     */
    private void clearView() {
        Plugin.getDisplay().syncExec(new Runnable() {
            public void run() {
                m_treeViewer.setComparer(null);
                m_treeViewer.setInput(null);
                setViewEnabled(false);
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public void handleParamChanged() {
        if (Plugin.getActivePart() instanceof PropertySheet) {
            if (((PropertySheet) Plugin.getActivePart()).getCurrentPage() != this) {
                return;
            }
        }
        Plugin.getDisplay().syncExec(new Runnable() {
            public void run() {
                m_treeViewer.refresh();
                m_treeViewer.expandToLevel(m_treeViewer.getAutoExpandLevel());
            }
        });
    }

    /**
     * Reacts on the changes from the SelectionService of Eclipse.
     * 
     * @param part
     *            the workbench part
     * @param selection
     *            the selection
     */
    private void reactOnChange(IWorkbenchPart part, IStructuredSelection selection) {

        m_correspondingPart = part;
        final Object firstElement = selection.getFirstElement();

        Plugin.getDisplay().syncExec(new Runnable() {
            public void run() {
                if (firstElement == null) {
                    // e.g. when a project was opened and no view has a selection
                    m_treeViewer.setSelection(null);
                    m_treeViewer.setInput(null);
                } else { // TestResultNodes must be excluded
                    if (firstElement instanceof IPersistentObject) {
                        m_treeViewer.setInput(firstElement);
                        workaroundSpringySelection(m_focusCellManager);
                    }
                }
                // property informations should be collapsed by default
                m_treeViewer.setExpandedState(Messages.OMTechNameGUIPropertySourcePropertyInformation, false);

                // parameters should be expanded by default
                m_treeViewer.setExpandedState(Messages.SpecTestCaseGUIPropertySourceParameter, true);
            }
        });

        expandTrackedChanges();

        setViewEnabled(!(part instanceof TestCaseBrowser || part instanceof TestSuiteBrowser
                || part instanceof JBPropertiesPage || part instanceof TestResultTreeView
                || part instanceof CompNamesView));

    }

    /**
     * Workaround for ticket #3012. Prevents odd cell selection 
     * behavior by pre-emptively setting the focus cell, if it is not already 
     * set. This workaround relies <b>heavily</b> on reflection. so the smallest
     * change to JFace might break it. A try-catch(throwable) block is used to 
     * minimize the damage that such a breakage would cause. Worst-case 
     * scenario: The bug is not fixed and a small performance penalty is 
     * incurred by looking everything up via reflection.
     * 
     * @param focusCellManager The focus manager on which to perform the 
     *                         workaround.
     */
    private void workaroundSpringySelection(TreeViewerFocusCellManager focusCellManager) {
        try {
            if (focusCellManager.getFocusCell() == null) {
                Class focusManagerClass = focusCellManager.getClass();
                Class abstractFocusManagerClass = focusManagerClass.getSuperclass();
                Method getInitialFocusCellMethod = focusManagerClass.getDeclaredMethod("getInitialFocusCell", //$NON-NLS-1$
                        new Class[0]);
                Method setFocusCellMethod = abstractFocusManagerClass.getDeclaredMethod("setFocusCell", //$NON-NLS-1$
                        ViewerCell.class);
                getInitialFocusCellMethod.setAccessible(true);
                setFocusCellMethod.setAccessible(true);
                Object initialFocusCellObj = getInitialFocusCellMethod.invoke(focusCellManager, new Object[0]);
                if (initialFocusCellObj instanceof ViewerCell) {
                    ViewerCell initialFocusCell = (ViewerCell) initialFocusCellObj;
                    setFocusCellMethod.invoke(focusCellManager, initialFocusCell);
                }
            }
        } catch (Throwable t) {
            LOG.info(Messages.ErrorInWorkaroundForSpringySelection, t);
        }
    }

    /**
     * Sets the widget in the treeView enabled or disabled.
     * @param enabled The disabled/enabled flag.
     * <p> It is <code>true</code>, if a node in the editor is selected. </p>
     * <p> It is <code>false</code>, if a node in one of the treeViews is selected. </p>
     */
    void setViewEnabled(boolean enabled) {
        m_isEditable = enabled;
        Color bColor = null;
        Color fColor = null;
        if (!enabled) {
            bColor = LayoutUtil.LIGHT_GRAY_COLOR;
            fColor = LayoutUtil.GRAY_COLOR;
        }
        getControl().setBackground(bColor);
        getControl().setForeground(fColor);
    }

    /**
     * @return <code>true</code> if the contributing part is the currently 
     *         active editor. Otherwise, <code>false</code>.
     */
    private boolean checkEditorPart() {
        return (Plugin.getActiveEditor() != null && Plugin.getActiveEditor().equals(m_correspondingPart));
    }

    /**
      * @param text The text field to set a max. char range.
      * @param propD The propertyDescriptor of the text field.
      */
    private void setMaxChar(Text text, Object propD) {
        if (!m_isEditable) {
            return;
        }
        if (propD instanceof TextPropertyDescriptor) {
            LayoutUtil.setMaxChar(text);
        }
    }

    /**
     * Content provider for properties.
     *
     * @author BREDEX GmbH
     * @created Apr 7, 2010
     */
    private final class PropertiesContentProvider implements ITreeContentProvider {

        /**
         * {@inheritDoc}
         */
        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof String) {
                // category
                List<IPropertyDescriptor> children = new ArrayList<IPropertyDescriptor>();
                for (IPropertyDescriptor propDesc : m_propSource.getPropertyDescriptors()) {
                    if (parentElement.equals(propDesc.getCategory())) {
                        children.add(propDesc);
                    }
                }
                return children.toArray();
            }

            return null;
        }

        /**
         * {@inheritDoc}
         */
        public Object getParent(Object element) {
            if (element instanceof IPropertyDescriptor) {
                return ((IPropertyDescriptor) element).getCategory();
            }
            return null;
        }

        /**
         * {@inheritDoc}
         */
        public boolean hasChildren(Object element) {
            return element instanceof String;

        }

        /**
         * {@inheritDoc}
         */
        public Object[] getElements(Object inputElement) {
            IPropertyDescriptor[] descriptors = getPropertyDescriptors(inputElement);
            Set<String> categories = new LinkedHashSet<String>();
            Set<IPropertyDescriptor> topLevelDescriptors = new LinkedHashSet<IPropertyDescriptor>();

            for (IPropertyDescriptor descriptor : descriptors) {
                String category = descriptor.getCategory();
                if (category == null) {
                    topLevelDescriptors.add(descriptor);
                } else {
                    categories.add(category);
                }
            }

            List<Object> children = new ArrayList<Object>();
            children.addAll(topLevelDescriptors);
            children.addAll(categories);
            return children.toArray();
        }

        /**
         * 
         * @param element The adaptable element.
         * @return the property source for the given <code>element</code>, or 
         *         <code>null</code> if no such property source can be found.
         */
        private IPropertySource getPropertySource(Object element) {
            if (element != null) {
                Object propertySourceObj = null;
                if (element instanceof IAdaptable) {
                    IAdaptable adaptable = (IAdaptable) element;
                    propertySourceObj = adaptable.getAdapter(IPropertySource.class);
                } else {
                    propertySourceObj = Platform.getAdapterManager().getAdapter(element, IPropertySource.class);
                }
                if (propertySourceObj instanceof IPropertySource) {
                    return (IPropertySource) propertySourceObj;
                }
            }

            return null;
        }

        /**
         * 
         * @param element The element for which to get the descriptors.
         * @return the corresponding property descriptors if <code>element</code>
         *         is a valid gui node. Otherwise returns an empty array.
         */
        private IPropertyDescriptor[] getPropertyDescriptors(Object element) {
            if (element instanceof INodePO) {
                INodePO guiNodeInput = (INodePO) element;
                if (isValid(guiNodeInput)) {
                    IPropertySource propertySource = getPropertySource(element);
                    if (propertySource != null) {
                        return propertySource.getPropertyDescriptors();
                    }
                }
            } else {
                IPropertySource propertySource = getPropertySource(element);
                if (propertySource != null) {
                    return propertySource.getPropertyDescriptors();
                }
            }

            return new IPropertyDescriptor[0];
        }

        /**
         * 
         * @param node The node to check.
         * @return <code>false</code> if the node is a Test Step with an invalid
         *         component. Otherwise, <code>true</code>. 
         */
        private boolean isValid(INodePO node) {
            return node != null && node.isValid();
        }

        /**
         * {@inheritDoc}
         */
        public void dispose() {
            // Nothing to dispose
        }

        /**
         * {@inheritDoc}
         */
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            m_propSource = getPropertySource(newInput);
        }

    }

    /**
     * Editing support for properties shown in the view.
     *
     * @author BREDEX GmbH
     * @created Apr 8, 2010
     */
    private final class PropertiesEditingSupport extends EditingSupport {

        /**
         * Constructor
         * 
         * @param viewer The viewer.
         */
        public PropertiesEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        /**
         * {@inheritDoc}
         */
        protected boolean canEdit(Object element) {
            if (m_correspondingPart instanceof IEditorPart) {

                if (element instanceof IPropertyDescriptor) {
                    Object propId = ((IPropertyDescriptor) element).getId();
                    if (m_propSource instanceof AbstractNodePropertySource
                            && propId instanceof IParameterPropertyController) {
                        return ((AbstractNodePropertySource) m_propSource)
                                .isParameterEntryEnabled((IParameterPropertyController) propId);
                    }
                }
                return true;
            }

            return false;
        }

        /**
         * {@inheritDoc}
         */
        protected CellEditor getCellEditor(Object element) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                CellEditor editor = ((IPropertyDescriptor) element).createPropertyEditor(m_treeViewer.getTree());
                if (editor != null) {
                    Control editorControl = editor.getControl();
                    if (editorControl instanceof Text) {
                        setMaxChar((Text) editorControl, element);
                    }
                }
                return editor;
            }
            return null;
        }

        /**
         * {@inheritDoc}
         */
        protected Object getValue(Object element) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                return m_propSource.getPropertyValue(((IPropertyDescriptor) element).getId());
            }

            return null;
        }

        /**
         * {@inheritDoc}
         */
        protected void setValue(Object element, Object value) {
            if (element instanceof IPropertyDescriptor && m_propSource != null) {
                IPropertyDescriptor propDesc = (IPropertyDescriptor) element;
                Object oldValue = m_propSource.getPropertyValue(propDesc.getId());
                if (oldValue == null || !oldValue.equals(value)) {
                    if (m_currentEditor.getEditorHelper().requestEditableState() == EditableState.OK) {

                        m_propSource.setPropertyValue(propDesc.getId(), value);
                        if (getCurrentEditor() != null) {
                            getCurrentEditor().getEditorHelper().setDirty(true);
                        }
                    }
                }
            }
        }

    }

    /**
     * Updates Help Context based on Selection Changed events.
     *
     * @author BREDEX GmbH
     * @created Apr 8, 2010
     */
    private final class HelpContextListener implements ISelectionChangedListener {
        /**
         * <code>m_oldSelection</code>
         */
        private Object m_oldSelection = null;

        /**
         * {@inheritDoc}
         */
        public void selectionChanged(SelectionChangedEvent event) {
            String helpId = ContextHelpIds.PRAEFIX;
            if (!(event.getSelection() instanceof IStructuredSelection)) {
                return;
            }

            Object selectedObj = ((IStructuredSelection) event.getSelection()).getFirstElement();
            if (!(selectedObj instanceof IPropertyDescriptor) || ObjectUtils.equals(m_oldSelection, selectedObj)) {
                return;
            }
            m_oldSelection = selectedObj;

            Object descriptorId = ((IPropertyDescriptor) selectedObj).getId();

            if (descriptorId instanceof ComponentTypeController
                    || descriptorId instanceof ComponentNameController) {

                helpId += getCompInfo().getHelpid();
            } else if (descriptorId instanceof ActionTypeController) {
                helpId += getActionInfo().getHelpid();
            } else if (descriptorId instanceof ParameterNameController) {
                helpId += getParamInfo(((ParameterNameController) descriptorId).getName()).getHelpid();
            } else if (descriptorId instanceof ParameterValueController) {
                helpId += getParamInfo(((ParameterValueController) descriptorId).getParamDesc().getUniqueId())
                        .getHelpid();
            } else if (descriptorId instanceof ParameterTypeController) {
                helpId += getParamInfo(((ParameterTypeController) descriptorId).getName()).getHelpid();
            }

            if (ContextHelpIds.PRAEFIX.equals(helpId)) {
                helpId = ContextHelpIds.JB_PROPERTIES_VIEW;
            }

            IWorkbenchHelpSystem helpSystem = Plugin.getHelpSystem();
            helpSystem.setHelp(m_treeViewer.getControl(), helpId);
            if (helpSystem.isContextHelpDisplayed() || Plugin.getView(Constants.ECLIPSE_HELP_VIEW_ID) != null) {
                helpSystem.displayHelp(helpId);
            }
        }

        /**
         * @param paramName the current parameter name
         * @return the current parameter helpID
         */
        private ParamInfo getParamInfo(String paramName) {
            return new ParamInfo(getAction().findParam(paramName), getActionInfo().getHelpid());
        }

        /**
         * @return the current action helpID
         */
        private ActionInfo getActionInfo() {
            CompSystemProcessor processor = new CompSystemProcessor(ComponentBuilder.getInstance().getCompSystem());
            ComponentInfo definingComp = processor.getDefiningComp(getCompInfo(), getAction());
            return new ActionInfo(getAction(), definingComp);
        }

        /**
         * @return the current action
         */
        private Action getAction() {
            return getComp().findAction(((ICapPO) getCurrentPO()).getActionName());
        }

        /**
         * @return the current component helpID
         */
        private ComponentInfo getCompInfo() {
            Component comp = getComp();
            ToolkitInfo tkInfo = CompSystemProcessor.getToolkitInfo(comp.getToolkitDesriptor());
            return new ComponentInfo(comp, tkInfo);
        }

        /**
         * @return the current component
         */
        private Component getComp() {
            return ComponentBuilder.getInstance().getCompSystem()
                    .findComponent(((ICapPO) getCurrentPO()).getComponentType());
        }
    }

    /**
     * {@inheritDoc}
     */
    public void handlePartClosed(IWorkbenchPart part) {
        final IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
        IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
        if (activePage == null) {
            // if Jubula was closed
            return;
        }
        IWorkbenchPart activePart = activePage.getActivePart();
        if (activePart == null) {
            // if the last Jubula perspective was closed
            return;
        }
        if (part == m_correspondingPart || m_correspondingPart == null || part instanceof JBPropertiesPage) {

            ISelection sel = activeWorkbenchWindow.getSelectionService().getSelection();

            if (sel == null || !(part instanceof IDataChangedListener) || part instanceof JBPropertiesPage
                    || activePart instanceof JBPropertiesPage) {

                clearView();
                return;
            }
            if (sel instanceof IStructuredSelection) {
                reactOnChange(activePart, (IStructuredSelection) sel);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public Object getAdapter(Class adapter) {
        if (adapter.equals(IContextProvider.class)) {
            return m_contextProvider;
        } else if (adapter.equals(IPropertySheetPage.class)) {
            return this;
        } else if (adapter.equals(IComponentNameCache.class) && m_compCache != null) {
            return m_compCache;
        }
        return null;
    }

    /**
     * @author BREDEX GmbH
     * @created Jan 22, 2007
     */
    private final class ContextHelpListener implements HelpListener {
        /** {@inheritDoc} */
        public void helpRequested(HelpEvent e) {
            IContext context = m_contextProvider.getContext(m_treeViewer.getControl().getData(ContextHelpIds.HELP));
            Plugin.getHelpSystem().displayHelp(context);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void createControl(Composite parent) {
        createPartControl(parent);
    }

    /**
     * {@inheritDoc}
     */
    public Control getControl() {
        return m_treeViewer.getControl();
    }

    /**
     * {@inheritDoc}
     */
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        if (part instanceof IJBPart && selection instanceof IStructuredSelection) {
            reactOnChange(part, (IStructuredSelection) selection);
        }
    }

    /**
     * @param currentEditor the currentEditor to set
     */
    private void setCurrentEditor(AbstractJBEditor currentEditor) {
        m_currentEditor = currentEditor;
    }

    /**
     * @return the currentEditor
     */
    public AbstractJBEditor getCurrentEditor() {
        return m_currentEditor;
    }

}