/*******************************************************************************
* Copyright (c) 2011, 2013 GitHub 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:
* Kevin Sawicki (GitHub Inc.) - initial API and implementation
* Tobias Pfeifer (SAP AG) - customizable font and color for the first header line - https://bugs.eclipse.org/397723
*******************************************************************************/
package org.eclipse.egit.ui.internal.commit;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffAddBackgroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffAddForegroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffHunkBackgroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffHunkForegroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffRemoveBackgroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffRemoveForegroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffHeadlineBackgroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffHeadlineForegroundColor;
import static org.eclipse.egit.ui.UIPreferences.THEME_DiffHeadlineFont;
import org.eclipse.egit.ui.internal.commit.DiffStyleRangeFormatter.DiffStyleRange;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.ColorDescriptor;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.DeviceResourceManager;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.source.CompositeRuler;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.LineNumberRulerColumn;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.custom.LineBackgroundEvent;
import org.eclipse.swt.custom.LineBackgroundListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.themes.IThemeManager;
/**
* Source viewer to display one or more file differences using standard editor
* colors and fonts preferences.
*/
public class DiffViewer extends SourceViewer {
private DiffStyleRangeFormatter formatter;
private DeviceResourceManager colors = new DeviceResourceManager(PlatformUI
.getWorkbench().getDisplay());
private LineNumberRulerColumn lineNumberRuler;
private Color hunkBackgroundColor;
private Color hunkForegroundColor;
private Color addBackgroundColor;
private Color addForegroundColor;
private Color removeBackgroundColor;
private Color removeForegroundColor;
private Color headlineBackgroundColor;
private Color headlineForegroundColor;
private Font headlineFont;
private IPropertyChangeListener themeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
if (IThemeManager.CHANGE_CURRENT_THEME.equals(property)
|| THEME_DiffAddBackgroundColor.equals(property)
|| THEME_DiffAddForegroundColor.equals(property)
|| THEME_DiffHunkBackgroundColor.equals(property)
|| THEME_DiffHunkForegroundColor.equals(property)
|| THEME_DiffHeadlineBackgroundColor.equals(property)
|| THEME_DiffHeadlineForegroundColor.equals(property)
|| THEME_DiffHeadlineFont.equals(property)
|| THEME_DiffRemoveBackgroundColor.equals(property)
|| THEME_DiffRemoveForegroundColor.equals(property)) {
refreshDiffColors();
refreshDiffFonts();
refreshStyleRanges();
}
}
};
private IPropertyChangeListener editorPrefListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
styleViewer();
}
};
/**
* @param parent
* @param ruler
* @param styles
* @param showCursorLine
*/
public DiffViewer(Composite parent, IVerticalRuler ruler, int styles,
boolean showCursorLine) {
super(parent, ruler, styles);
setDocument(new Document());
SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(
this, null, null, EditorsUI.getSharedTextColors());
if (showCursorLine) {
support.setCursorLinePainterPreferenceKeys(
AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE,
AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR);
}
support.install(EditorsUI.getPreferenceStore());
if (ruler instanceof CompositeRuler) {
lineNumberRuler = new LineNumberRulerColumn();
((CompositeRuler) ruler).addDecorator(0, lineNumberRuler);
}
getTextWidget().setAlwaysShowScrollBars(false);
initListeners();
getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
EditorsUI.getPreferenceStore().removePropertyChangeListener(
editorPrefListener);
PlatformUI.getWorkbench().getThemeManager()
.removePropertyChangeListener(themeListener);
colors.dispose();
}
});
refreshDiffColors();
refreshDiffFonts();
styleViewer();
}
private void refreshDiffFonts() {
FontRegistry reg = PlatformUI.getWorkbench().getThemeManager()
.getCurrentTheme().getFontRegistry();
this.headlineFont = reg.get(THEME_DiffHeadlineFont);
}
private void refreshDiffColors() {
ColorRegistry reg = PlatformUI.getWorkbench().getThemeManager()
.getCurrentTheme().getColorRegistry();
this.addBackgroundColor = reg.get(THEME_DiffAddBackgroundColor);
this.addForegroundColor = reg.get(THEME_DiffAddForegroundColor);
this.removeBackgroundColor = reg.get(THEME_DiffRemoveBackgroundColor);
this.removeForegroundColor = reg.get(THEME_DiffRemoveForegroundColor);
this.hunkBackgroundColor = reg.get(THEME_DiffHunkBackgroundColor);
this.hunkForegroundColor = reg.get(THEME_DiffHunkForegroundColor);
this.headlineBackgroundColor = reg.get(THEME_DiffHeadlineBackgroundColor);
this.headlineForegroundColor = reg.get(THEME_DiffHeadlineForegroundColor);
}
private void initListeners() {
PlatformUI.getWorkbench().getThemeManager()
.addPropertyChangeListener(this.themeListener);
EditorsUI.getPreferenceStore().addPropertyChangeListener(
this.editorPrefListener);
getTextWidget().addLineBackgroundListener(new LineBackgroundListener() {
public void lineGetBackground(LineBackgroundEvent event) {
StyledText text = getTextWidget();
if (event.lineOffset < text.getCharCount()) {
StyleRange style = text
.getStyleRangeAtOffset(event.lineOffset);
if (style instanceof DiffStyleRange)
event.lineBackground = ((DiffStyleRange) style).lineBackground;
}
}
});
}
private ColorDescriptor createEditorColorDescriptor(String key) {
return ColorDescriptor.createFrom(PreferenceConverter.getColor(
EditorsUI.getPreferenceStore(), key));
}
private Color getEditorColor(String key) {
return (Color) colors.get(createEditorColorDescriptor(key));
}
private void styleViewer() {
IPreferenceStore store = EditorsUI.getPreferenceStore();
Color foreground = null;
if (!store
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT))
foreground = getEditorColor(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND);
Color background = null;
if (!store
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT))
background = getEditorColor(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
Color selectionForeground = null;
if (!store
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT))
selectionForeground = getEditorColor(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_FOREGROUND);
Color selectionBackground = null;
if (!store
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT))
selectionBackground = getEditorColor(AbstractTextEditor.PREFERENCE_COLOR_SELECTION_BACKGROUND);
StyledText text = getTextWidget();
text.setForeground(foreground);
text.setBackground(background);
text.setSelectionForeground(selectionForeground);
text.setSelectionBackground(selectionBackground);
text.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT));
if (lineNumberRuler != null) {
lineNumberRuler.setFont(text.getFont());
lineNumberRuler.setForeground(foreground);
lineNumberRuler.setBackground(background);
}
}
/** Refresh style ranges */
public void refreshStyleRanges() {
DiffStyleRange[] ranges = formatter != null ? formatter.getRanges()
: new DiffStyleRange[0];
for (DiffStyleRange range : ranges)
switch (range.diffType) {
case ADD:
range.foreground = addForegroundColor;
range.lineBackground = addBackgroundColor;
break;
case REMOVE:
range.foreground = removeForegroundColor;
range.lineBackground = removeBackgroundColor;
break;
case HUNK:
range.foreground = hunkForegroundColor;
range.lineBackground = hunkBackgroundColor;
break;
case HEADLINE:
range.font = headlineFont;
range.foreground = headlineForegroundColor;
range.lineBackground = headlineBackgroundColor;
break;
default:
break;
}
getTextWidget().setStyleRanges(ranges);
}
/** @param formatter */
public void setFormatter(DiffStyleRangeFormatter formatter) {
this.formatter = formatter;
refreshStyleRanges();
}
}