/******************************************************************************* * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2011, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>* * 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 *******************************************************************************/ package org.eclipse.egit.ui.internal.history; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIPreferences; import org.eclipse.egit.ui.internal.history.SWTCommitList.SWTLane; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revplot.AbstractPlotRenderer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.TableItem; class SWTPlotRenderer extends AbstractPlotRenderer<SWTLane, Color> { private static final RGB OUTER_HEAD = new RGB(0, 128, 0); private static final RGB INNER_HEAD = new RGB(188, 220, 188); private static final RGB OUTER_TAG = new RGB(121, 120, 13); private static final RGB INNER_TAG = new RGB(249, 255, 199); private static final RGB OUTER_ANNOTATED = new RGB(104, 78, 0); private static final RGB INNER_ANNOTATED = new RGB(255, 239, 192); private static final RGB OUTER_REMOTE = new RGB(80, 80, 80); private static final RGB INNER_REMOTE = new RGB(225, 225, 225); private static final RGB OUTER_OTHER = new RGB(30, 30, 30); private static final RGB INNER_OTHER = new RGB(250, 250, 250); private static final int MAX_LABEL_LENGTH = 18; private static final String ELLIPSIS = "\u2026"; // ellipsis "..." (in UTF-8) //$NON-NLS-1$ private final Color sys_black; private final Color sys_gray; private final Color sys_white; private final Color commitDotFill; private final Color commitDotOutline; /** * Map from ref name to its label coordinates */ private final Map<String, Point> labelCoordinates = new HashMap<>(); /** * Set of ref names that are shown as an ellipsis */ private final Set<String> ellipsisTags = new HashSet<>(); private int textHeight; private final ResourceManager resources; GC g; int cellX; int cellY; Color cellFG; Color cellBG; private Ref headRef; /** * Number of tags of the current commit being rendered. Reset after each * commit. */ private int tagCount = 0; SWTPlotRenderer(final Display d, final ResourceManager resources) { this.resources = resources; sys_black = d.getSystemColor(SWT.COLOR_BLACK); sys_gray = d.getSystemColor(SWT.COLOR_GRAY); sys_white = d.getSystemColor(SWT.COLOR_WHITE); commitDotFill = resources.createColor(new RGB(220, 220, 220)); commitDotOutline = resources.createColor(new RGB(110, 110, 110)); } void paint(final Event event, Ref actHeadRef) { g = event.gc; this.headRef = actHeadRef; cellX = event.x; cellY = event.y; cellFG = g.getForeground(); cellBG = g.getBackground(); if (textHeight == 0) textHeight = g.stringExtent("/").y; //$NON-NLS-1$ final TableItem ti = (TableItem) event.item; SWTCommit commit = (SWTCommit) ti.getData(); try { commit.parseBody(); } catch (IOException e) { Activator.error("Error parsing body", e); //$NON-NLS-1$ return; } paintCommit(commit , event.height); } @Override protected void drawLine(final Color color, final int x1, final int y1, final int x2, final int y2, final int width) { g.setForeground(color); g.setLineWidth(width); g.drawLine(cellX + x1, cellY + y1, cellX + x2, cellY + y2); } protected void drawDot(final Color outline, final Color fill, final int x, final int y, final int w, final int h) { int dotX = cellX + x + 2; int dotY = cellY + y + 1; int dotW = w - 2; int dotH = h - 2; g.setBackground(fill); g.fillOval(dotX, dotY, dotW, dotH); g.setForeground(outline); g.setLineWidth(2); g.drawOval(dotX, dotY, dotW, dotH); } @Override protected void drawCommitDot(final int x, final int y, final int w, final int h) { drawDot(commitDotOutline, commitDotFill, x, y, w, h); } @Override protected void drawBoundaryDot(final int x, final int y, final int w, final int h) { drawDot(sys_gray, sys_white, x, y, w, h); } @Override protected void drawText(final String msg, final int x, final int y) { final Point textsz = g.textExtent(msg); final int texty = (y - textsz.y) / 2; g.setForeground(cellFG); g.setBackground(cellBG); g.drawString(msg, cellX + x, cellY + texty, true); tagCount = 0; } @Override protected int drawLabel(int x, int y, Ref ref) { String txt; String name = ref.getName(); boolean tag = false; boolean branch = false; RGB labelOuter; RGB labelInner; if (name.startsWith(Constants.R_HEADS)) { branch = true; labelOuter = OUTER_HEAD; labelInner = INNER_HEAD; txt = name.substring(Constants.R_HEADS.length()); } else if (name.startsWith(Constants.R_REMOTES)) { branch = true; labelOuter = OUTER_REMOTE; labelInner = INNER_REMOTE; txt = name.substring(Constants.R_REMOTES.length()); } else if (name.startsWith(Constants.R_TAGS)) { tagCount++; tag = true; if (ref.getPeeledObjectId() != null) { labelOuter = OUTER_ANNOTATED; labelInner = INNER_ANNOTATED; } else { labelOuter = OUTER_TAG; labelInner = INNER_TAG; } int maxNumberOfTags = 1; if (tagCount == maxNumberOfTags) { txt = name.substring(Constants.R_TAGS.length()); } else if (tagCount == maxNumberOfTags + 1) { txt = ELLIPSIS; ellipsisTags.add(name); } else { // Don't draw additional tags, they are shown when hovering the // ellipsis return 0; } } else { labelOuter = OUTER_OTHER; labelInner = INNER_OTHER; if (name.startsWith(Constants.R_REFS)) txt = name.substring(Constants.R_REFS.length()); else txt = name; // HEAD and such } int maxLength; if (tag) maxLength = Activator.getDefault().getPreferenceStore() .getInt(UIPreferences.HISTORY_MAX_TAG_LENGTH); else if (branch) maxLength = Activator.getDefault().getPreferenceStore() .getInt(UIPreferences.HISTORY_MAX_BRANCH_LENGTH); else maxLength = MAX_LABEL_LENGTH; if (txt.length() > maxLength) { // Account for the ellipsis length int textLength = maxLength - 3; if (Activator.getDefault().getPreferenceStore() .getBoolean(UIPreferences.HISTORY_CUT_AT_START)) txt = ELLIPSIS + txt.substring(txt.length() - textLength); else txt = txt.substring(0, textLength) + ELLIPSIS; } // highlight checked out branch Font oldFont = g.getFont(); boolean isHead = isHead(name); if (isHead) g.setFont(CommitGraphTable.highlightFont()); Point textsz = g.stringExtent(txt); int arc = textsz.y / 2; final int texty = (y * 2 - textsz.y) / 2; final int outerWidth = textsz.x + 7; // Draw backgrounds g.setLineWidth(1); g.setBackground(sys_white); g.fillRoundRectangle(cellX + x + 1, cellY + texty, textsz.x + 6, textsz.y + 1, arc, arc); g.setBackground(resources.createColor(labelInner)); g.fillRoundRectangle(cellX + x + 2, cellY + texty + 1, textsz.x + 4, textsz.y - 2, arc - 1, arc - 1); g.setForeground(resources.createColor(labelOuter)); g.drawRoundRectangle(cellX + x, cellY + texty - 1, outerWidth, textsz.y + 1, arc, arc); g.setForeground(sys_black); // Draw text g.drawString(txt, cellX + x + 4, cellY + texty, true); if (isHead) g.setFont(oldFont); labelCoordinates.put(name, new Point(x, x + outerWidth)); return 10 + textsz.x; } private boolean isHead(String name) { boolean isHead = false; if (headRef != null) { String headRefName = headRef.getLeaf().getName(); if (name.equals(headRefName)) isHead = true; } return isHead; } @Override protected Color laneColor(final SWTLane myLane) { return myLane != null ? myLane.color : sys_black; } /** * Obtain the horizontal span of {@link Ref} label in pixels * * For example, let's assume the SWTCommit has two {@link Ref}s (see * {@link SWTCommit#getRef(int)}, which are rendered as two labels. The * first label may span from 15 to 54 pixels in x direction, while the * second one may span from 58 to 76 pixels. * * This can be used to determine if the mouse is positioned over a label. * * @param ref * @return a Point where x and y designate the start and end x position of * the label */ Point getRefHSpan(Ref ref) { return labelCoordinates.get(ref.getName()); } boolean isShownAsEllipsis(Ref ref) { return ellipsisTags.contains(ref.getName()); } /** * @return text height in pixel */ public int getTextHeight() { return textHeight; } }