com.vectrace.MercurialEclipse.history.GraphLogTableViewer.java Source code

Java tutorial

Introduction

Here is the source code for com.vectrace.MercurialEclipse.history.GraphLogTableViewer.java

Source

/*******************************************************************************
 * Copyright (c) 2007-2008 VecTrace (Zingo Andersen) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Andrei Loskutov - bug fixes
 *******************************************************************************/
package com.vectrace.MercurialEclipse.history;

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

import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.LineAttributes;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;

import com.aragost.javahg.Phase;
import com.vectrace.MercurialEclipse.commands.HgBisectClient.Status;
import com.vectrace.MercurialEclipse.history.GraphLayout.GraphRow;
import com.vectrace.MercurialEclipse.model.Signature;
import com.vectrace.MercurialEclipse.preferences.MercurialPreferenceConstants;
import com.vectrace.MercurialEclipse.team.MercurialUtilities;

public class GraphLogTableViewer extends TableViewer {

    /**
     * Number of colors. See {@link #colors}.
     */
    public static final int NUM_COLORS = 11;

    private static final int COL_WIDTH_PIXELS = 12;

    private static int DOT_RADIUS_PIXELS = 3;

    /**
     * @see #NUM_COLORS
     */
    private final List<Color> colors = new ArrayList<Color>();
    private final MercurialHistoryPage mhp;
    private final Color mergeBack;
    private final Color mergeFore;

    public GraphLogTableViewer(Composite parent, int style, MercurialHistoryPage mercurialHistoryPage) {
        super(parent, style);
        this.mhp = mercurialHistoryPage;
        getTable().addListener(SWT.PaintItem, new Listener() {
            public void handleEvent(final Event event) {
                paint(event);
            }
        });

        Display display = parent.getDisplay();
        colors.add(display.getSystemColor(SWT.COLOR_DARK_RED));
        colors.add(display.getSystemColor(SWT.COLOR_GREEN));
        colors.add(display.getSystemColor(SWT.COLOR_BLUE));
        colors.add(display.getSystemColor(SWT.COLOR_RED));
        colors.add(display.getSystemColor(SWT.COLOR_MAGENTA));
        colors.add(display.getSystemColor(SWT.COLOR_GRAY));
        colors.add(display.getSystemColor(SWT.COLOR_DARK_YELLOW));
        colors.add(display.getSystemColor(SWT.COLOR_DARK_MAGENTA));
        colors.add(display.getSystemColor(SWT.COLOR_DARK_CYAN));
        colors.add(display.getSystemColor(SWT.COLOR_DARK_GRAY));
        colors.add(display.getSystemColor(SWT.COLOR_DARK_GREEN));

        // TODO add pref store listener
        mergeBack = MercurialUtilities
                .getColorPreference(MercurialPreferenceConstants.PREF_HISTORY_MERGE_CHANGESET_BACKGROUND);
        mergeFore = MercurialUtilities
                .getColorPreference(MercurialPreferenceConstants.PREF_HISTORY_MERGE_CHANGESET_FOREGROUND);
    }

    protected void paint(Event event) {
        TableItem tableItem = (TableItem) event.item;
        if (event.index != 0) {
            return;
        }

        MercurialRevision rev = (MercurialRevision) tableItem.getData();
        MercurialHistory data = mhp.getMercurialHistory();

        paintRow(event, rev.getGraphRow());

        final Table table = tableItem.getParent();
        int from = rev.getRevision() - 1;
        int lastReqVersion = data.getLastRequestedVersion();
        if (from != lastReqVersion && from >= 0 && data.getLastVersion() > 0) {
            if (tableItem.equals(table.getItems()[table.getItemCount() - 1])) {
                MercurialHistoryPage.LoadMercurialHistoryJob refreshJob = mhp.new LoadMercurialHistoryJob(from);
                refreshJob.addJobChangeListener(new JobChangeAdapter() {
                    @Override
                    public void done(IJobChangeEvent event1) {
                        Display.getDefault().asyncExec(new Runnable() {
                            public void run() {
                                if (table.isDisposed()) {
                                    return;
                                }
                                table.redraw();
                                table.update();
                            }
                        });
                    }
                });
                mhp.scheduleInPage(refreshJob);
            }
        }

        // validate signed changesets
        Signature sig = rev.getSignature();
        if (sig != null) {
            if (sig.validate()) {
                tableItem.setBackground(colors.get(0));
            } else {
                tableItem.setBackground(colors.get(2));
            }
        }

        if (mhp.getCurrentWorkdirChangeset() != null) {
            if (rev.getRevision() == mhp.getCurrentWorkdirChangeset().getIndex()) {
                tableItem.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
            }
        }

        // bisect colorization
        Status bisectStatus = rev.getBisectStatus();
        if (bisectStatus != null) {
            if (bisectStatus == Status.BAD) {
                tableItem.setBackground(colors.get(10));
            } else {
                tableItem.setBackground(colors.get(9));
            }
        } else {
            if (rev.getChangeSet().isMerge()) {
                // Don't set font here -> UI freezes on windows
                tableItem.setBackground(mergeBack);
                tableItem.setForeground(mergeFore);

            }
        }
    }

    private void paintRow(Event event, GraphRow curRow) {
        if (curRow == null) {
            return;
        }

        GraphRow prevRow = curRow.getPrevious();

        if (prevRow != null) {
            for (int i = 0, n = prevRow.numColumns(); i < n; i++) {
                int numParents = prevRow.numParents(i);

                for (int p = 0; p < numParents; p++) {
                    int color = p == 0 ? prevRow.getColor(i) : prevRow.getParentColor(i, p);
                    paintTop(event, i, prevRow.getParentIndex(i, p), getColor(color));
                }
            }
        }

        for (int i = 0, n = curRow.numColumns(); i < n; i++) {
            int numParents = curRow.numParents(i);

            for (int p = 0; p < numParents; p++) {
                int color = p == 0 ? curRow.getColor(i) : curRow.getParentColor(i, p);
                paintBottom(event, i, curRow.getParentIndex(i, p), getColor(color));
            }
        }

        int dot = curRow.getDot();

        paintDot(event, dot, curRow.getPhase(dot));
    }

    private Color getColor(int color) {
        return colors.get(color % colors.size());
    }

    /**
     * Paint the top part of the cell, between the current change set and it's children
     */
    private static void paintTop(Event event, int fromCol, int toCol, Color color) {
        GC g = event.gc;
        g.setLineAttributes(new LineAttributes(2));
        g.setLineStyle(SWT.LINE_SOLID);
        g.setForeground(color);

        int endY = event.y + event.height / 2;
        int toX = getX(event, toCol);

        g.drawLine(toX, event.y, toX, endY);
    }

    /**
     * Paint the bottom part of the cell, between the current change set and it's parents
     */
    private static void paintBottom(Event event, int fromCol, int toCol, Color color) {
        GC g = event.gc;
        g.setLineAttributes(new LineAttributes(2));
        g.setLineStyle(SWT.LINE_SOLID);
        g.setForeground(color);

        int fromX = getX(event, fromCol);
        int toX = getX(event, toCol);
        int endY = event.y + event.height;

        if (fromCol == toCol) {
            g.drawLine(fromX, event.y + event.height / 2, fromX, endY);
        } else {
            int horStartX = getX(event, toCol + (fromCol > toCol ? 1 : -1));
            // horizontal line
            if (Math.abs(toCol - fromCol) > 1) {
                g.drawLine(fromX, event.y + event.height / 2, horStartX, event.y + event.height / 2);
            }

            // diagonal line
            g.drawLine(horStartX, event.y + event.height / 2, toX, event.y + event.height);
        }
    }

    private static void paintDot(Event event, int dot, Phase phase) {
        event.gc.setLineWidth(2);

        int x = getX(event, dot);

        switch (phase) {
        case PUBLIC:
            event.gc.setBackground(event.display.getSystemColor(SWT.COLOR_BLACK));
            event.gc.fillOval(x - DOT_RADIUS_PIXELS, // x
                    event.y + (event.height / 2) - DOT_RADIUS_PIXELS, // y
                    DOT_RADIUS_PIXELS * 2, // width
                    DOT_RADIUS_PIXELS * 2); // height
            break;
        case DRAFT:
            event.gc.setBackground(event.display.getSystemColor(SWT.COLOR_WHITE));
            event.gc.setForeground(event.display.getSystemColor(SWT.COLOR_BLACK));
            event.gc.fillRectangle(x - DOT_RADIUS_PIXELS, // x
                    event.y + (event.height / 2) - DOT_RADIUS_PIXELS, // y
                    DOT_RADIUS_PIXELS * 2, // width
                    DOT_RADIUS_PIXELS * 2); // height
            event.gc.drawRectangle(x - DOT_RADIUS_PIXELS, // x
                    event.y + (event.height / 2) - DOT_RADIUS_PIXELS, // y
                    DOT_RADIUS_PIXELS * 2, // width
                    DOT_RADIUS_PIXELS * 2); // height
            break;
        case SECRET:
            event.gc.setBackground(event.display.getSystemColor(SWT.COLOR_WHITE));
            event.gc.setForeground(event.display.getSystemColor(SWT.COLOR_BLACK));
            event.gc.fillPolygon(new int[] { //
                    x, event.y + (event.height / 2) - DOT_RADIUS_PIXELS, //
                    x + DOT_RADIUS_PIXELS, event.y + (event.height / 2) + DOT_RADIUS_PIXELS, //
                    x - DOT_RADIUS_PIXELS, event.y + (event.height / 2) + DOT_RADIUS_PIXELS,//
            });
            event.gc.drawPolygon(new int[] { //
                    x, event.y + (event.height / 2) - DOT_RADIUS_PIXELS, //
                    x + DOT_RADIUS_PIXELS, event.y + (event.height / 2) + DOT_RADIUS_PIXELS, //
                    x - DOT_RADIUS_PIXELS, event.y + (event.height / 2) + DOT_RADIUS_PIXELS,//
            });
            break;
        }
    }

    /**
     * @return The x coordinate of the centre of the column
     */
    private static int getX(Event event, int col) {
        return event.x + (COL_WIDTH_PIXELS * col) + 5;
    }
}