com.jaspersoft.studio.property.section.style.StylesListSection.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.property.section.style.StylesListSection.java

Source

/*******************************************************************************
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 * 
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 * 
 * 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
 ******************************************************************************/
package com.jaspersoft.studio.property.section.style;

import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.design.JRDesignReportTemplate;
import net.sf.jasperreports.engine.design.JRDesignStyle;
import net.sf.jasperreports.engine.type.JREnum;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.wb.swt.ResourceCache;
import org.eclipse.wb.swt.ResourceManager;
import org.eclipse.wb.swt.SWTResourceManager;

import com.jaspersoft.studio.ExternalStylesManager;
import com.jaspersoft.studio.JSSCompoundCommand;
import com.jaspersoft.studio.JaspersoftStudioPlugin;
import com.jaspersoft.studio.editor.gef.parts.EditableFigureEditPart;
import com.jaspersoft.studio.messages.Messages;
import com.jaspersoft.studio.messages.MessagesByKeys;
import com.jaspersoft.studio.model.ANode;
import com.jaspersoft.studio.model.APropertyNode;
import com.jaspersoft.studio.model.DefaultValuesMap;
import com.jaspersoft.studio.model.INode;
import com.jaspersoft.studio.model.MLineBox;
import com.jaspersoft.studio.model.MLinePen;
import com.jaspersoft.studio.model.MPage;
import com.jaspersoft.studio.model.style.MConditionalStyle;
import com.jaspersoft.studio.model.style.MStyle;
import com.jaspersoft.studio.model.style.MStyleTemplate;
import com.jaspersoft.studio.model.style.MStyles;
import com.jaspersoft.studio.model.style.MStylesTemplate;
import com.jaspersoft.studio.model.text.MParagraph;
import com.jaspersoft.studio.properties.view.TabbedPropertySheetPage;
import com.jaspersoft.studio.property.section.AbstractSection;
import com.jaspersoft.studio.utils.Colors;
import com.jaspersoft.studio.utils.GridDataUtil;
import com.jaspersoft.studio.utils.UIUtil;

/**
 * Class that paint the widget where are shown the attributes of element, those inherited by the it's styles, and the
 * default values
 * 
 * @author Orlandin Marco
 * 
 */
public class StylesListSection extends AbstractSection {

    /**
     * Color for the text that represent the attribute name
     */
    private static Color leftStringColor = null;

    /**
     * Image show to remove an attribute
     */

    private static Image image = ResourceManager.getPluginImage(JaspersoftStudioPlugin.PLUGIN_ID,
            "icons/resources/remove-16.png"); //$NON-NLS-1$

    /**
     * Map of all the styles, where the key is the style value for the internal style and
     * the style name for the external ones
     */
    private HashMap<Object, StyleContainer> styleMaps;

    /**
     * List of attributes overridden by others of an upper level in the hierarchy (the hierarchy is element-styles-default
     * style-default attribute)
     */
    private HashSet<String> ovverridenAttributes;

    /**
     * Reference to the default style
     */
    private MStyle defaultStyle = null;

    /**
     * The map of the element own attributes
     */
    private HashMap<String, Object> elementAttributes = null;

    /**
     * Manager for the events binded to the mouse
     */
    private IconMouseTracker trackerListener = new IconMouseTracker();

    /**
     * Used as guard when an remove click listener is created. If it's true the listener assume that it's created because
     * it's assigned to the main element, otherwise it was Assigned to a an element in the hierarchy of the main element.
     * This could be done using a parameter Instead of a local variable, but to keep the method signature more simply this
     * approach was choose
     */
    private Boolean mainElementEvent;

    /**
     * When a property of the element change an update job is runned. This update job is delayed and cancelled
     * if another update job is requested before it start
     */
    private UpdatePanelJob updatePanelJob = new UpdatePanelJob();

    /**
     * Job to update the panel UI when expression text changes or
     * when caret is moved. 
     * This job is supposed to be delayed in order not to call
     * UI-update events too often (avoiding flickering effects).
     */
    private class UpdatePanelJob extends WorkbenchJob {

        public UpdatePanelJob() {
            super("Update Styles Tab");
            setSystem(true);
        }

        @Override
        public IStatus runInUIThread(IProgressMonitor monitor) {
            if (shown) {
                monitor.beginTask("Update Styles Tab", IProgressMonitor.UNKNOWN);
                createContent();
                monitor.done();
                return Status.OK_STATUS;
            } else {
                return Status.CANCEL_STATUS;
            }
        }
    }

    /**
     * The delay of the update job
     */
    private static final int UPDATE_DELAY = 100;

    /**
     * Boolean flag to take trace it the tab is shown
     */
    private boolean shown = false;

    /**
     * Color used from the label as background
     */
    private static final Color labelBackgroundColor = SWTResourceManager.getColor(240, 240, 240);;

    /**
     * map cache of the colors, they are disposed when the section is disposed
     */
    private ResourceCache colorCache = new ResourceCache();

    /**
     * Class to manage the events of the mouse click, used to remove an attribute from an element or one of it's styles
     * 
     * @author Orlandin Marco
     * 
     */
    private class ElementClickListener implements MouseListener {

        /**
         * Element binded to this event
         */
        private APropertyNode targetElement;

        /**
         * Property of the element binded to this event
         */
        private String property;

        /**
         * True if this listener is used to remove a property from the main element, false otherwise. In this last case a
         * warning popup is showed before the cancellation
         */
        private boolean isTargetMain;

        public ElementClickListener(APropertyNode targetElement, String property) {
            isTargetMain = mainElementEvent;
            this.targetElement = targetElement;
            this.property = property;
        }

        public void mouseDown(MouseEvent e) {
        }

        /**
         * Set the property of the element binded to this event to null, using the manipulation commands (so the operation
         * can be undone)
         */
        public void mouseUp(MouseEvent e) {
            boolean executeCommand = true;
            if (!targetElement.isEditable()) {
                MessageBox messageBox = new MessageBox(e.widget.getDisplay().getActiveShell(),
                        SWT.ICON_QUESTION | SWT.YES | SWT.NO);
                messageBox.setText(Messages.StylesListSection_NotEditable_Title);
                messageBox.setMessage(Messages.StylesListSection_NotEditable_Message);
                int response = messageBox.open();
                executeCommand = false;
                if (response == SWT.YES) {
                    StyleContainer styleReference = styleMaps.get(((JRStyle) targetElement.getValue()).getName());
                    EditableFigureEditPart.openEditor(styleReference.getTemplateValue(),
                            ((DefaultEditDomain) getEditDomain()).getEditorPart(), styleReference.getTemplate());
                }
            } else if (!isTargetMain) {
                MessageBox messageBox = new MessageBox(e.widget.getDisplay().getActiveShell(),
                        SWT.ICON_WARNING | SWT.YES | SWT.NO);
                messageBox.setText(Messages.StylesListSection_Warining_Box_Title);
                messageBox.setMessage(Messages.StylesListSection_Warning_Box_Message);
                int buttonID = messageBox.open();
                if (buttonID == SWT.NO)
                    executeCommand = false;
            }
            if (executeCommand) {
                CommandStack cs = getEditDomain().getCommandStack();
                JSSCompoundCommand cc = new JSSCompoundCommand("Set " + property, targetElement); //$NON-NLS-1$
                Command c = getChangePropertyCommand(property, null, targetElement);
                if (c != null)
                    cc.add(c);
                if (!cc.getCommands().isEmpty()) {
                    cs.execute(cc);
                    // Force a refresh
                    createContent();
                    parent.setFocus();
                }
            }
        }

        public void mouseDoubleClick(MouseEvent e) {

        }
    }

    /**
     * This class encapsulate a style and eventually its external reference, used to handle easly the external styles
     * 
     * @author Orlandin Marco
     * 
     */
    private class StyleContainer {

        /**
         * The style
         */
        private MStyle style;

        /**
         * True if the style come from an external reference
         */
        private boolean external;

        /**
         * A reference to the external reference
         */
        private MStyleTemplate externalTemplate;

        /**
         * Encapsulate a local style
         * 
         * @param style
         *          the style model
         */
        public StyleContainer(MStyle style) {
            external = false;
            externalTemplate = null;
            this.style = style;
        }

        /**
         * Encapsulate an external style with its container
         * 
         * @param style
         *          the style
         * @param reference
         *          the container
         */
        public StyleContainer(MStyle style, MStyleTemplate reference) {
            external = true;
            externalTemplate = reference;
            this.style = style;
        }

        /**
         * Return if the style is external
         * 
         * @return true if the style it's external, false otherwise
         */
        public boolean isExternal() {
            return external;
        }

        /**
         * Return the style
         * 
         * @return the model of the style
         */
        public MStyle getStyle() {
            return style;
        }

        /**
         * Return the template
         * 
         * @return the template of the style
         */
        public MStyleTemplate getTemplate() {
            return externalTemplate;
        }

        /**
         * Return the value of the template
         * 
         * @return the JRElement of the template
         */
        public JRDesignReportTemplate getTemplateValue() {
            return (JRDesignReportTemplate) externalTemplate.getValue();
        }
    }

    /**
     * Class to manage the events of the mouse move event, as the mouse over and the mouse exit, used to show the button
     * to delete an attribute when the mouse pointer is over it
     * 
     * @author Orlandin Marco
     * 
     */
    private class IconMouseTracker implements MouseTrackListener {

        /**
         * Last element where the remove button was shown
         */
        Composite lastElementSelected = null;

        /**
         * Set the last element to null, necessary after a refresh of the widget because the old element were deallocated,
         * so this pointer need to be reseted too.
         */
        public void refresh() {
            lastElementSelected = null;
        }

        /**
         * Handle the event of the mouse enter on area that show the delete image, eventually hide the old one. Change event
         * the mouse cursor to an hand.
         */
        @Override
        public void mouseEnter(MouseEvent e) {
            Composite parentLayout = null;
            if (e.widget instanceof Composite)
                parentLayout = ((Composite) e.widget);
            else
                parentLayout = ((Control) e.widget).getParent();
            if (lastElementSelected == null)
                lastElementSelected = parentLayout;

            // We must be sure that the properties view is the one that currently is active
            if (parentLayout.getChildren().length > 1 && UIUtil.isPropertiesViewFocused()) {
                lastElementSelected.getChildren()[0].setVisible(false);
                lastElementSelected = parentLayout;
                parentLayout.getChildren()[0].setVisible(true);
                parentLayout.getChildren()[0].setCursor(new Cursor(null, SWT.CURSOR_HAND));
            }
        }

        /**
         * Handle the event of the mouse exit the area that show the delete image, hide the image
         */
        @Override
        public void mouseExit(MouseEvent e) {
            Composite parentLayout = null;
            if (e.widget instanceof Composite)
                parentLayout = ((Composite) e.widget);
            else
                parentLayout = ((Control) e.widget).getParent();
            if (parentLayout.getChildren().length > 1)
                parentLayout.getChildren()[0].setVisible(false);
        }

        @Override
        public void mouseHover(MouseEvent e) {
        }

    }

    /**
     * Return the key of the parent style of an element, check also if the style is an 
     * internal of an external one. In the first case the key is the jrstyle, in the second 
     * one it is the name of the style
     * 
     * @param child a JRElement or a JRStyle
     * @return the key of the style for the passed parameter, independently if it is
     * external or internal. Null if it has not a parent style of it has a not valid internal
     * parent style (a style that was removed)
     */
    private Object getStyleKey(APropertyNode element) {
        if (element.getValue() instanceof JRElement) {
            JRElement jrElement = (JRElement) element.getValue();
            if (jrElement.getStyle() != null)
                return jrElement.getStyle();
            else
                return jrElement.getStyleNameReference();
        } else if (element.getValue() instanceof JRStyle) {
            JRStyle jrStyle = (JRStyle) element.getValue();
            if (jrStyle.getStyle() != null)
                return jrStyle.getStyle();
            else
                return jrStyle.getStyleNameReference();
        }
        return null;
    }

    /**
     * Build the hierarchy of styles of an element
     * 
     * @param element
     *          Element from which the styles list will be generated
     * @return A list of MStyle, where the first is the style assigned to the element, the second is the style assigned to
     *         the first item of the list and so on
     */
    private LinkedList<MStyle> buildStylesGerarchy(APropertyNode element) {
        LinkedList<MStyle> result = new LinkedList<MStyle>();
        Object styleKey;
        if (element instanceof MConditionalStyle) {
            //The external style dosen't allow a conditional style, so the parent must be a jrstyle
            styleKey = ((MStyle) element.getParent()).getValue();
        } else {
            styleKey = getStyleKey(element);
        }
        StyleContainer styleContainer = styleMaps.get(styleKey);
        if (styleContainer != null) {
            MStyle styleModel = styleContainer.getStyle();
            result.addLast(styleModel);
            Object nextStylKey = getStyleKey(styleModel);
            while (nextStylKey != null) {
                styleModel = styleMaps.get(nextStylKey).getStyle();
                result.addLast(styleModel);
                nextStylKey = getStyleKey(styleModel);
            }

        }
        return result;
    }

    /**
     * Add to a styledtext a new style to made the text with a middle black line (strike trought)
     * 
     * @param valueText
     *          StyledText widget where the new style will be applied
     */
    private void strikeStyledText(StyledText valueText) {
        StyleRange style1 = new StyleRange();
        style1.strikeout = true;
        style1.start = 0;
        style1.length = valueText.getText().length();
        valueText.setStyleRange(style1);
    }

    /**
     * Return the hexadecimal representation of a color
     * 
     * @param color
     *          The color
     * @return The color hexadecimal representation
     */
    private String getHexFromRGB(RGB color) {
        int r = color.red;
        int g = color.green;
        int b = color.blue;
        String s = Integer.toHexString(r) + Integer.toHexString(g) + Integer.toHexString(b);
        return "#" + StringUtils.rightPad(s, 6, "0").toUpperCase(); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * Paint on the main widget the fields to show the value of an attribute color. the color will be expressed in textual
     * form, as RGB values, but with a tooltip that show the visually the color
     * 
     * @param parent
     *          Reference to the widget composite
     * @param colorValue
     *          Value of the color
     * @param colorName
     *          Name of the attribute
     * @param gData
     *          Grid data for the layout
     * @param addLine
     *          true if a stroke line is needed
     * @param toolTip
     *          tooltip text of the element name label
     * @return The button where the click handle will be added
     */
    private Control paintColor(Composite parent, final RGB colorValue, String colorName, GridData gData,
            boolean addLine, String toolTip) {
        String stringValue = getHexFromRGB(colorValue);
        Composite nameComp = new Composite(parent, SWT.NONE);
        RowLayout layout = new RowLayout();
        nameComp.setLayout(layout);
        nameComp.setLayoutData(GridDataUtil.clone(gData));

        Label imageLabel = new Label(nameComp, SWT.NONE);
        imageLabel.setImage(image);
        imageLabel.setVisible(false);

        StyledText label = new StyledText(nameComp, SWT.NONE);
        label.setText(colorName); //$NON-NLS-1$
        label.setForeground(leftStringColor);
        label.setEditable(false);
        label.setEnabled(false);
        nameComp.setToolTipText(toolTip);

        Composite valueComp = new Composite(parent, SWT.NONE);
        RowLayout inLineLayout = new RowLayout();
        valueComp.setLayout(inLineLayout);
        valueComp.setLayoutData(GridDataUtil.clone(gData));

        StyledText valueText = new StyledText(valueComp, SWT.NONE);
        valueText.addPaintListener(new PaintListener() {
            public void paintControl(PaintEvent e) {
                e.gc.setBackground(colorCache.getColor(colorValue));
                e.gc.drawRectangle(0, 0, 13, 13);
                e.gc.fillRectangle(1, 1, 12, 12);

            }
        });
        valueText.setLeftMargin(18);
        valueText.setText(stringValue);
        valueText.setAlignment(SWT.LEFT);
        valueText.setEditable(false);
        valueText.setEnabled(true);
        RowData valueText_RD = new RowData();
        valueText_RD.height = 15;
        valueText.setLayoutData(valueText_RD);
        if (addLine) {
            strikeStyledText(valueText);
            strikeStyledText(label);
        }
        return imageLabel;
    }

    /**
     * Paint a couple of string as two label
     * 
     * @param parent
     *          Reference to the widget composite
     * @param name
     *          The name of the attribute
     * @param value
     *          The value of the attribute
     * @param gData
     *          Grid data for the layout
     * @param addLine
     *          true if a stroke line is needed
     * @param toolTip
     *          tooltip text of the element name label
     * @return The button where the click handle will be added
     */
    private Control printLabels(Composite parent, String name, String value, GridData gData, boolean addLine,
            String toolTip) {
        Composite valueComp = new Composite(parent, SWT.NONE);
        valueComp.setLayout(new RowLayout());
        valueComp.setLayoutData(gData);

        Label imageLabel = new Label(valueComp, SWT.NONE);
        imageLabel.setImage(image);
        imageLabel.setVisible(false);

        StyledText label = new StyledText(valueComp, SWT.NONE);
        label.setText(name); //$NON-NLS-1$
        label.setForeground(leftStringColor);
        label.setEditable(false);
        label.setEnabled(false);
        valueComp.setToolTipText(toolTip);

        StyledText valueText = new StyledText(parent, SWT.NONE);
        valueText.setText(value);
        valueText.setEditable(false);
        valueText.setEnabled(false);
        if (addLine) {
            strikeStyledText(valueText);
            strikeStyledText(label);
        }
        return imageLabel;
    }

    /**
     * Paint a boolean attribute, it's value is expressed as text
     * 
     * @param parent
     *          Reference to the widget composite
     * @param name
     *          The name of the attribute
     * @param checked
     *          true if the attribute has value true, false otherwise
     * @param gData
     *          Grid data for the layout
     * @param addLine
     *          true if a stoke line is needed
     * @param toolTip
     *          tooltip text of the element name label
     * @return The button where the click handle will be added
     */
    private Control paintCheckBox(Composite parent, String name, boolean checked, GridData gData, boolean addLine,
            String toolTip) {
        String stringValue = MessagesByKeys.getString("common_boolean_" + checked); //$NON-NLS-1$
        return printLabels(parent, name, stringValue, gData, addLine, toolTip);
    }

    /**
     * Add the mouse move listener to an element, it's father and it's brothers
     * 
     * @param element
     */
    private void AddListener(Control element) {
        Composite parent = element.getParent();
        parent.addMouseTrackListener(trackerListener);
        for (Control son : parent.getChildren()) {
            son.addMouseTrackListener(trackerListener);
        }
    }

    /**
     * Print a generic object attribute with the appropriate widgets on the main composite
     * 
     * @param keyPrefix
     *          optional prefix to the key represented by the name
     * @param name
     *          Name and key of the attribute
     * @param value
     *          value of the attribute
     * @param parent
     *          main widget
     * @param gData
     *          grid layout data
     * @param printLine
     *          True if the printed attribute need a strike thought line
     * @param actualElement
     *          element that contain the attribute
     * @param addListener
     *          true if to the element will be added the listener for the mouse move\click
     */
    private void printObject(String namePrefix, String name, Object value, Composite parent, GridData gData,
            boolean printLine, APropertyNode actualElement, boolean addListener,
            HashMap<String, Object> localContext) {
        if (value instanceof Color) {
            RGB valImage = ((Color) value).getRGB();
            Control label = paintColor(parent, valImage,
                    MessagesByKeys.getString("common".concat(namePrefix).concat("_").concat(name)), gData, //$NON-NLS-1$//$NON-NLS-2$
                    printLine, actualElement.getPropertyDescriptor(name).getDescription());
            if (addListener) {
                AddListener(label);
                label.addMouseListener(new ElementClickListener(actualElement, name));
                label.setToolTipText(Messages.StylesListSection_removeAttribure_tooltip); //$NON-NLS-1$
            }
        } else if (value instanceof java.awt.Color) {
            java.awt.Color valImage = (java.awt.Color) value;
            Control label = paintColor(parent, getSWTColorFromAWT(valImage),
                    MessagesByKeys.getString("common".concat(namePrefix).concat("_").concat(name)), gData, //$NON-NLS-1$//$NON-NLS-2$
                    printLine, actualElement.getPropertyDescriptor(name).getDescription());
            if (addListener) {
                AddListener(label);
                label.addMouseListener(new ElementClickListener(actualElement, name));
                label.setToolTipText(Messages.StylesListSection_removeAttribure_tooltip); //$NON-NLS-1$
            }
        } else if (value instanceof JREnum) {
            JREnum enumValue = (JREnum) value;
            Control label = printLabels(parent,
                    MessagesByKeys.getString("common".concat(namePrefix).concat("_").concat(name)), //$NON-NLS-1$//$NON-NLS-2$
                    enumValue.getName(), gData, printLine,
                    actualElement.getPropertyDescriptor(name).getDescription());
            if (addListener) {
                AddListener(label);
                label.addMouseListener(new ElementClickListener(actualElement, name));
                label.setToolTipText(Messages.StylesListSection_removeAttribure_tooltip); //$NON-NLS-1$
            }
        } else if (value instanceof Boolean) {
            Control label = paintCheckBox(parent,
                    MessagesByKeys.getString("common".concat(namePrefix).concat("_").concat(name)), (Boolean) value, //$NON-NLS-1$//$NON-NLS-2$
                    gData, printLine, actualElement.getPropertyDescriptor(name).getDescription());
            if (addListener) {
                AddListener(label);
                label.addMouseListener(new ElementClickListener(actualElement, name));
                label.setToolTipText(Messages.StylesListSection_removeAttribure_tooltip); //$NON-NLS-1$
            }
        } else if (value instanceof MLinePen) {
            MLinePen lineValue = (MLinePen) value;
            // I need to pass a new context for the linepen because it's a composite value, so in the main hashmap i have only
            // the
            // complex value, not all it's fields
            printStyleAttribute(parent, lineValue, null, namePrefix.concat("_").concat(name), //$NON-NLS-1$
                    ((MLinePen) localContext.get(name)).getStylesDescriptors(), addListener);
        } else if (value instanceof MParagraph) {
            MParagraph lineValue = (MParagraph) value;
            MParagraph ctxMParagraph = (MParagraph) localContext.get(name);
            HashMap<String, Object> stylesDescriptors = null;
            if (ctxMParagraph != null) {
                stylesDescriptors = ctxMParagraph.getStylesDescriptors();
            }
            printStyleAttribute(parent, lineValue, null, namePrefix.concat("_").concat(name), stylesDescriptors, //$NON-NLS-1$
                    addListener);
        } else if (value instanceof MLineBox) {
            MLineBox lineValue = (MLineBox) value;
            printStyleAttribute(parent, lineValue, null, namePrefix.concat("_").concat(name), //$NON-NLS-1$
                    ((MLineBox) localContext.get(name)).getStylesDescriptors(), addListener);
        } else {
            Control label = printLabels(parent,
                    MessagesByKeys.getString("common".concat(namePrefix).concat("_").concat(name)), //$NON-NLS-1$//$NON-NLS-2$
                    value.toString(), gData, printLine, actualElement.getPropertyDescriptor(name).getDescription());
            if (addListener) {
                AddListener(label);
                label.addMouseListener(new ElementClickListener(actualElement, name));
                label.setToolTipText(Messages.StylesListSection_removeAttribure_tooltip);
            }
        }
    }

    /**
     * Print a title label, gray that take a whole line
     * 
     * @param parent
     *          composite of the main widget
     * @param value
     *          text to put into the label
     */
    private Label printTitle(Composite parent, String value) {
        Label label = new Label(parent, SWT.NONE);
        GridData gridData = new GridData();
        gridData.horizontalAlignment = SWT.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.horizontalSpan = 2;
        gridData.widthHint = SWT.FILL;
        gridData.heightHint = 20;
        label.setLayoutData(gridData);
        label.setBackground(labelBackgroundColor);
        label.setText(" " + value); //$NON-NLS-1$
        return label;
    }

    /**
     * Print the attributes of an element store in the elementAttributes hash map
     * 
     * @param parent
     *          composite of the main widget
     * @param element
     *          The selected element
     * @param titleValue
     *          The title to print for this element
     */
    private void printElementAttribute(Composite parent, APropertyNode element, String titleValue) {
        if (titleValue != null) {
            printTitle(parent, titleValue);
        }
        GridData sameSizeGridData = new GridData();
        sameSizeGridData.verticalAlignment = SWT.CENTER;
        sameSizeGridData.heightHint = 20;
        sameSizeGridData.widthHint = 200;
        Iterator<String> it = elementAttributes.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            Object elementAttribute = elementAttributes.get(key);
            if (elementAttribute != null) {
                printObject("", key, elementAttribute, parent, sameSizeGridData, ovverridenAttributes.contains(key), //$NON-NLS-1$
                        element, true, elementAttributes);
                ovverridenAttributes.add(key);
            }
        }
    }

    /**
     * Print the attributes that belong to a styles
     * 
     * @param parent
     *          composite of the main widget
     * @param element
     *          The selected element
     * @param titleValue
     *          The title to print for this element
     * @param keyPrefix
     *          optional prefix of the attribute key
     * @param localElementAttributes
     *          Map that contains the attribute of the element associated with this style
     */
    private void printStyleAttribute(Composite parent, APropertyNode element, String titleValue, String keyPrefix,
            HashMap<String, Object> localElementAttributes, boolean addHandler) {
        if (titleValue != null) {
            Label titleLabel = printTitle(parent, titleValue);
            final StyleContainer styleReference = styleMaps.get(getStyleKey(element));
            if (styleReference != null && styleReference.isExternal()) {
                // If the style is external i made its editor open by double clicking on the style title
                titleLabel
                        .setText(titleLabel.getText().concat(Messages.StylesListSection_NotEditable_Visual_Marker));
                titleLabel.addMouseListener(new MouseListener() {
                    @Override
                    public void mouseUp(MouseEvent e) {
                    }

                    @Override
                    public void mouseDown(MouseEvent e) {
                    }

                    @Override
                    public void mouseDoubleClick(MouseEvent e) {
                        EditableFigureEditPart.openEditor(styleReference.getTemplateValue(),
                                ((DefaultEditDomain) getEditDomain()).getEditorPart(),
                                styleReference.getTemplate());
                    }
                });
            }
        }
        GridData sameSizeGridData = new GridData();
        sameSizeGridData.verticalAlignment = SWT.CENTER;
        sameSizeGridData.heightHint = 20;
        sameSizeGridData.widthHint = 200;
        HashMap<String, Object> properties = element.getStylesDescriptors();
        Iterator<String> it = properties.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            Object elementAttribute = properties.get(key);
            if (elementAttribute != null && localElementAttributes.containsKey(key)) {
                printObject(keyPrefix, key, elementAttribute, parent, sameSizeGridData,
                        ovverridenAttributes.contains(keyPrefix + key), element, addHandler,
                        localElementAttributes);
                ovverridenAttributes.add(keyPrefix + key);
            }
        }
    }

    /**
     * Print the attributes of all the styles of the element
     * 
     * @param styles
     *          List of styles
     * @param parent
     *          composite of the main widget
     */
    private void printStyles(LinkedList<MStyle> styles, Composite parent) {
        ListIterator<MStyle> itr = styles.listIterator();
        boolean hasDefaultStyleInGerarchy = false;
        while (itr.hasNext()) {
            MStyle style = itr.next();
            printStyleAttribute(parent, style, Messages.StylesSectionList_Inherited_From_Style
                    + style.getPropertyValue(JRDesignStyle.PROPERTY_NAME), "", elementAttributes, true); //$NON-NLS-1$
            if (style == defaultStyle)
                hasDefaultStyleInGerarchy = true;
        }
        if (!hasDefaultStyleInGerarchy && defaultStyle != null && defaultStyle != getElement())
            printStyleAttribute(parent, defaultStyle,
                    Messages.StylesListSection_Inherited_From_Default_Style
                            .concat(defaultStyle.getPropertyValue(JRDesignStyle.PROPERTY_NAME).toString()),
                    "", elementAttributes, true); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * Add the external list to the styles map, but only those with a different name from the one already added
     * 
     * @param stylesList
     */
    private void recursiveReadStyles(List<INode> stylesList, MStyleTemplate parentReference, JRStyle defaultValue) {
        for (INode style : stylesList) {
            if (style instanceof MStyle) {
                MStyle element = (MStyle) style;
                String name = element.getPropertyValue(JRDesignStyle.PROPERTY_NAME).toString();
                if (element.getValue() == defaultValue)
                    defaultStyle = element;
                styleMaps.put(name, new StyleContainer(element, parentReference));
            } else if (style instanceof MStyleTemplate) {
                recursiveReadStyles(style.getChildren(), (MStyleTemplate) style, defaultValue);
            }
        }
    }

    /**
     * Initialize the map of the styles
     */
    private void initStyleMaps() {
        styleMaps = new HashMap<Object, StyleContainer>();
        ovverridenAttributes = new HashSet<String>();
        if (leftStringColor == null) {
            leftStringColor = SWTResourceManager.getColor(42, 96, 213);
        }
        JRStyle defaultValue = getElement().getJasperDesign().getDefaultStyle();
        List<INode> list = getStylesRoot(getElement()).getChildren();
        List<INode> externalList = new ArrayList<INode>();
        for (INode style : list) {
            if (style instanceof MStyle) {
                MStyle element = (MStyle) style;
                styleMaps.put(element.getValue(), new StyleContainer(element));
                if (element.getValue() == defaultValue)
                    defaultStyle = element;
            } else if (style instanceof MStyleTemplate) {
                externalList.add(style);
            }
        }
        recursiveReadStyles(externalList, null, defaultValue);
    }

    /**
     * Print the default values of an element, the aren't editable
     * 
     * @param parent
     *          composite of the main widget
     * @param defaultValues
     *          map of the default values
     */
    private void printDefaultValues(Composite parent, Map<String, Object> defaultValues) {
        printTitle(parent, Messages.StylesListSection_defaultAttributesTitle);
        GridData sameSizeGridData = new GridData();
        sameSizeGridData.verticalAlignment = SWT.CENTER;
        sameSizeGridData.heightHint = 20;
        sameSizeGridData.widthHint = 200;
        Iterator<String> it = defaultValues.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            Object elementAttribute = defaultValues.get(key);
            if (elementAttribute != null && elementAttributes.containsKey(key)) {
                printObject("", key, elementAttribute, parent, sameSizeGridData, ovverridenAttributes.contains(key), //$NON-NLS-1$
                        getElement(), false, elementAttributes);
            }
        }
    }

    /**
     * Add not only this node to the notify handler but all it's root, so even change in it's styles will be notified
     */
    public void aboutToBeShown() {
        if (getElement() != null) {
            getElement().getRoot().getPropertyChangeSupport().removePropertyChangeListener(this);
            getElement().getRoot().getPropertyChangeSupport().addPropertyChangeListener(this);
            // Set the handler for every style also because in this way an update of the style is immediately reflected
            for (INode style : getStylesRoot(getElement()).getChildren()) {
                style.getPropertyChangeSupport().removePropertyChangeListener(this);
                style.getPropertyChangeSupport().addPropertyChangeListener(this);
            }
        }
        shown = true;
        createContent();
    }

    /**
     * Add not only this node to the notify handler but all it's root, so even change in it's styles will be notified
     */
    public void aboutToBeHidden() {
        if (getElement() != null && getElement().getRoot() != null) {
            getElement().getRoot().getPropertyChangeSupport().removePropertyChangeListener(this);
            ANode styles = getStylesRoot(getElement());
            // check in case the selected element was deleted
            if (styles != null) {
                for (INode style : styles.getChildren()) {
                    style.getPropertyChangeSupport().removePropertyChangeListener(this);
                }
            }
        }
        shown = false;
    }

    /**
     * Override of the property change handler, check if the last event received was already notified
     */
    public void propertyChange(PropertyChangeEvent evt) {
        if (!evt.getPropertyName().equals(ExternalStylesManager.STYLE_FOUND_EVENT)) {
            updatePanelJob.cancel();
            updatePanelJob.schedule(UPDATE_DELAY);
        }
    }

    /**
     * convert an awt color to an swt rgb
     * 
     * @param awtColor the color, must be not null
     * @return the rgb fo the color
     */
    private RGB getSWTColorFromAWT(java.awt.Color awtColor) {
        return Colors.getSWTRGB4AWTGBColor(awtColor).getRgb();
    }

    private void printWindowTitle(Composite parent) {
        StyledText label = new StyledText(parent, SWT.WRAP);
        GridData gridData = new GridData();
        gridData.horizontalAlignment = SWT.FILL;
        gridData.verticalAlignment = SWT.CENTER;
        gridData.horizontalSpan = 2;
        gridData.horizontalIndent = 5;
        gridData.heightHint = 20;
        label.setLayoutData(gridData);
        label.setFont(ResourceManager.getBoldFont(label.getFont()));
        label.setText(Messages.StylesListSection_Title);
        label.setEnabled(false);
    }

    /**
     * Clear and populate the inheritance container where the controls
     * are shown
     */
    private void createContent() {
        if (!isRefreshing()) {
            setRefreshing(true);
            trackerListener.refresh();
            elementAttributes = getElement().getStylesDescriptors();
            // Dispose the old widgets
            clearOldContent();
            GridLayout layout = new GridLayout(2, false);
            layout.marginWidth = 0;
            parent.setLayout(layout);
            printWindowTitle(parent);
            initStyleMaps();
            LinkedList<MStyle> styles = buildStylesGerarchy(getElement());
            // Printing the main attribute, opening the guard
            mainElementEvent = true;
            printElementAttribute(parent, getElement(), Messages.StylesSectionList_Element_Attributes);
            // Element printed, closing the guard
            mainElementEvent = false;
            printStyles(styles, parent);
            printDefaultValues(parent, DefaultValuesMap.getPropertiesByType(getElement()));
            parent.layout();
            setRefreshing(false);
        }
    }

    /**
     * Return a reference to the node father of all the styles
     * 
     * @param element
     * @return reference to the father of all the styles
     */
    private ANode getStylesRoot(APropertyNode element) {
        List<INode> children = element.getRoot().getChildren();
        Iterator<INode> it = children.iterator();
        ANode stylesClass = null;
        while (it.hasNext() && stylesClass == null) {
            INode childElement = it.next();
            if (childElement instanceof MStyles || childElement instanceof MStylesTemplate)
                stylesClass = (ANode) childElement;
            // The root is a subreport or a table, i need to move into an upper level
            if (childElement instanceof MPage) {
                children = childElement.getChildren();
                it = children.iterator();
            }
        }
        return stylesClass;
    }

    @Override
    public void dispose() {
        super.dispose();
        colorCache.dispose();
        updatePanelJob.cancel();
    }

    /**
     * Delete the old controls created for the tab
     */
    private void clearOldContent() {
        for (Control control : parent.getChildren()) {
            control.dispose();
        }
    }

    /**
     * Initialize the styles widget, create the control and set them
     */
    @Override
    public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
        super.createControls(parent, tabbedPropertySheetPage);
        createContent();
    }
}