blob: 713f85d7112da579b61e3af9e4223465826c76a1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.history;
import java.text.DateFormat;
import java.util.Date;
import org.eclipse.compare.IModificationDate;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileState;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.team.internal.ui.ITeamUIImages;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.themes.ITheme;
public class LocalHistoryTableProvider {
/* private */ static final int COL_DATE = 0;
/* private */ TreeViewer viewer;
private Image localRevImage;
private DateFormat dateFormat;
/**
* The Local history label provider.
*/
private class LocalHistoryLabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider, IFontProvider {
private Image dateImage;
private Font currentRevisionFont;
private IPropertyChangeListener themeListener = event -> LocalHistoryTableProvider.this.viewer.refresh();
public LocalHistoryLabelProvider() {
PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(themeListener);
}
@Override
public void dispose() {
if (dateImage != null){
dateImage.dispose();
dateImage = null;
}
if (localRevImage != null) {
localRevImage.dispose();
localRevImage = null;
}
if (themeListener != null){
PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(themeListener);
}
if (currentRevisionFont != null) {
currentRevisionFont.dispose();
}
}
@Override
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex == COL_DATE) {
if (element instanceof DateHistoryCategory) {
if (dateImage == null) {
ImageDescriptor dateDesc = TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_DATES_CATEGORY);
dateImage = dateDesc.createImage();
}
return dateImage;
}
if (getModificationDate(element) != -1) {
return getRevisionImage();
}
}
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
if (columnIndex == COL_DATE) {
if (element instanceof AbstractHistoryCategory){
return ((AbstractHistoryCategory) element).getName();
}
long date = getModificationDate(element);
if (date != -1) {
Date dateFromLong = new Date(date);
return getDateFormat().format(dateFromLong);
}
}
return ""; //$NON-NLS-1$
}
@Override
public Color getForeground(Object element) {
if (element instanceof AbstractHistoryCategory){
// TODO: We should have a Team theme for this
ITheme current = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
return current.getColorRegistry().get("org.eclipse.team.cvs.ui.fontsandcolors.cvshistorypagecategories"); //$NON-NLS-1$
}
if (isDeletedEdition(element)) {
return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
}
return null;
}
@Override
public Color getBackground(Object element) {
return null;
}
@Override
public Font getFont(Object element) {
if (element instanceof AbstractHistoryCategory) {
return getCurrentRevisionFont();
}
if (isCurrentEdition(element)) {
return getCurrentRevisionFont();
}
return null;
}
private Font getCurrentRevisionFont() {
if (currentRevisionFont == null) {
Font defaultFont = JFaceResources.getDefaultFont();
FontData[] data = defaultFont.getFontData();
for (FontData d : data) {
d.setStyle(SWT.BOLD);
}
currentRevisionFont = new Font(viewer.getTree().getDisplay(), data);
}
return currentRevisionFont;
}
}
/**
* The history sorter
*/
private class HistoryComparator extends ViewerComparator {
private boolean reversed = false;
private int columnNumber;
// column headings: "Revision" "Tags" "Date" "Author" "Comment"
private int[][] SORT_ORDERS_BY_COLUMN = {
{COL_DATE}, /* date */
};
/**
* The constructor.
* @param columnNumber
*/
public HistoryComparator(int columnNumber) {
this.columnNumber = columnNumber;
}
/**
* Compares two log entries, sorting first by the main column of this sorter,
* then by subsequent columns, depending on the column sort order.
*/
@Override
public int compare(Viewer compareViewer, Object o1, Object o2) {
/*if (o1 instanceof AbstractCVSHistoryCategory || o2 instanceof AbstractCVSHistoryCategory)
return 0;*/
long date1 = getModificationDate(o1);
long date2 = getModificationDate(o2);
int result = 0;
if (date1 == -1 || date2 == -1) {
result = super.compare(compareViewer, o1, o2);
} else {
for (int columnSortOrder : SORT_ORDERS_BY_COLUMN[columnNumber]) {
result = compareColumnValue(columnSortOrder, date1, date2);
if (result != 0)
break;
}
}
if (reversed)
result = -result;
return result;
}
/**
* Compares two markers, based only on the value of the specified column.
*/
int compareColumnValue(int columnNumber, long date1, long date2) {
switch (columnNumber) {
case 0 : /* date */
if (date1 == date2)
return 0;
return date1 > date2 ? -1 : 1;
default :
return 0;
}
}
/**
* Returns the number of the column by which this is sorting.
* @return the column number
*/
public int getColumnNumber() {
return columnNumber;
}
/**
* Returns true for descending, or false
* for ascending sorting order.
* @return returns true if reversed
*/
public boolean isReversed() {
return reversed;
}
/**
* Sets the sorting order.
* @param newReversed
*/
public void setReversed(boolean newReversed) {
reversed = newReversed;
}
}
/**
* Creates the columns for the history table.
*/
private void createColumns(Tree tree, TableLayout layout) {
SelectionListener headerListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// column selected - need to sort
int column = viewer.getTree().indexOf((TreeColumn) e.widget);
HistoryComparator oldSorter = (HistoryComparator) viewer.getComparator();
if (oldSorter != null && column == oldSorter.getColumnNumber()) {
oldSorter.setReversed(!oldSorter.isReversed());
viewer.refresh();
} else {
viewer.setComparator(new HistoryComparator(column));
}
}
};
// creation date
TreeColumn col = new TreeColumn(tree, SWT.NONE);
col.setResizable(true);
col.setText(TeamUIMessages.GenericHistoryTableProvider_RevisionTime);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
}
/**
* Create a TreeViewer that can be used to display a list of IFile instances.
* This method provides the labels and sorter but does not provide a content provider
*
* @param parent
* @return TableViewer
*/
public TreeViewer createTree(Composite parent) {
Tree tree = new Tree(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
tree.setHeaderVisible(true);
tree.setLinesVisible(false);
GridData data = new GridData(GridData.FILL_BOTH);
tree.setLayoutData(data);
TableLayout layout = new TableLayout();
tree.setLayout(layout);
this.viewer = new TreeViewer(tree);
createColumns(tree, layout);
viewer.setLabelProvider(new LocalHistoryLabelProvider());
// By default, reverse sort by revision.
// If local filter is on sort by date
HistoryComparator sorter = new HistoryComparator(COL_DATE);
sorter.setReversed(false);
viewer.setComparator(sorter);
return viewer;
}
protected long getModificationDate(Object element) {
IModificationDate md = Adapters.adapt(element, IModificationDate.class);
if (md != null)
return md.getModificationDate();
if (element instanceof IFileState) {
IFileState fs = (IFileState) element;
return fs.getModificationTime();
}
if (element instanceof IFile) {
IFile f = (IFile) element;
return f.getLocalTimeStamp();
}
return -1;
}
protected boolean isCurrentEdition(Object element) {
if (element instanceof IFile) {
return true;
}
if (element instanceof IFileState) {
return false;
}
return false;
}
protected boolean isDeletedEdition(Object element) {
if (element instanceof IFile) {
IFile f = (IFile) element;
return !f.exists();
}
return false;
}
public Image getRevisionImage() {
if (localRevImage == null) {
ImageDescriptor localRevDesc = TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_LOCALREVISION_TABLE);
localRevImage = localRevDesc.createImage();
}
return localRevImage;
}
public synchronized DateFormat getDateFormat() {
if (dateFormat == null)
dateFormat = DateFormat.getInstance();
return dateFormat;
}
}