info.vancauwenberge.designer.enhtrace.viewer.outline.page.DetailedPolicyFlowPage.java Source code

Java tutorial

Introduction

Here is the source code for info.vancauwenberge.designer.enhtrace.viewer.outline.page.DetailedPolicyFlowPage.java

Source

/*******************************************************************************
 * Copyright (c) 2014-2015 Stefaan Van Cauwenberge
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0 (the "License"). If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *      
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Initial Developer of the Original Code is
 * Stefaan Van Cauwenberge. Portions created by
 *  the Initial Developer are Copyright (C) 2007-2015 by
 * Stefaan Van Cauwenberge. All Rights Reserved.
 *
 * Contributor(s): none so far.
 *    Stefaan Van Cauwenberge: Initial API and implementation
 *******************************************************************************/
package info.vancauwenberge.designer.enhtrace.viewer.outline.page;

import info.vancauwenberge.designer.enhtrace.Activator;
import info.vancauwenberge.designer.enhtrace.action.OpenDetailAction;
import info.vancauwenberge.designer.enhtrace.api.ILogMessage;
import info.vancauwenberge.designer.enhtrace.api.ILogMessageProvider;
import info.vancauwenberge.designer.enhtrace.api.IPolicySetLogMessage;
import info.vancauwenberge.designer.enhtrace.api.IRootLogMessage.Status;
import info.vancauwenberge.designer.enhtrace.editor.input.StaticTraceEditorInput;
import info.vancauwenberge.designer.enhtrace.editor.input.StaticTraceEditorInput.IStaticInputListener;
import info.vancauwenberge.designer.enhtrace.editor.input.StaticTraceEditorInput.PolicySteps;
import info.vancauwenberge.designer.enhtrace.editors.DetailedTraceEditor;
import info.vancauwenberge.designer.enhtrace.model.logmessage.StatusLogMessage;
import info.vancauwenberge.designer.enhtrace.util.Util;

import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
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.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import com.novell.core.Core;

/*
 * The outline view of the event details is a paged view.
 * This is the policyFlow page showing the fishbone view
 */
public class DetailedPolicyFlowPage extends Page implements ISelectionChangedListener, IContentOutlinePage,
        MouseMoveListener, MouseListener, IMenuListener, IStaticInputListener {

    private static final RGB RGB_FILL_HAS_DATA = new RGB(255, 255, 125);
    private static final RGB RGB_FILL_HAS_FILTER_DATA = new RGB(109, 180, 213);
    private static final RGB RGB_FILL_HAS_NO_DATA = new RGB(255, 255, 255);
    private static final RGB RGB_BOUND_SELECTED = new RGB(0, 0, 255);
    private static final RGB RGB_BOUND_RIGHTSELECTED = new RGB(0, 0, 125);
    private static final RGB RGB_BOUND_UNSELECTED = new RGB(192, 192, 192);
    private static final RGB RGB_LABEL = new RGB(0, 0, 0);

    private static final Pattern applyingPolicyPattern = Pattern.compile("%14C.*%3C");
    private static final Pattern applyingPolicySetPattern = Pattern.compile("^Applying ");

    private class GotoLogmessageAction extends Action {
        private final ILogMessage messageToSelect;

        private GotoLogmessageAction(String text, ILogMessage messageToSelect) {
            super(text);
            this.messageToSelect = messageToSelect;
        }

        public void run() {
            details.setSelection(new IStructuredSelection() {

                @Override
                public boolean isEmpty() {
                    return false;
                }

                @Override
                public List<?> toList() {
                    return Arrays.asList(toArray());
                }

                @Override
                public Object[] toArray() {
                    return new ILogMessage[] { messageToSelect };
                }

                @Override
                public int size() {
                    return 1;
                }

                @Override
                public Iterator<?> iterator() {
                    return toList().iterator();
                }

                @Override
                public Object getFirstElement() {
                    return messageToSelect;
                }
            });
            details.getSite().getPage().activate(details);
        }

    }

    private static class PaintData {
        final int[] points;
        final Polygon polygon;
        final int maxX;
        final int minX;
        final int minY;
        final int maxY;
        final String label;
        final Image textImage;

        private PaintData(int[] points, String label, Image textImage) {
            this.label = label;
            this.textImage = textImage;
            this.points = points;
            int[] x = new int[points.length / 2];
            int[] y = new int[points.length / 2];
            int minX = Integer.MAX_VALUE;
            int maxX = Integer.MIN_VALUE;
            int minY = Integer.MAX_VALUE;
            int maxY = Integer.MIN_VALUE;
            //Convert the points to 2 ararys, x and ynew int[]{77,55,  77,73,  95,82,  113,73,  113,55,  95,64}
            for (int i = 0; i < points.length / 2; i++) {
                x[i] = points[i * 2];
                y[i] = points[i * 2 + 1];
                minX = Math.min(minX, x[i]);
                maxX = Math.max(maxX, x[i]);
                minY = Math.min(minY, y[i]);
                maxY = Math.max(maxY, y[i]);
            }
            this.minX = minX;
            this.maxX = maxX;
            this.minY = minY;
            this.maxY = maxY;
            this.polygon = new Polygon(x, y, x.length);
        }
    }

    static final Map<StaticTraceEditorInput.PolicySteps, PaintData> paintdataMap = new EnumMap<StaticTraceEditorInput.PolicySteps, DetailedPolicyFlowPage.PaintData>(
            StaticTraceEditorInput.PolicySteps.class);
    static {

        paintdataMap.put(StaticTraceEditorInput.PolicySteps.INPUT_TRANSFORM,
                new PaintData(new int[] { 77, 55, 77, 73, 95, 82, 113, 73, 113, 55, 95, 64 }, "Input",
                        Core.getImage("icons/policyflow/text_input.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.OUTPUT_TRANSFORM,
                new PaintData(new int[] { 117, 66, 117, 84, 135, 75, 153, 84, 153, 66, 135, 57 }, "Output",
                        Core.getImage("icons/policyflow/text_output.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_SCHEMA_MAP,
                new PaintData(new int[] { 24, 89, 24, 115, 108, 115, 108, 89 }, "Schema Mapping",
                        Core.getImage("icons/policyflow/text_schema.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_SCHEMA_MAP,
                new PaintData(new int[] { 109, 89, 109, 115, 193, 115, 193, 89 }, "Schema Mapping",
                        Core.getImage("icons/policyflow/text_schema.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_EVENT,
                new PaintData(new int[] { 48, 145, 48, 163, 71, 170, 94, 163, 94, 145, 71, 152 }, "Event",
                        Core.getImage("icons/policyflow/text_event.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_MATCHING,
                new PaintData(new int[] { 48, 222, 48, 240, 71, 247, 94, 240, 94, 222, 71, 229 }, "Matching",
                        Core.getImage("icons/policyflow/text_matching.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_CREATION,
                new PaintData(new int[] { 48, 246, 48, 264, 71, 271, 94, 264, 94, 246, 71, 253 }, "Creation",
                        Core.getImage("icons/policyflow/text_creation.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_PLACEMENT,
                new PaintData(new int[] { 48, 269, 48, 287, 71, 294, 94, 287, 94, 269, 71, 276 }, "Placement",
                        Core.getImage("icons/policyflow/text_placement.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_COMMAND,
                new PaintData(new int[] { 48, 299, 48, 318, 71, 324, 94, 317, 94, 299, 71, 306 }, "Command",
                        Core.getImage("icons/policyflow/text_command.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_EVENT,
                new PaintData(new int[] { 138, 319, 138, 337, 161, 330, 184, 337, 184, 319, 161, 312 }, "Event",
                        Core.getImage("icons/policyflow/text_event.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_MATCHING,
                new PaintData(new int[] { 138, 261, 138, 279, 161, 272, 184, 279, 184, 261, 161, 254 }, "Matching",
                        Core.getImage("icons/policyflow/text_matching.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_CREATION,
                new PaintData(new int[] { 138, 236, 138, 254, 161, 247, 184, 254, 184, 236, 161, 229 }, "Creation",
                        Core.getImage("icons/policyflow/text_creation.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_PLACEMENT,
                new PaintData(new int[] { 138, 211, 138, 229, 161, 222, 184, 229, 184, 211, 161, 204 }, "Placement",
                        Core.getImage("icons/policyflow/text_placement.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_COMMAND,
                new PaintData(new int[] { 138, 181, 138, 199, 161, 192, 184, 199, 184, 181, 161, 174 }, "Command",
                        Core.getImage("icons/policyflow/text_command.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_NOTIFY_FILTER,
                new PaintData(new int[] { 44, 334, 48, 354, 98, 354, 94, 334 }, "Notify",
                        Core.getImage("icons/policyflow/text_notify.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_NOTIFY_FILTER,
                new PaintData(new int[] { 134, 145, 138, 165, 188, 165, 183, 145 }, "Notify",
                        Core.getImage("icons/policyflow/text_notify.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_SYNC_FILTER,
                new PaintData(new int[] { 134, 341, 138, 361, 188, 361, 183, 341 }, "Sync",
                        Core.getImage("icons/policyflow/text_sync.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_SYNC_FILTER,
                new PaintData(new int[] { 44, 177, 48, 197, 98, 197, 93, 177 }, "Sync",
                        Core.getImage("icons/policyflow/text_sync.png")));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SHIM,
                new PaintData(new int[] { 88, 1, 89, 38, 138, 38, 138, 1 }, "App", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_ADD_PROCESSOR,
                new PaintData(new int[] { 71, 201, 59, 213, 71, 225, 83, 213 }, "Add?", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_ADD_PROCESSOR,
                new PaintData(new int[] { 161, 280, 149, 292, 161, 304, 173, 292 }, "Add?", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_ASS_PROCESSOR,
                new PaintData(new int[] { 59, 116, 59, 130, 83, 130, 83, 116 }, "Ass.", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_ASS_PROCESSOR,
                new PaintData(new int[] { 149, 116, 149, 130, 173, 130, 173, 116 }, "Ass.", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_RESET_INJECTION,
                new PaintData(new int[] { 5, 302, 5, 314, 26, 314, 32, 308, 26, 302 }, "Inject", null));

        paintdataMap.put(StaticTraceEditorInput.PolicySteps.PUB_STARTUP,
                new PaintData(new int[] { 26, 23, 26, 41, 72, 41, 72, 23 }, "Startup", null));
        paintdataMap.put(StaticTraceEditorInput.PolicySteps.SUB_SHUTDOWN,
                new PaintData(new int[] { 149, 23, 149, 41, 195, 41, 195, 23 }, "Shutdown", null));
    }

    private ScrolledComposite pageContent;
    private Canvas canvas;
    private DetailedTraceEditor details;
    private Image imagePageFlow;
    private PolicySteps selectedPolicySet;
    private PolicySteps rightClickSelectedPolicySet;
    private Font canvasFont;
    private Map<RGB, Color> colorCache = new HashMap<RGB, Color>();

    private List<StatusLogMessage> nonpolicyStatusses = new ArrayList<StatusLogMessage>();
    private Cursor cursorPointer;
    private MenuManager menuManager;
    private Image overlayRetry;
    private Image overlaySuccess;
    private Image overlayWarning;
    private Image overlayError;
    private Image overlayFatal;
    private StaticTraceEditorInput input;
    private Map<PolicySteps, Image> policy2ImageMap = new EnumMap<PolicySteps, Image>(PolicySteps.class);

    public DetailedPolicyFlowPage(DetailedTraceEditor details) {
        this.details = details;
        this.input = ((StaticTraceEditorInput) details.getEditorInput());

        input.addListener(this);
        details.addSelectionChangedListener(this);

        //TODO: somehow reuse the image for multiple detail views.
        ImageDescriptor imageDescr = Activator.getImageDescriptor("icons/page_flow_shell4.gif");
        this.imagePageFlow = imageDescr.createImage();

        imageDescr = Activator.getImageDescriptor("icons/overlayRetry.gif");
        this.overlayRetry = imageDescr.createImage();

        imageDescr = Activator.getImageDescriptor("icons/overlaySuccess.gif");
        this.overlaySuccess = imageDescr.createImage();

        imageDescr = Activator.getImageDescriptor("icons/overlayWarning.gif");
        this.overlayWarning = imageDescr.createImage();

        imageDescr = Activator.getImageDescriptor("icons/overlayError.gif");
        this.overlayError = imageDescr.createImage();

        imageDescr = Activator.getImageDescriptor("icons/overlayFatal.gif");
        this.overlayFatal = imageDescr.createImage();

        createOverlayMap();
    }

    public void createControl(Composite parent) {
        pageContent = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        pageContent.setExpandHorizontal(true);
        pageContent.setExpandVertical(false);
        pageContent.setContent(createContent());
        createMenu();
    }

    private void disposeColorCache() {
        for (Color colors : colorCache.values()) {
            colors.dispose();
        }
    }

    private Color getColor(RGB rgb) {
        Color color = colorCache.get(rgb);
        if (color == null) {
            color = new Color(canvas.getDisplay(), rgb);
            colorCache.put(rgb, color);
        }
        return color;
    }

    private void createMenu() {
        //Add a context menu extention point
        menuManager = new MenuManager();
        //allow additions => not for this menu. All is added on the fly.
        //menuManager.add ( new  Separator( IWorkbenchActionConstants.MB_ADDITIONS)) ; 
        menuManager.setRemoveAllWhenShown(true);

        //Control control = getControl();
        Menu menu = menuManager.createContextMenu(canvas);
        canvas.setMenu(menu);

        menuManager.addMenuListener(this);

        /*
        Control control = getControl();
            
        Menu menu = new Menu(canvas);
        canvas.setMenu(menu);
        MenuItem item = new MenuItem(menu, SWT.PUSH);
         item.setText("Popup");*/
    }

    private Control createContent() {
        // * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>,
        // * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>.

        this.canvas = new Canvas(pageContent, SWT.NO_MERGE_PAINTS | SWT.NO_REDRAW_RESIZE);

        ImageData imageData = imagePageFlow.getImageData();

        int shellWidth = imageData.width;
        int shellHeight = imageData.height;
        canvas.setBounds(0, 0, shellWidth, shellHeight);
        cursorPointer = new Cursor(canvas.getDisplay(), SWT.CURSOR_HAND);
        System.out.println("shellWidth:" + shellWidth + "; shellHeight" + shellHeight);
        Font f = PlatformUI.getWorkbench().getDisplay().getSystemFont();
        FontData fontdata = f.getFontData()[0];
        //Take the default system font, but a bit smaller
        this.canvasFont = new Font(canvas.getDisplay(), fontdata.getName(), fontdata.getHeight() - 4,
                fontdata.getStyle());

        canvas.setFont(canvasFont);

        //GC gc = new GC(canvas);

        canvas.addPaintListener(new PaintListener() {

            @Override
            public void paintControl(PaintEvent e) {
                e.gc.drawImage(imagePageFlow, 0, 0);
                e.gc.setLineCap(SWT.CAP_SQUARE);
                for (PolicySteps policySet : PolicySteps.values()) {
                    PaintData paintData = paintdataMap.get(policySet);
                    List<IPolicySetLogMessage> messageList = input.getPolicy2MessageMap().get(policySet);
                    //Fill with "having data colour
                    if (messageList != null) {
                        switch (policySet) {
                        case PUB_NOTIFY_FILTER:
                        case PUB_SYNC_FILTER:
                        case SUB_NOTIFY_FILTER:
                        case SUB_SYNC_FILTER:
                        case SUB_ADD_PROCESSOR:
                        case PUB_ADD_PROCESSOR:
                            e.gc.setBackground(getColor(RGB_FILL_HAS_FILTER_DATA));
                            break;
                        default:
                            e.gc.setBackground(getColor(RGB_FILL_HAS_DATA));
                            break;
                        }
                    } else
                        e.gc.setBackground(getColor(RGB_FILL_HAS_NO_DATA));
                    e.gc.fillPolygon(paintData.points);

                    if (selectedPolicySet == policySet) {
                        e.gc.setLineWidth(2);
                        e.gc.setForeground(getColor(RGB_BOUND_SELECTED));
                        e.gc.drawPolygon(paintData.points);//new int[]{77+1,55+1,  77+1,73,  95,82-1,  113,73-1,  113,55+1,  95,64+1});                   
                    } else if (rightClickSelectedPolicySet == policySet) {
                        e.gc.setLineWidth(2);
                        e.gc.setForeground(getColor(RGB_BOUND_RIGHTSELECTED));
                        e.gc.drawPolygon(paintData.points);//new int[]{77+1,55+1,  77+1,73,  95,82-1,  113,73-1,  113,55+1,  95,64+1});                   
                    } else {//UnSelected bounds
                        e.gc.setLineWidth(1);
                        e.gc.setForeground(getColor(RGB_BOUND_UNSELECTED));
                        e.gc.drawPolygon(paintData.points);
                    }

                    if (paintData.textImage != null) {
                        Rectangle strSize = paintData.textImage.getBounds();
                        e.gc.drawImage(paintData.textImage, (paintData.maxX + paintData.minX - strSize.width) / 2,
                                (paintData.maxY + paintData.minY - strSize.height) / 2);
                    } else
                    //Draw the label
                    if (paintData.label != null) {
                        e.gc.setForeground(getColor(RGB_LABEL));
                        Point strSize = e.gc.stringExtent(paintData.label);
                        e.gc.drawText(paintData.label, (paintData.maxX + paintData.minX - strSize.x) / 2,
                                (paintData.maxY + paintData.minY - strSize.y) / 2, true);
                    }
                    //Draw any overlay if the message has a status as a child
                    Image overlay = policy2ImageMap.get(policySet);
                    if (overlay != null) {
                        e.gc.drawImage(overlay, paintData.minX, paintData.minY);
                    }
                }
            }

        });

        canvas.addMouseMoveListener(this);
        canvas.addMouseListener(this);

        return canvas;

    }

    public void setFocus() {
        pageContent.setFocus();
    }

    @Override
    public void mouseMove(MouseEvent e) {
        if (isStatusOverlayPosition(e.x, e.y)) {
            canvas.setCursor(cursorPointer);
        } else {
            PolicySteps aPolicy = getPolicySets(e.x, e.y);
            if (aPolicy != null) {
                canvas.setCursor(cursorPointer);
            } else {
                canvas.setCursor(null);
            }
        }
    }

    public Control getControl() {
        return pageContent;
    }

    @Override
    public ISelection getSelection() {
        return null;
    }

    private IStructuredSelection createSelection(final ILogMessage statusMessage) {
        return new IStructuredSelection() {

            @Override
            public boolean isEmpty() {
                return false;
            }

            @Override
            public List<?> toList() {
                List<ILogMessage> result = new ArrayList<ILogMessage>(1);
                result.add(statusMessage);
                return result;
            }

            @Override
            public Object[] toArray() {
                return new Object[] { statusMessage };
            }

            @Override
            public int size() {
                return 1;
            }

            @Override
            public Iterator<?> iterator() {
                return toList().iterator();
            }

            @Override
            public Object getFirstElement() {
                return statusMessage;
            }
        };
    }

    private IStructuredSelection createSelection(PolicySteps PolicySteps) {
        if (PolicySteps != null) {
            final List<IPolicySetLogMessage> result = input.getPolicy2MessageMap().get(PolicySteps);
            System.out.println(this.getClass().getName() + ".createSelection():" + result);
            if (result != null && result.size() > 0)
                return new IStructuredSelection() {

                    @Override
                    public boolean isEmpty() {
                        return false;
                    }

                    @Override
                    public List<?> toList() {
                        return result;
                    }

                    @Override
                    public Object[] toArray() {
                        return result.toArray();
                    }

                    @Override
                    public int size() {
                        return result.size();
                    }

                    @Override
                    public Iterator<?> iterator() {
                        return result.iterator();
                    }

                    @Override
                    public Object getFirstElement() {
                        return result.get(0);
                    }
                };
        }
        System.out.println(this.getClass().getName() + ".createSelection(): null");
        return null;
    }

    /**
     * Redraw the policyflow with the new selection
     * @param newSelected
     */
    private void redrawPolicyFlow(PolicySteps oldSelection, PolicySteps newSelected) {
        if (newSelected != oldSelection) {
            if (newSelected != null) {
                PaintData paintData = paintdataMap.get(newSelected);
                canvas.redraw(paintData.minX - 1, paintData.minY - 1, paintData.maxX + 1, paintData.maxY + 1,
                        false);
            }

            if (oldSelection != null) {
                PaintData paintData = paintdataMap.get(oldSelection);
                canvas.redraw(paintData.minX - 1, paintData.minY - 1, paintData.maxX + 1, paintData.maxY + 1,
                        false);
            }
        }
    }

    public void dispose() {
        canvas.dispose();
        pageContent.dispose();
        imagePageFlow.dispose();
        canvasFont.dispose();
        disposeColorCache();
        menuManager.dispose();
        cursorPointer.dispose();
        overlayError.dispose();
        overlayFatal.dispose();
        overlayRetry.dispose();
        overlaySuccess.dispose();
        overlayWarning.dispose();
        super.dispose();
        super.dispose();
    }

    @Override
    public void mouseDoubleClick(MouseEvent e) {
        mouseDown(e);
    }

    private boolean isStatusOverlayPosition(int x, int y) {
        for (PolicySteps policySet : PolicySteps.values()) {
            Image overlay = policy2ImageMap.get(policySet);
            if (overlay != null) {
                Rectangle rect = overlay.getBounds();
                PaintData paintData = paintdataMap.get(policySet);
                rect.x = paintData.minX;
                rect.y = paintData.minY;
                if (rect.contains(x, y)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Get the worst case status message for the policy set under the given x-y coordinates
     * @param x
     * @param y
     * @return
     */
    private StatusLogMessage getWorstStatusMessage(int x, int y) {
        for (PolicySteps policySet : PolicySteps.values()) {
            Image overlay = policy2ImageMap.get(policySet);
            if (overlay != null) {
                PaintData paintData = paintdataMap.get(policySet);
                Rectangle rect = overlay.getBounds();
                rect.x = paintData.minX;
                rect.y = paintData.minY;
                if (rect.contains(x, y)) {
                    Status worstStatus = Status.UNKNOWN;
                    StatusLogMessage worstStatusMessage = null;

                    List<IPolicySetLogMessage> messageList = input.getPolicy2MessageMap().get(policySet);

                    for (IPolicySetLogMessage iPolicySetLogMessage : messageList) {
                        List<StatusLogMessage> allStatusses = input.getPolicy2StatusMap().get(iPolicySetLogMessage);
                        if (allStatusses != null) {
                            for (StatusLogMessage statusLogMessage : allStatusses) {
                                if (worstStatus.getLevel() < statusLogMessage.getStatus().getLevel())
                                    worstStatusMessage = statusLogMessage;
                                worstStatus = statusLogMessage.getStatus();
                            }
                        }
                    }
                    return worstStatusMessage;
                }
            }
        }
        return null;
    }

    /**
     * Get the policyset (if any) at the given coordinates
     * @param x
     * @param y
     * @return
     */
    private PolicySteps getPolicySets(int x, int y) {
        for (PolicySteps policySet : PolicySteps.values()) {
            PaintData paintData = paintdataMap.get(policySet);
            if (paintData.polygon.contains(x, y)) {
                return policySet;
            }
        }
        return null;
    }

    @Override
    public void mouseDown(MouseEvent e) {
        switch (e.button) {
        case 1:
            redrawPolicyFlow(rightClickSelectedPolicySet, null);
            rightClickSelectedPolicySet = null;

            final StatusLogMessage statusMessage = getWorstStatusMessage(e.x, e.y);
            if (statusMessage != null) {
                System.out.println("mouseDown(): Setting selection to " + statusMessage);
                details.setSelection(createSelection(statusMessage));
            } else {
                PolicySteps aPolicy = getPolicySets(e.x, e.y);
                System.out.println("mouseDown(): Setting selection to " + aPolicy);
                details.setSelection((IStructuredSelection) createSelection(aPolicy));
            }
            details.getSite().getPage().activate(details);
            break;
        case 3:
            PolicySteps oldRightClickSelection = rightClickSelectedPolicySet;
            rightClickSelectedPolicySet = getPolicySets(e.x, e.y);
            redrawPolicyFlow(oldRightClickSelection, rightClickSelectedPolicySet);
            break;
        default:
            break;
        }
    }

    @Override
    public void mouseUp(MouseEvent e) {
        //Nothing to do
    }

    @Override
    public void menuAboutToShow(IMenuManager manager) {
        System.out.println("about to show. selectedPolicySet=" + rightClickSelectedPolicySet);
        if (rightClickSelectedPolicySet != null) {
            List<IPolicySetLogMessage> rootMessages = input.getPolicy2MessageMap().get(rightClickSelectedPolicySet);
            if (rootMessages != null && rootMessages.size() > 0) {
                if (rootMessages.size() > 1) {
                    for (IPolicySetLogMessage iPolicySetLogMessage : rootMessages) {
                        String label = null;
                        if (iPolicySetLogMessage.getPolicySet().isSubflowRoot()) {
                            //If this is the root, the label should come from itself
                            label = iPolicySetLogMessage.getMessage();
                        } else
                            //If this is not the root, the parent should have the label
                            label = iPolicySetLogMessage.getParent().getMessage();
                        //TODO: make this more generic.
                        //Potentially more strings can be removed.
                        label = label.replaceAll("^Subscriber processing ", "");
                        label = label.replaceAll("^Publisher processing ", "");
                        MenuManager subMenu = new MenuManager(Util.elipsisLabelMiddle(label, Util.MAX_LABEL_SIZE),
                                null);
                        manager.add(subMenu);

                        createPolicysetMenu(iPolicySetLogMessage, subMenu);

                    }
                } else {
                    //Do not create a submenu if only one policymessage in the list
                    createPolicysetMenu(rootMessages.get(0), menuManager);
                }
            }

        } else {
            if (nonpolicyStatusses != null && nonpolicyStatusses.size() > 0)
                createStatusSubmenu(manager, nonpolicyStatusses);
        }
    }

    private void createPolicysetMenu(final IPolicySetLogMessage iPolicySetLogMessage, MenuManager subMenu) {
        createPolicysetSubmenu(subMenu, iPolicySetLogMessage);

        List<StatusLogMessage> statusses = input.getPolicy2StatusMap().get(iPolicySetLogMessage);
        if (statusses != null && statusses.size() > 0) {
            createStatusSubmenu(subMenu, statusses);
        }
        List<ILogMessage> traces = input.getPolicy2TraceMap().get(iPolicySetLogMessage);
        if (traces != null && traces.size() > 0)
            createTracesSubmenu(subMenu, traces);

        if (iPolicySetLogMessage.getPolicySet().isSubflowRoot()) {

            subMenu.add(new OpenDetailAction(new IStructuredSelection() {

                @Override
                public boolean isEmpty() {
                    return false;
                }

                @Override
                public List<?> toList() {
                    return Arrays.asList(toArray());
                }

                @Override
                public Object[] toArray() {
                    return new Object[] { iPolicySetLogMessage };
                }

                @Override
                public int size() {
                    return 1;
                }

                @Override
                public Iterator<?> iterator() {
                    return toList().iterator();
                }

                @Override
                public Object getFirstElement() {
                    return iPolicySetLogMessage;
                }
            }, details));
        }
    }

    private void createTracesSubmenu(IMenuManager manager, List<ILogMessage> traces) {
        MenuManager subMenu = new MenuManager("Trace", null);
        for (final ILogMessage iLogMessage : traces) {
            subMenu.add(new GotoLogmessageAction(
                    Util.elipsisLabelEnd(iLogMessage.getMessage(), Util.MAX_LABEL_SIZE), iLogMessage));
        }
        manager.add(subMenu);
    }

    private void createPolicysetSubmenu(IMenuManager manager, IPolicySetLogMessage iPolicySetLogMessage) {
        if (iPolicySetLogMessage.hasChildren()) {
            List<ILogMessage> children = iPolicySetLogMessage.getChildren();
            MenuManager subMenu = null;
            if (iPolicySetLogMessage.getPolicySet().isSubflowRoot()) {
                //Only list the policySets
                subMenu = new MenuManager("Policy Set", null);
                for (final ILogMessage iLogMessage : children) {
                    if (iLogMessage instanceof IPolicySetLogMessage) {
                        String message = iLogMessage.getMessage();
                        /*
                        Matcher matcher = applyingPolicySetPattern.matcher(message);
                            
                        if (matcher.find()){
                           message = message.substring(matcher.end());
                        }*/
                        subMenu.add(new GotoLogmessageAction(Util.elipsisLabelEnd(message, Util.MAX_LABEL_SIZE),
                                iLogMessage));
                    }
                }

            } else {
                subMenu = new MenuManager("Policy", null);
                for (final ILogMessage iLogMessage : children) {

                    if (iLogMessage.getMessage().startsWith("Applying policy:")) {
                        //We need to create a submenu
                        String message = iLogMessage.getMessage();
                        Matcher matcher = applyingPolicyPattern.matcher(message);

                        if (matcher.find()) {
                            message = message.substring(matcher.start() + 4, matcher.end() - 3);
                        }
                        subMenu.add(new GotoLogmessageAction(Util.elipsisLabelEnd(message, Util.MAX_LABEL_SIZE),
                                iLogMessage));
                    }
                }
            }
            if (!subMenu.isEmpty())
                manager.add(subMenu);
        }
    }

    private void createStatusSubmenu(IMenuManager manager, List<StatusLogMessage> statusses) {
        MenuManager subMenu = new MenuManager("Status", null);
        for (final StatusLogMessage statusLogMessage : statusses) {
            StringBuilder sbLabel = new StringBuilder();
            sbLabel.append(statusLogMessage.getStatus().geLabel());
            String message = statusLogMessage.getStatusMessage();
            if (message != null) {
                sbLabel.append(": ");
                sbLabel.append(message);
            }
            subMenu.add(new GotoLogmessageAction(Util.elipsisLabelEnd(sbLabel.toString(), Util.MAX_LABEL_SIZE),
                    statusLogMessage));
        }
        manager.add(subMenu);
    }

    /*
    private void buildNonpolicyStatusList(ILogMessage root) {
       //No need to analyze if this message is a policy root
       Collection<List<IPolicySetLogMessage>> valueList = policy2MessageMap.values();
       //TODO: buggy but we no longer have statusses without a parent policy....
       for (List<IPolicySetLogMessage> list : valueList) {
     if (list.contains(root))
        return;
     if (root instanceof StatusLogMessage)
        nonpolicyStatusses.add((StatusLogMessage)root);
     if (root.hasChildren()){
        List<ILogMessage> children = root.getChildren();
        for (ILogMessage iLogMessage : children) {
           buildNonpolicyStatusList(iLogMessage);
        }
     }
         
       }
    }*/

    private Image getOverlayFor(Status worstStatus) {
        switch (worstStatus) {
        case WARNING:
            return overlayWarning;
        case SUCCESS:
            return overlaySuccess;
        case RETRY:
            return overlayRetry;
        case ERROR:
            return overlayError;
        case FATAL:
            return overlayFatal;
        default:
            return null;
        }
    }

    private void createOverlayMap() {
        //Overlays are again per policy set, based on the statusses found before
        Set<StaticTraceEditorInput.PolicySteps> keys = input.getPolicy2MessageMap().keySet();
        for (StaticTraceEditorInput.PolicySteps policySets : keys) {
            List<IPolicySetLogMessage> messageList = input.getPolicy2MessageMap().get(policySets);
            Status worstStatus = Status.UNKNOWN;
            for (IPolicySetLogMessage iPolicySetLogMessage : messageList) {
                List<StatusLogMessage> allStatusses = input.getPolicy2StatusMap().get(iPolicySetLogMessage);
                if (allStatusses != null)
                    worstStatus = getWorstStatus(worstStatus, allStatusses);
            }
            Image overlay = getOverlayFor(worstStatus);
            if (overlay != null) {
                policy2ImageMap.put(policySets, overlay);
            }
        }
    }

    private Status getWorstStatus(Status currentWorstStatus, List<StatusLogMessage> allStatusses) {
        for (StatusLogMessage statusLogMessage : allStatusses) {
            if (currentWorstStatus.getLevel() < statusLogMessage.getStatus().getLevel())
                currentWorstStatus = statusLogMessage.getStatus();
        }
        return currentWorstStatus;
    }

    public void refresh() {
        createOverlayMap();
        if (canvas != null)
            canvas.redraw();
    }

    @Override
    public void notifyRootChanged(ILogMessage newValue, ILogMessage oldValue) {
        createOverlayMap();
        canvas.redraw();
    }

    /**
     * The selection in the editor changed.
     */
    @Override
    public void selectionChanged(SelectionChangedEvent event) {
        //Remove any right click selection when we are receiving a new selection
        rightClickSelectedPolicySet = null;
        redrawPolicyFlow(rightClickSelectedPolicySet, null);

        //Now get the actual selection (if any)
        ISelection selection = event.getSelection();
        if (selection == null) {
            return;
        }

        System.out.println(this.getClass().getName() + ".selectionChanged() to " + selection);
        if (selection instanceof IStructuredSelection) {
            Object selectedObject = ((IStructuredSelection) selection).getFirstElement();
            System.out.println(this.getClass().getName() + ".selectionChanged() to " + selectedObject);
            if (selectedObject == null) {
                redrawPolicyFlow(selectedPolicySet, null);
                selectedPolicySet = null;
                return;
            }

            if (selectedObject instanceof ILogMessageProvider) {
                ILogMessage message = ((ILogMessageProvider) selectedObject).getLogMessage();
                while (true) {
                    if (message instanceof IPolicySetLogMessage) {
                        Set<StaticTraceEditorInput.PolicySteps> keys = input.getPolicy2MessageMap().keySet();
                        for (StaticTraceEditorInput.PolicySteps policySets : keys) {
                            List<IPolicySetLogMessage> listOfPolicies = input.getPolicy2MessageMap()
                                    .get(policySets);
                            if (listOfPolicies.contains(message)) {
                                redrawPolicyFlow(selectedPolicySet, policySets);
                                //Update the selection
                                selectedPolicySet = policySets;
                                return;
                            }
                        }
                    }
                    message = message.getParent();
                    if (message == null) {
                        redrawPolicyFlow(selectedPolicySet, null);
                        selectedPolicySet = null;
                        return;
                    }
                }
            }
        }
    }

    @Override
    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        //We are not a selection provider....
    }

    @Override
    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        //We are not a selection provider....
    }

    @Override
    public void setSelection(ISelection selection) {
        //We are not a selection provider....
    }

}