/*******************************************************************************
* Copyright (c) 2017 Rogue Wave Software Inc. 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:
* Rogue Wave Software Inc. - initial implementation
*******************************************************************************/
package org.eclipse.php.internal.debug.ui.views.coverage;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.php.internal.debug.ui.PHPDebugUIMessages;
import org.eclipse.php.internal.ui.editor.PHPSourceViewer;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.themes.IThemeManager;
/**
* Code coverage text viewer.
*/
public class CodeCoverageTextViewer extends PHPSourceViewer implements IPropertyChangeListener {
private static final String COVERED_LINES_COLOR_DEF = "org.eclipse.php.debug.ui.themePHPDebug.codeCoverageCoveredLinesBg"; //$NON-NLS-1$
private static final String UNCOVERED_LINES_COLOR_DEF = "org.eclipse.php.debug.ui.themePHPDebug.codeCoverageUncoveredLinesBg"; //$NON-NLS-1$
private IThemeManager fThemeManager;
private Color fCoveredLineBackground;
private Color fUncoveredLineBackground;
private Color fUncoveredSignificantBackground;
private byte[] fCoverageBitmask = {};
private byte[] fSignificanceBitmask = {};
public CodeCoverageTextViewer(Composite parent, int style) {
super(parent, style);
setEditable(false);
fThemeManager = PlatformUI.getWorkbench().getThemeManager();
fThemeManager.addPropertyChangeListener(this);
fCoveredLineBackground = fThemeManager.getCurrentTheme().getColorRegistry().get(COVERED_LINES_COLOR_DEF);
fUncoveredLineBackground = fThemeManager.getCurrentTheme().getColorRegistry().get(UNCOVERED_LINES_COLOR_DEF);
fUncoveredSignificantBackground = composeColors(fUncoveredLineBackground, fCoveredLineBackground, 2);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
* .jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (COVERED_LINES_COLOR_DEF.equals(event.getProperty())) {
fCoveredLineBackground = fThemeManager.getCurrentTheme().getColorRegistry().get(COVERED_LINES_COLOR_DEF);
refresh();
} else if (UNCOVERED_LINES_COLOR_DEF.equals(event.getProperty())) {
fUncoveredLineBackground = fThemeManager.getCurrentTheme().getColorRegistry()
.get(UNCOVERED_LINES_COLOR_DEF);
refresh();
}
super.propertyChange(event);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
public void dispose() {
fThemeManager.removePropertyChangeListener(this);
fUncoveredSignificantBackground.dispose();
super.dispose();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.php.internal.ui.editor.PHPSourceViewer#applyStyles()
*/
public void applyStyles() {
super.applyStyles();
StyledText text = getTextWidget();
int linesNum = text.getLineCount();
for (int line = 0; line < linesNum; line++) {
if (isLineCovered(line)) {
text.setLineBackground(line, 1, fCoveredLineBackground);
} else {
if (isLineSignificant(line))
text.setLineBackground(line, 1, fUncoveredLineBackground);
}
}
}
public void setCoverageBitmask(byte[] coverageBitmask) {
fCoverageBitmask = coverageBitmask;
}
public void setSingificanceBitmask(byte[] coverageBitmask) {
fSignificanceBitmask = coverageBitmask;
}
public void goToNextLine() {
StyledText text = getTextWidget();
int line = text.getLineAtOffset(text.getCaretOffset());
int numLines = text.getLineCount();
do {
++line;
} while ((!isLineCovered(line - 1) /* || !isLineSignificant(line - 1) */) && line < numLines);
if (line < numLines) {
text.setSelection(text.getOffsetAtLine(line - 1), text.getOffsetAtLine(line));
} else {
MessageDialog.openInformation(getShell(), PHPDebugUIMessages.CodeCoverageTextViewer_1,
PHPDebugUIMessages.CodeCoverageTextViewer_2);
}
}
public void goToPreviousLine() {
StyledText text = getTextWidget();
int line = text.getLineAtOffset(text.getCaretOffset());
do {
--line;
} while ((!isLineCovered(line - 1) /* || !isLineSignificant(line - 1) */) && line > 0);
if (line > 0) {
text.setSelection(text.getOffsetAtLine(line - 1), text.getOffsetAtLine(line));
} else {
MessageDialog.openInformation(getShell(), PHPDebugUIMessages.CodeCoverageTextViewer_3,
PHPDebugUIMessages.CodeCoverageTextViewer_4);
}
}
/**
* Checks whether the specified line is covered.
*
* @param int
* line (beginning from 1)
* @return <code>true</code> if the specified line is covered,
* <code>false</code> otherwise.
* @throws IllegalArgumentException
* when the specified line is out of coverage bitmask bounds.
*/
private boolean isLineCovered(int line) {
line++;
if (fCoverageBitmask.length > line / 8) {
return ((fCoverageBitmask[line / 8] >> (line % 8)) & 0x1) == (byte) 1;
}
return false;
}
private boolean isLineSignificant(int line) {
line++;
if (fSignificanceBitmask.length > line / 8) {
return ((fSignificanceBitmask[line / 8] >> (line % 8)) & 0x1) == (byte) 1;
}
return false;
}
private static Color composeColors(Color c1, Color c2, int proportion) {
int divider = proportion + 1;
Color newColor = new Color(c1.getDevice(), (proportion * c1.getRed() + c2.getRed()) / divider,
(proportion * c1.getGreen() + c2.getGreen()) / divider,
(proportion * c1.getBlue() + c2.getBlue()) / divider);
return newColor;
}
}