Java tutorial
/******************************************************************************* * Copyright (c) 2006, 2013 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 * Brock Janiczak (brockj@tpg.com.au) - Bug 180436 Use table sort indicators on CVS * Brock Janiczak (brockj@tpg.com.au) - Bug 181899 CVS History wrongly ordered * Brock Janiczak <brockj@tpg.com.au> - Bug 182442 Display full comment in tooltip * 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.resources.IFile; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.layout.PixelConverter; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; 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.core.history.*; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.ICVSFile; import org.eclipse.team.internal.ccvs.core.filehistory.CVSFileRevision; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.core.history.LocalFileRevision; import org.eclipse.team.internal.ui.TeamUIMessages; import org.eclipse.team.internal.ui.history.AbstractHistoryCategory; import org.eclipse.team.internal.ui.history.DateHistoryCategory; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.themes.ITheme; import com.ibm.icu.text.DateFormat; public class CVSHistoryTableProvider { public static final String CATEGORIES_COLOR = "org.eclipse.team.cvs.ui.fontsandcolors.cvshistorypagecategories"; //$NON-NLS-1$ private IFileHistory currentFileHistory; private IFile workspaceFile; /* private */TreeViewer viewer; /* private */Font currentRevisionFont; private boolean baseModified; private IDialogSettings settings; //column constants private static final int COL_REVISIONID = 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; // cvs history table provider settings section name private static final String CVS_HISTORY_TABLE_PROVIDER_SECTION = CVSHistoryTableProvider.class.getName(); // cvs history table provider settings keys private static final String COL_REVISIONID_NAME = "COL_REVISIONID"; //$NON-NLS-1$ private static final String COL_BRANCHES_NAME = "COL_BRANCHES"; //$NON-NLS-1$ private static final String COL_TAGS_NAME = "COL_TAGS"; //$NON-NLS-1$ private static final String COL_DATE_NAME = "COL_DATE"; //$NON-NLS-1$ private static final String COL_AUTHOR_NAME = "COL_AUTHOR"; //$NON-NLS-1$ private static final String COL_COMMENT_NAME = "COL_COMMENT"; //$NON-NLS-1$ private static final String COL_NAME = "COLUMN_NAME"; //$NON-NLS-1$ private static final String SORT_COL_NAME = "SORT_COL_NAME"; //$NON-NLS-1$ private static final String SORT_COL_DIRECTION = "SORT_COL_DIRECTION"; //$NON-NLS-1$ public CVSHistoryTableProvider() { IDialogSettings viewsSettings = CVSUIPlugin.getPlugin().getDialogSettings(); settings = viewsSettings.getSection(CVS_HISTORY_TABLE_PROVIDER_SECTION); if (settings == null) { settings = viewsSettings.addNewSection(CVS_HISTORY_TABLE_PROVIDER_SECTION); } } /** * The history label provider. */ class HistoryLabelProvider extends ColumnLabelProvider { Image dateImage = null; ImageDescriptor dateDesc = null; Image localRevImage = null; ImageDescriptor localRevDesc = null; Image remoteRevImage = null; ImageDescriptor remoteRevDesc = null; ThemeListener themeListener; private DateFormat dateFormat; private final int column; public HistoryLabelProvider(int column, CVSHistoryTableProvider provider) { this.column = column; PlatformUI.getWorkbench().getThemeManager() .addPropertyChangeListener(themeListener = new ThemeListener(provider)); } public void dispose() { if (dateImage != null) { dateImage.dispose(); dateImage = null; } if (localRevImage != null) { localRevImage.dispose(); localRevImage = null; } if (remoteRevImage != null) { remoteRevImage.dispose(); remoteRevImage = null; } if (themeListener != null) { PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(themeListener); } } /* (non-Javadoc) * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object) */ public String getToolTipText(Object element) { if (column == COL_COMMENT && !isSingleLine(element)) { IFileRevision entry = adaptToFileRevision(element); if (entry != null) return entry.getComment(); } return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.CellLabelProvider#useNativeToolTip(java.lang.Object) */ public boolean useNativeToolTip(Object object) { return column != COL_COMMENT || isSingleLine(object); } private boolean isSingleLine(Object object) { IFileRevision entry = adaptToFileRevision(object); if (entry != null) return entry.getComment() == null || entry.getComment().indexOf('\n') == -1; return true; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object) */ public Image getImage(Object element) { return getColumnImage(element, column); } public Image getColumnImage(Object element, int columnIndex) { if (element instanceof DateHistoryCategory && columnIndex == COL_REVISIONID) { if (dateImage == null) { dateDesc = CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_DATES_CATEGORY); dateImage = dateDesc.createImage(); } return dateImage; } if (element instanceof LocalFileRevision && columnIndex == COL_REVISIONID) { if (localRevImage == null) { localRevDesc = CVSUIPlugin.getPlugin() .getImageDescriptor(ICVSUIConstants.IMG_LOCALREVISION_TABLE); localRevImage = localRevDesc.createImage(); } return localRevImage; } if (element instanceof CVSFileRevision && columnIndex == COL_REVISIONID) { if (remoteRevImage == null) { remoteRevDesc = CVSUIPlugin.getPlugin() .getImageDescriptor(ICVSUIConstants.IMG_REMOTEREVISION_TABLE); remoteRevImage = remoteRevDesc.createImage(); } return remoteRevImage; } return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object) */ public String getText(Object element) { return getColumnText(element, column); } public String getColumnText(Object element, int columnIndex) { if (element instanceof AbstractHistoryCategory) { if (columnIndex != COL_REVISIONID) return ""; //$NON-NLS-1$ return ((AbstractHistoryCategory) element).getName(); } IFileRevision entry = adaptToFileRevision(element); if (entry == null) return ""; //$NON-NLS-1$ switch (columnIndex) { case COL_REVISIONID: String revision = entry.getContentIdentifier(); String currentRevision = getCurrentRevision(); if (currentRevision != null && currentRevision.equals(revision)) { if (baseModified) revision = NLS.bind(CVSUIMessages.nameAndRevision, new String[] { revision, CVSUIMessages.CVSHistoryTableProvider_base }); //NLS.bind(CVSUIMessages.currentRevision, new String[] { revision }); else revision = NLS.bind(CVSUIMessages.currentRevision, new String[] { revision }); //NLS.bind(CVSUIMessages.currentRevision, new String[] { revision }); } return revision; case COL_BRANCHES: ITag[] branches = entry.getBranches(); StringBuffer resultBranches = new StringBuffer(); for (int i = 0; i < branches.length; i++) { resultBranches.append(branches[i].getName()); if (i < branches.length - 1) { resultBranches.append(", "); //$NON-NLS-1$ } } return resultBranches.toString(); case COL_TAGS: ITag[] 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: long date = entry.getTimestamp(); Date dateFromLong = new Date(date); return getDateFormat().format(dateFromLong); case COL_AUTHOR: return entry.getAuthor(); case COL_COMMENT: return getCommentAsSingleLine(entry); } return ""; //$NON-NLS-1$ } private synchronized DateFormat getDateFormat() { if (dateFormat == null) dateFormat = DateFormat.getInstance(); return dateFormat; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) */ public Color getForeground(Object element) { if (element instanceof AbstractHistoryCategory) { ITheme current = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme(); return current.getColorRegistry().get(CVSHistoryTableProvider.CATEGORIES_COLOR); } IFileRevision entry = adaptToFileRevision(element); if (!entry.exists()) { return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); } 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) { if (element instanceof AbstractHistoryCategory) { return getCurrentRevisionFont(); } IFileRevision entry = adaptToFileRevision(element); if (entry == null) return null; String revision = entry.getContentIdentifier(); //String comment = entry.getComment(); String tempCurrentRevision = getCurrentRevision(); Font returnFont = null; if (tempCurrentRevision != null && tempCurrentRevision.equals(revision)) { returnFont = getCurrentRevisionFont(); } //Check to see if this is the local workspace file if (workspaceFile != null && entry instanceof LocalFileRevision) { LocalFileRevision localRevision = (LocalFileRevision) entry; if (localRevision.isCurrentState()) return getCurrentRevisionFont(); } return returnFont; } private Font getCurrentRevisionFont() { 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.getTree().getDisplay(), data); } return currentRevisionFont; } } /** * 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_REVISIONID, COL_DATE, COL_AUTHOR, COL_COMMENT, COL_TAGS, COL_BRANCHES }, /* revision */ { COL_BRANCHES, COL_DATE, COL_REVISIONID, COL_AUTHOR, COL_COMMENT, COL_TAGS }, /* tags */ { COL_TAGS, COL_DATE, COL_REVISIONID, COL_AUTHOR, COL_COMMENT, COL_BRANCHES }, /* tags */ { COL_DATE, COL_REVISIONID, COL_AUTHOR, COL_COMMENT, COL_TAGS, COL_BRANCHES }, /* date */ { COL_AUTHOR, COL_REVISIONID, COL_DATE, COL_COMMENT, COL_TAGS, COL_BRANCHES }, /* author */ { COL_COMMENT, COL_REVISIONID, 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. */ public int compare(Viewer compareViewer, Object o1, Object o2) { if (o1 instanceof AbstractHistoryCategory || o2 instanceof AbstractHistoryCategory) return 0; IFileRevision e1 = adaptToFileRevision(o1); IFileRevision e2 = adaptToFileRevision(o2); int result = 0; if (e1 == null || e2 == null) { result = super.compare(compareViewer, 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, IFileRevision e1, IFileRevision e2) { switch (columnNumber) { case COL_REVISIONID: /* revision */ if (e1 instanceof LocalFileRevision || e2 instanceof LocalFileRevision) { //compare based on dates long date1 = e1.getTimestamp(); long date2 = e2.getTimestamp(); if (date1 == date2) return 0; return date1 > date2 ? 1 : -1; } return versionCollator.compare(e1.getContentIdentifier(), e2.getContentIdentifier()); case COL_BRANCHES: /* branches */ ITag[] branches1 = e1.getBranches(); ITag[] 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 */ ITag[] tags1 = e1.getTags(); ITag[] 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 */ long date1 = e1.getTimestamp(); long date2 = e2.getTimestamp(); if (date1 == date2) return 0; return date1 > date2 ? 1 : -1; case COL_AUTHOR: /* author */ String author1 = e1.getAuthor(); String author2 = e2.getAuthor(); if (author2 == null) return -1; if (author1 == null) return 1; return getComparator().compare(author1, author2); case COL_COMMENT: /* comment */ String comment1 = e1.getComment(); String comment2 = e2.getComment(); if (comment2 == null) return -1; if (comment1 == null) return 1; return getComparator().compare(comment1, comment2); 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 IFileRevision adaptToFileRevision(Object element) { // Get the log entry for the provided object IFileRevision entry = null; if (element instanceof IFileRevision) { entry = (IFileRevision) element; } else if (element instanceof IAdaptable) { entry = (IFileRevision) ((IAdaptable) element).getAdapter(IFileRevision.class); } else if (element instanceof AbstractHistoryCategory) { if (((AbstractHistoryCategory) element).hasRevisions()) entry = ((AbstractHistoryCategory) element).getRevisions()[0]; } return entry; } /** * Create a TableViewer that can be used to display a list of IFileRevision instances. * Ths 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(true); GridData data = new GridData(GridData.FILL_BOTH); tree.setLayoutData(data); TableLayout layout = new TableLayout(true); tree.setLayout(layout); this.viewer = new TreeViewer(tree); createColumns(viewer, layout); // Initialize the sorting ColumnViewerToolTipSupport.enableFor(viewer); viewer.refresh(); tree.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (currentRevisionFont != null) { currentRevisionFont.dispose(); } } }); return viewer; } /** * Creates the columns for the history table. */ private void createColumns(TreeViewer tree, TableLayout layout) { SelectionListener headerListener = getColumnListener(viewer); // revision TreeViewerColumn viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_REVISIONID, this)); TreeColumn col = viewerCol.getColumn(); col.setData(COL_NAME, COL_REVISIONID_NAME); col.setResizable(true); col.setText(TeamUIMessages.GenericHistoryTableProvider_Revision); col.addSelectionListener(headerListener); // branches viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_BRANCHES, this)); col = viewerCol.getColumn(); col.setData(COL_NAME, COL_BRANCHES_NAME); col.setResizable(true); col.setText(CVSUIMessages.HistoryView_branches); col.addSelectionListener(headerListener); // tags viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_TAGS, this)); col = viewerCol.getColumn(); col.setData(COL_NAME, COL_TAGS_NAME); col.setResizable(true); col.setText(CVSUIMessages.HistoryView_tags); col.addSelectionListener(headerListener); // creation date viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_DATE, this)); col = viewerCol.getColumn(); col.setData(COL_NAME, COL_DATE_NAME); col.setResizable(true); col.setText(TeamUIMessages.GenericHistoryTableProvider_RevisionTime); col.addSelectionListener(headerListener); // author viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_AUTHOR, this)); col = viewerCol.getColumn(); col.setData(COL_NAME, COL_AUTHOR_NAME); col.setResizable(true); col.setText(TeamUIMessages.GenericHistoryTableProvider_Author); col.addSelectionListener(headerListener); //comment viewerCol = new TreeViewerColumn(tree, SWT.NONE); viewerCol.setLabelProvider(new HistoryLabelProvider(COL_COMMENT, this)); col = viewerCol.getColumn(); col.setData(COL_NAME, COL_COMMENT_NAME); col.setResizable(true); col.setText(TeamUIMessages.GenericHistoryTableProvider_Comment); col.addSelectionListener(headerListener); loadColumnLayout(layout); } public void loadColumnLayout(TableLayout layout) { int widths[] = new int[] { getSettingsInt(COL_REVISIONID_NAME), getSettingsInt(COL_BRANCHES_NAME), getSettingsInt(COL_TAGS_NAME), getSettingsInt(COL_DATE_NAME), getSettingsInt(COL_AUTHOR_NAME), getSettingsInt(COL_COMMENT_NAME) }; ColumnLayoutData weightData[] = getWeightData(widths); for (int i = 0; i < weightData.length; i++) { layout.addColumnData(weightData[i]); } String sortName = settings.get(SORT_COL_NAME); if (sortName == null) { sortName = COL_DATE_NAME; } int sortDirection = SWT.DOWN; try { sortDirection = settings.getInt(SORT_COL_DIRECTION); } catch (NumberFormatException e) { // Silently ignored } TreeColumn sortColumn = null; int columnNumber = 0; TreeColumn columns[] = viewer.getTree().getColumns(); for (int i = 0; i < columns.length; i++) { if (columns[i].getData(COL_NAME).equals(sortName)) { sortColumn = columns[i]; columnNumber = i; } } viewer.getTree().setSortColumn(sortColumn); viewer.getTree().setSortDirection(sortDirection); HistoryComparator sorter = new HistoryComparator(columnNumber); sorter.setReversed(sortDirection == SWT.DOWN); viewer.setComparator(sorter); } private int getSettingsInt(String key) { String value = settings.get(key); int ret = 0; try { ret = Integer.parseInt(value); } catch (NumberFormatException e) { ret = -1; } return ret; } private ColumnLayoutData[] getWeightData(int[] widths) { boolean reset = true; for (int i = 0; i < widths.length; i++) { if (widths[i] > 0) { reset = false; break; } } ColumnLayoutData[] ret = new ColumnLayoutData[widths.length]; for (int i = 0; i < widths.length; i++) { if (reset) { // use same weight for all columns ret[i] = new ColumnWeightData(10, true); } else { if (widths[i] < 0) ret[i] = new ColumnPixelData(getWidthForColumn(i)); else ret[i] = new ColumnPixelData(widths[i]); } } return ret; } private int getWidthForColumn(int i) { // see #createColumns int chars = 4; switch (i) { case COL_REVISIONID: chars += TeamUIMessages.GenericHistoryTableProvider_Revision.length(); break; case COL_BRANCHES: chars += CVSUIMessages.HistoryView_branches.length(); break; case COL_TAGS: chars += CVSUIMessages.HistoryView_tags.length(); break; case COL_DATE: chars += TeamUIMessages.GenericHistoryTableProvider_RevisionTime.length(); break; case COL_AUTHOR: chars += TeamUIMessages.GenericHistoryTableProvider_Author.length(); break; case COL_COMMENT: chars += TeamUIMessages.GenericHistoryTableProvider_Comment.length(); break; } return new PixelConverter(viewer.getTree()).convertWidthInCharsToPixels(chars); } public void saveColumnLayout() { TreeColumn columns[] = viewer.getTree().getColumns(); for (int i = 0; i < columns.length; i++) { settings.put((String) columns[i].getData(COL_NAME), columns[i].getWidth()); } settings.put(SORT_COL_NAME, (String) viewer.getTree().getSortColumn().getData(COL_NAME)); settings.put(SORT_COL_DIRECTION, viewer.getTree().getSortDirection()); } /** * Adds the listener that sets the sorter. */ private SelectionListener getColumnListener(final TreeViewer treeViewer) { /** * 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 = treeViewer.getTree().indexOf((TreeColumn) e.widget); HistoryComparator oldSorter = (HistoryComparator) treeViewer.getComparator(); TreeColumn treeColumn = ((TreeColumn) e.widget); if (oldSorter != null && column == oldSorter.getColumnNumber()) { oldSorter.setReversed(!oldSorter.isReversed()); treeViewer.getTree().setSortColumn(treeColumn); treeViewer.getTree().setSortDirection(oldSorter.isReversed() ? SWT.DOWN : SWT.UP); treeViewer.refresh(); } else { treeViewer.getTree().setSortColumn(treeColumn); treeViewer.getTree().setSortDirection(SWT.UP); treeViewer.setComparator(new HistoryComparator(column)); } } }; } public void setFile(IFileHistory fileHistory, IFile workspaceFile) { this.currentFileHistory = fileHistory; this.workspaceFile = workspaceFile; } public IFileHistory getIFileHistory() { return this.currentFileHistory; } public String getCurrentRevision() { try { if (workspaceFile != null) { ICVSFile cvsWorkspaceFile = CVSWorkspaceRoot.getCVSFileFor(workspaceFile); byte[] syncBytes = cvsWorkspaceFile.getSyncBytes(); if (syncBytes != null) { String workspaceRevision = ResourceSyncInfo.getRevision(syncBytes); return workspaceRevision; } } } catch (CVSException e) { } return null; } public void setBaseModified(boolean modified) { this.baseModified = modified; } private static class ThemeListener implements IPropertyChangeListener { private final CVSHistoryTableProvider provider; ThemeListener(CVSHistoryTableProvider provider) { this.provider = provider; } public void propertyChange(PropertyChangeEvent event) { provider.viewer.refresh(); } } public void setWorkspaceFile(IFile workspaceFile) { this.workspaceFile = workspaceFile; } public static String getCommentAsSingleLine(IFileRevision entry) { String comment = entry.getComment(); if (comment != null) { 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$ } }