| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ccvs.ui; |
| |
| import java.text.DateFormat; |
| import java.util.Date; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.viewers.*; |
| 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; |
| |
| /** |
| * 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_TAGS = 1; |
| private static final int COL_DATE = 2; |
| private static final int COL_AUTHOR = 3; |
| private static final int COL_COMMENT = 4; |
| |
| /** |
| * The history label provider. |
| */ |
| class HistoryLabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider, IFontProvider { |
| public Image getColumnImage(Object element, int columnIndex) { |
| return null; |
| } |
| 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 = Policy.bind("currentRevision", revision); //$NON-NLS-1$ |
| } |
| return revision; |
| case COL_TAGS: |
| CVSTag[] tags = entry.getTags(); |
| StringBuffer 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 Policy.bind("notAvailable"); //$NON-NLS-1$ |
| return DateFormat.getInstance().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 Policy.bind("HistoryView.[...]_4"); //$NON-NLS-1$ |
| default: |
| return Policy.bind("CVSCompareRevisionsInput.truncate", comment.substring(0, index)); //$NON-NLS-1$ |
| } |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) |
| */ |
| public Color getForeground(Object element) { |
| ILogEntry entry = adaptToLogEntry(element); |
| if (entry.isDeletion()) { |
| return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| } else { |
| return null; |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object) |
| */ |
| public Color getBackground(Object element) { |
| return null; |
| } |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object) |
| */ |
| 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 HistorySorter extends ViewerSorter { |
| private boolean reversed = false; |
| private int columnNumber; |
| |
| private VersionCollator versionCollator = new VersionCollator(); |
| |
| // column headings: "Revision" "Tags" "Date" "Author" "Comment" |
| private int[][] SORT_ORDERS_BY_COLUMN = { |
| {COL_REVISION, COL_DATE, COL_AUTHOR, COL_COMMENT, COL_TAGS}, /* revision */ |
| {COL_TAGS, COL_REVISION, COL_DATE, COL_AUTHOR, COL_COMMENT}, /* tags */ |
| {COL_DATE, COL_REVISION, COL_AUTHOR, COL_COMMENT, COL_TAGS}, /* date */ |
| {COL_AUTHOR, COL_REVISION, COL_DATE, COL_COMMENT, COL_TAGS}, /* author */ |
| {COL_COMMENT, COL_REVISION, COL_DATE, COL_AUTHOR, COL_TAGS} /* comment */ |
| }; |
| |
| /** |
| * The constructor. |
| */ |
| public HistorySorter(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. |
| */ |
| 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 0: /* revision */ |
| return versionCollator.compare(e1.getRevision(), e2.getRevision()); |
| case 1: /* tags */ |
| CVSTag[] tags1 = e1.getTags(); |
| CVSTag[] tags2 = e2.getTags(); |
| if (tags2.length == 0) { |
| return -1; |
| } |
| if (tags1.length == 0) { |
| return 1; |
| } |
| return getCollator().compare(tags1[0].getName(), tags2[0].getName()); |
| case 2: /* date */ |
| Date date1 = e1.getDate(); |
| Date date2 = e2.getDate(); |
| return date1.compareTo(date2); |
| case 3: /* author */ |
| return getCollator().compare(e1.getAuthor(), e2.getAuthor()); |
| case 4: /* comment */ |
| return getCollator().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 = (ILogEntry)((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. |
| HistorySorter sorter = new HistorySorter(COL_REVISION); |
| sorter.setReversed(true); |
| viewer.setSorter(sorter); |
| |
| table.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent 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. |
| HistorySorter sorter = new HistorySorter(COL_REVISION); |
| sorter.setReversed(true); |
| viewer.setSorter(sorter); |
| |
| table.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent 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(Policy.bind("HistoryView.revision")); //$NON-NLS-1$ |
| col.addSelectionListener(headerListener); |
| layout.addColumnData(new ColumnWeightData(20, true)); |
| |
| // tags |
| col = new TableColumn(table, SWT.NONE); |
| col.setResizable(true); |
| col.setText(Policy.bind("HistoryView.tags")); //$NON-NLS-1$ |
| col.addSelectionListener(headerListener); |
| layout.addColumnData(new ColumnWeightData(20, true)); |
| |
| // creation date |
| col = new TableColumn(table, SWT.NONE); |
| col.setResizable(true); |
| col.setText(Policy.bind("HistoryView.date")); //$NON-NLS-1$ |
| col.addSelectionListener(headerListener); |
| layout.addColumnData(new ColumnWeightData(20, true)); |
| |
| // author |
| col = new TableColumn(table, SWT.NONE); |
| col.setResizable(true); |
| col.setText(Policy.bind("HistoryView.author")); //$NON-NLS-1$ |
| col.addSelectionListener(headerListener); |
| layout.addColumnData(new ColumnWeightData(20, true)); |
| |
| //comment |
| col = new TableColumn(table, SWT.NONE); |
| col.setResizable(true); |
| col.setText(Policy.bind("HistoryView.comment")); //$NON-NLS-1$ |
| 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). |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| // column selected - need to sort |
| int column = tableViewer.getTable().indexOf((TableColumn) e.widget); |
| HistorySorter oldSorter = (HistorySorter)tableViewer.getSorter(); |
| if (oldSorter != null && column == oldSorter.getColumnNumber()) { |
| oldSorter.setReversed(!oldSorter.isReversed()); |
| tableViewer.refresh(); |
| } else { |
| tableViewer.setSorter(new HistorySorter(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; |
| } |
| } |