blob: 30334fc91b2cf68c6595d13ed5619a272366be66 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 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
* Olexiy Buyanskyy <olexiyb@gmail.com> - Bug 76386 - [History View] CVS Resource History shows revisions from all branches
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui;
import java.util.Date;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import com.ibm.icu.text.DateFormat;
/**
* This class provides the table and it's required components for a file's revision
* history
*/
public class HistoryTableProvider {
private ICVSFile currentFile;
private String currentRevision;
private TableViewer viewer;
private Font currentRevisionFont;
/**
* Constructor for HistoryTableProvider.
*/
public HistoryTableProvider() {
super();
}
//column constants
private static final int COL_REVISION = 0;
private static final int COL_BRANCHES = 1;
private static final int COL_TAGS = 2;
private static final int COL_DATE = 3;
private static final int COL_AUTHOR = 4;
private static final int COL_COMMENT = 5;
/**
* The history label provider.
*/
class HistoryLabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider, IFontProvider {
private DateFormat dateFormat;
@Override
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
ILogEntry entry = adaptToLogEntry(element);
if (entry == null) return ""; //$NON-NLS-1$
switch (columnIndex) {
case COL_REVISION:
String revision = entry.getRevision();
String currentRevision = getCurrentRevision();
if (currentRevision != null && currentRevision.equals(revision)) {
revision = NLS.bind(CVSUIMessages.currentRevision, new String[] { revision });
}
return revision;
case COL_BRANCHES:
CVSTag[] branches = entry.getBranches();
StringBuffer result = new StringBuffer();
for (int i = 0; i < branches.length; i++) {
result.append(branches[i].getName());
if (i < branches.length - 1) {
result.append(", "); //$NON-NLS-1$
}
}
return result.toString();
case COL_TAGS:
CVSTag[] tags = entry.getTags();
result = new StringBuffer();
for (int i = 0; i < tags.length; i++) {
result.append(tags[i].getName());
if (i < tags.length - 1) {
result.append(", "); //$NON-NLS-1$
}
}
return result.toString();
case COL_DATE:
Date date = entry.getDate();
if (date == null) return CVSUIMessages.notAvailable;
return getDateFormat().format(date);
case COL_AUTHOR:
return entry.getAuthor();
case COL_COMMENT:
String comment = entry.getComment();
int index = comment.indexOf("\n"); //$NON-NLS-1$
switch (index) {
case -1:
return comment;
case 0:
return CVSUIMessages.HistoryView_______4;
default:
return NLS.bind(CVSUIMessages.CVSCompareRevisionsInput_truncate, new String[] { comment.substring(0, index) });
}
}
return ""; //$NON-NLS-1$
}
private synchronized DateFormat getDateFormat() {
if (dateFormat == null)
dateFormat = DateFormat.getInstance();
return dateFormat;
}
@Override
public Color getForeground(Object element) {
ILogEntry entry = adaptToLogEntry(element);
if (entry.isDeletion()) {
return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
} else {
return null;
}
}
@Override
public Color getBackground(Object element) {
return null;
}
@Override
public Font getFont(Object element) {
ILogEntry entry = adaptToLogEntry(element);
if (entry == null)
return null;
String revision = entry.getRevision();
String currentRevision = getCurrentRevision();
if (currentRevision != null && currentRevision.equals(revision)) {
if (currentRevisionFont == null) {
Font defaultFont = JFaceResources.getDefaultFont();
FontData[] data = defaultFont.getFontData();
for (int i = 0; i < data.length; i++) {
data[i].setStyle(SWT.BOLD);
}
currentRevisionFont = new Font(viewer.getTable().getDisplay(), data);
}
return currentRevisionFont;
}
return null;
}
}
/**
* The history sorter
*/
class HistoryComparator extends ViewerComparator {
private boolean reversed = false;
private int columnNumber;
private VersionCollator versionCollator = new VersionCollator();
// column headings: "Revision" "Branches" "Tags" "Date" "Author" "Comment"
private int[][] SORT_ORDERS_BY_COLUMN = {
{COL_REVISION, COL_DATE, COL_AUTHOR, COL_COMMENT, COL_TAGS, COL_BRANCHES}, /* revision */
{COL_BRANCHES, COL_REVISION, COL_DATE, COL_AUTHOR, COL_COMMENT, COL_TAGS}, /* tags */
{COL_TAGS, COL_REVISION, COL_DATE, COL_AUTHOR, COL_COMMENT, COL_BRANCHES}, /* tags */
{COL_DATE, COL_REVISION, COL_AUTHOR, COL_COMMENT, COL_TAGS, COL_BRANCHES}, /* date */
{COL_AUTHOR, COL_REVISION, COL_DATE, COL_COMMENT, COL_TAGS, COL_BRANCHES}, /* author */
{COL_COMMENT, COL_REVISION, COL_DATE, COL_AUTHOR, COL_TAGS, COL_BRANCHES} /* comment */
};
/**
* The constructor.
*/
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 viewer, Object o1, Object o2) {
ILogEntry e1 = adaptToLogEntry(o1);
ILogEntry e2 = adaptToLogEntry(o2);
int result = 0;
if (e1 == null || e2 == null) {
result = super.compare(viewer, o1, o2);
} else {
int[] columnSortOrder = SORT_ORDERS_BY_COLUMN[columnNumber];
for (int i = 0; i < columnSortOrder.length; ++i) {
result = compareColumnValue(columnSortOrder[i], e1, e2);
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, ILogEntry e1, ILogEntry e2) {
switch (columnNumber) {
case COL_REVISION: /* revision */
return versionCollator.compare(e1.getRevision(), e2.getRevision());
case COL_BRANCHES: /* branches */
CVSTag[] branches1 = e1.getBranches();
CVSTag[] branches2 = e2.getBranches();
if (branches2.length == 0) {
return -1;
}
if (branches1.length == 0) {
return 1;
}
return getComparator().compare(branches1[0].getName(), branches2[0].getName());
case COL_TAGS: /* tags */
CVSTag[] tags1 = e1.getTags();
CVSTag[] tags2 = e2.getTags();
if (tags2.length == 0) {
return -1;
}
if (tags1.length == 0) {
return 1;
}
return getComparator().compare(tags1[0].getName(), tags2[0].getName());
case COL_DATE: /* date */
Date date1 = e1.getDate();
Date date2 = e2.getDate();
return date1.compareTo(date2);
case COL_AUTHOR: /* author */
return getComparator().compare(e1.getAuthor(), e2.getAuthor());
case COL_COMMENT: /* comment */
return getComparator().compare(e1.getComment(), e2.getComment());
default:
return 0;
}
}
/**
* Returns the number of the column by which this is sorting.
*/
public int getColumnNumber() {
return columnNumber;
}
/**
* Returns true for descending, or false
* for ascending sorting order.
*/
public boolean isReversed() {
return reversed;
}
/**
* Sets the sorting order.
*/
public void setReversed(boolean newReversed) {
reversed = newReversed;
}
}
protected ILogEntry adaptToLogEntry(Object element) {
// Get the log entry for the provided object
ILogEntry entry = null;
if (element instanceof ILogEntry) {
entry = (ILogEntry) element;
} else if (element instanceof IAdaptable) {
entry = ((IAdaptable)element).getAdapter(ILogEntry.class);
}
return entry;
}
/**
* Create a TableViewer that can be used to display a list of ILogEntry instances.
* Ths method provides the labels and sorter but does not provide a content provider
*
* @param parent
* @return TableViewer
*/
public TableViewer createTable(Composite parent) {
Table table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
GridData data = new GridData(GridData.FILL_BOTH);
table.setLayoutData(data);
TableLayout layout = new TableLayout();
table.setLayout(layout);
TableViewer viewer = new TableViewer(table);
createColumns(table, layout, viewer);
viewer.setLabelProvider(new HistoryLabelProvider());
// By default, reverse sort by revision.
HistoryComparator sorter = new HistoryComparator(COL_REVISION);
sorter.setReversed(true);
viewer.setComparator(sorter);
table.addDisposeListener(e -> {
if (currentRevisionFont != null) {
currentRevisionFont.dispose();
}
});
this.viewer = viewer;
return viewer;
}
/**
* Create a CheckBoxTableViewer that can be used to display a list of ILogEntry instances.
* Ths method provides the labels and sorter but does not provide a content provider
*
* @param parent
* @return TableViewer
*/
public CheckboxTableViewer createCheckBoxTable(Composite parent) {
Table table = new Table(parent, SWT.CHECK | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
GridData data = new GridData(GridData.FILL_BOTH);
table.setLayoutData(data);
TableLayout layout = new TableLayout();
table.setLayout(layout);
CheckboxTableViewer viewer = new CheckboxTableViewer(table);
createColumns(table, layout, viewer);
viewer.setLabelProvider(new HistoryLabelProvider());
// By default, reverse sort by revision.
HistoryComparator sorter = new HistoryComparator(COL_REVISION);
sorter.setReversed(true);
viewer.setComparator(sorter);
table.addDisposeListener(e -> {
if (currentRevisionFont != null) {
currentRevisionFont.dispose();
}
});
this.viewer = viewer;
return viewer;
}
/**
* Creates the columns for the history table.
*/
private void createColumns(Table table, TableLayout layout, TableViewer viewer) {
SelectionListener headerListener = getColumnListener(viewer);
// revision
TableColumn col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_revision);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
// branches
col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_branches);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
// tags
col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_tags);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
// creation date
col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_date);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
// author
col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_author);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(20, true));
//comment
col = new TableColumn(table, SWT.NONE);
col.setResizable(true);
col.setText(CVSUIMessages.HistoryView_comment);
col.addSelectionListener(headerListener);
layout.addColumnData(new ColumnWeightData(50, true));
}
/**
* Adds the listener that sets the sorter.
*/
private SelectionListener getColumnListener(final TableViewer tableViewer) {
/**
* This class handles selections of the column headers.
* Selection of the column header will cause resorting
* of the shown tasks using that column's sorter.
* Repeated selection of the header will toggle
* sorting order (ascending versus descending).
*/
return new SelectionAdapter() {
/**
* Handles the case of user selecting the
* header area.
* <p>If the column has not been selected previously,
* it will set the sorter of that column to be
* the current tasklist sorter. Repeated
* presses on the same column header will
* toggle sorting order (ascending/descending).
*/
@Override
public void widgetSelected(SelectionEvent e) {
// column selected - need to sort
int column = tableViewer.getTable().indexOf((TableColumn) e.widget);
HistoryComparator oldSorter = (HistoryComparator)tableViewer.getComparator();
if (oldSorter != null && column == oldSorter.getColumnNumber()) {
oldSorter.setReversed(!oldSorter.isReversed());
tableViewer.refresh();
} else {
tableViewer.setComparator(new HistoryComparator(column));
}
}
};
}
public String getCurrentRevision() {
return currentRevision;
}
/**
* Method getRevision.
* @param currentEdition
*/
private String getRevision(ICVSFile currentEdition) throws CVSException {
if (currentEdition == null) return ""; //$NON-NLS-1$
ResourceSyncInfo info = currentEdition.getSyncInfo();
if (info == null) return ""; //$NON-NLS-1$
return info.getRevision();
}
public void setFile(ICVSFile file) throws CVSException {
this.currentFile = file;
this.currentRevision = getRevision(this.currentFile);
}
public ICVSFile getICVSFile() {
return this.currentFile;
}
}