| /******************************************************************************* |
| * Copyright (c) 2008 The Eclipse Foundation. |
| * 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: |
| * The Eclipse Foundation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.epp.usagedata.internal.ui.preview; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Date; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.epp.usagedata.internal.gathering.events.UsageDataEvent; |
| import org.eclipse.epp.usagedata.internal.recording.filtering.FilterChangeListener; |
| import org.eclipse.epp.usagedata.internal.recording.filtering.FilterUtils; |
| import org.eclipse.epp.usagedata.internal.recording.filtering.PreferencesBasedFilter; |
| import org.eclipse.epp.usagedata.internal.recording.uploading.UploadParameters; |
| import org.eclipse.epp.usagedata.internal.recording.uploading.UsageDataFileReader; |
| import org.eclipse.epp.usagedata.internal.ui.Activator; |
| import org.eclipse.jface.viewers.ColumnLabelProvider; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.TableViewerColumn; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerSorter; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.PaintEvent; |
| import org.eclipse.swt.events.PaintListener; |
| 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.Cursor; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.layout.RowLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableColumn; |
| import org.eclipse.ui.forms.widgets.FormText; |
| |
| import com.ibm.icu.text.DateFormat; |
| |
| public class UploadPreview { |
| |
| private final UploadParameters parameters; |
| |
| TableViewer viewer; |
| Job contentJob; |
| List<UsageDataEventWrapper> events = Collections.synchronizedList(new ArrayList<UsageDataEventWrapper>()); |
| |
| private static final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); |
| |
| private UsageDataTableViewerColumn includeColumn; |
| private UsageDataTableViewerColumn whatColumn; |
| private UsageDataTableViewerColumn kindColumn; |
| private UsageDataTableViewerColumn descriptionColumn; |
| private UsageDataTableViewerColumn bundleIdColumn; |
| private UsageDataTableViewerColumn bundleVersionColumn; |
| private UsageDataTableViewerColumn timestampColumn; |
| |
| private Color colorGray; |
| private Color colorBlack; |
| private Image xImage; |
| |
| private Cursor busyCursor; |
| |
| Button removeFilterButton; |
| |
| private Button eclipseOnlyButton; |
| |
| private Button addFilterButton; |
| |
| public UploadPreview(UploadParameters parameters) { |
| this.parameters = parameters; |
| } |
| |
| public Control createControl(final Composite parent) { |
| allocateResources(parent); |
| |
| Composite composite = new Composite(parent, SWT.NONE); |
| composite.setLayout(new GridLayout()); |
| |
| createDescriptionText(composite); |
| createEventsTable(composite); |
| createEclipseOnlyButton(composite); |
| createButtons(composite); |
| |
| /* |
| * Bit of a crazy idea. Add a paint listener that will |
| * start the job of actually populating the page when |
| * the composite is exposed. If the instance is created |
| * in a wizard, it won't start populating until the user |
| * actually switches to the page. |
| */ |
| final PaintListener paintListener = new PaintListener() { |
| boolean called = false; |
| // Don't need to synchronize since this will only ever be called in the UI thread. |
| public void paintControl(PaintEvent e) { |
| if (called) return; |
| called = true; |
| startContentJob(); |
| } |
| }; |
| composite.addPaintListener(paintListener); |
| |
| return composite; |
| } |
| |
| /* |
| * This method allocates the resources used by the receiver. |
| * It installs a dispose listener on parent so that when |
| * the parent is disposed, the allocated resources will be |
| * deallocated. |
| */ |
| private void allocateResources(Composite parent) { |
| colorGray = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY); |
| colorBlack = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK); |
| busyCursor = parent.getDisplay().getSystemCursor(SWT.CURSOR_WAIT); |
| |
| xImage = Activator.getDefault().getImageDescriptor("/icons/x.png").createImage(parent.getDisplay()); //$NON-NLS-1$ |
| |
| parent.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| xImage.dispose(); |
| } |
| }); |
| } |
| |
| private void createDescriptionText(Composite parent) { |
| FormText text = new FormText(parent, SWT.NONE); |
| text.setImage("x", xImage); //$NON-NLS-1$ |
| text.setText(Messages.UploadPreview_2, true, false); |
| GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false); |
| layoutData.widthHint = 500; |
| text.setLayoutData(layoutData); |
| } |
| |
| private void createEventsTable(Composite parent) { |
| viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); |
| viewer.getTable().setHeaderVisible(true); |
| viewer.getTable().setLinesVisible(false); |
| GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); |
| layoutData.widthHint = 500; |
| viewer.getTable().setLayoutData(layoutData); |
| |
| createIncludeColumn(); |
| createWhatColumn(); |
| createKindColumn(); |
| createDescriptionColumn(); |
| createBundleIdColumn(); |
| createBundleVersionColumn(); |
| createTimestampColumn(); |
| |
| timestampColumn.setSortColumn(); |
| |
| viewer.setContentProvider(new IStructuredContentProvider() { |
| public void dispose() { |
| } |
| |
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { |
| } |
| |
| @SuppressWarnings("unchecked") |
| public Object[] getElements(Object input) { |
| if (input instanceof List) { |
| return (Object[]) ((List<UsageDataEventWrapper>)input).toArray(new Object[((List<UsageDataEventWrapper>)input).size()]); |
| } |
| return new Object[0]; |
| } |
| }); |
| |
| /* |
| * Add a FilterChangeListener to the filter; if the filter changes, we need to |
| * refresh the display. The dispose listener, added to the table will clean |
| * up the FilterChangeListener when the table is disposed. |
| */ |
| final FilterChangeListener filterChangeListener = new FilterChangeListener() { |
| public void filterChanged() { |
| for (UsageDataEventWrapper event : events) { |
| event.resetCaches(); |
| } |
| viewer.refresh(); |
| } |
| }; |
| parameters.getFilter().addFilterChangeListener(filterChangeListener); |
| |
| viewer.getTable().addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| parameters.getFilter().removeFilterChangeListener(filterChangeListener); |
| } |
| }); |
| |
| // Initially, we have nothing. |
| viewer.setInput(events); |
| } |
| |
| private void createIncludeColumn() { |
| includeColumn = new UsageDataTableViewerColumn(SWT.CENTER); |
| includeColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public Image getImage(UsageDataEventWrapper event) { |
| if (!event.isIncludedByFilter()) return xImage; |
| return null; |
| } |
| }); |
| } |
| |
| private void createWhatColumn() { |
| whatColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| whatColumn.setText(Messages.UploadPreview_3); |
| whatColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return event.getWhat(); |
| } |
| }); |
| } |
| |
| private void createKindColumn() { |
| kindColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| kindColumn.setText(Messages.UploadPreview_4); |
| kindColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return event.getKind(); |
| } |
| }); |
| } |
| |
| private void createDescriptionColumn() { |
| descriptionColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| descriptionColumn.setText(Messages.UploadPreview_5); |
| descriptionColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return event.getDescription(); |
| } |
| }); |
| } |
| |
| private void createBundleIdColumn() { |
| bundleIdColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| bundleIdColumn.setText(Messages.UploadPreview_6); |
| bundleIdColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return event.getBundleId(); |
| } |
| }); |
| } |
| |
| private void createBundleVersionColumn() { |
| bundleVersionColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| bundleVersionColumn.setText(Messages.UploadPreview_7); |
| bundleVersionColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return event.getBundleVersion(); |
| } |
| }); |
| } |
| |
| private void createTimestampColumn() { |
| timestampColumn = new UsageDataTableViewerColumn(SWT.LEFT); |
| timestampColumn.setText(Messages.UploadPreview_8); |
| timestampColumn.setLabelProvider(new UsageDataColumnProvider() { |
| @Override |
| public String getText(UsageDataEventWrapper event) { |
| return dateFormat.format(new Date(event.getWhen())); |
| } |
| }); |
| timestampColumn.setSorter(new Comparator<UsageDataEventWrapper>() { |
| public int compare(UsageDataEventWrapper event1, UsageDataEventWrapper event2) { |
| if (event1.getWhen() == event2.getWhen()) return 0; |
| return event1.getWhen() > event2.getWhen() ? 1 : -1; |
| } |
| }); |
| } |
| |
| private void createButtons(Composite parent) { |
| Composite buttons = new Composite(parent, SWT.NONE); |
| GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false); |
| buttons.setLayoutData(layoutData); |
| buttons.setLayout(new RowLayout()); |
| createAddFilterButton(buttons); |
| createRemoveFilterButton(buttons); |
| |
| final FilterChangeListener filterChangeListener = new FilterChangeListener() { |
| public void filterChanged() { |
| updateButtons(); |
| } |
| }; |
| parameters.getFilter().addFilterChangeListener(filterChangeListener); |
| parent.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| parameters.getFilter().removeFilterChangeListener(filterChangeListener); |
| } |
| }); |
| updateButtons(); |
| } |
| |
| private void createEclipseOnlyButton(Composite buttons) { |
| eclipseOnlyButton = new Button(buttons, SWT.CHECK); |
| eclipseOnlyButton.setText(Messages.UploadPreview_9); |
| eclipseOnlyButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| ((PreferencesBasedFilter)parameters.getFilter()).setEclipseOnly(eclipseOnlyButton.getSelection()); |
| } |
| }); |
| } |
| |
| private void updateButtons() { |
| if (parameters.getFilter() instanceof PreferencesBasedFilter) { |
| PreferencesBasedFilter filter = (PreferencesBasedFilter)parameters.getFilter(); |
| if (filter.isEclipseOnly()) { |
| eclipseOnlyButton.setSelection(true); |
| addFilterButton.setEnabled(false); |
| removeFilterButton.setEnabled(false); |
| } else { |
| eclipseOnlyButton.setSelection(false); |
| addFilterButton.setEnabled(true); |
| removeFilterButton.setEnabled(filter.getFilterPatterns().length > 0); |
| } |
| } |
| } |
| |
| private void createAddFilterButton(Composite parent) { |
| if (parameters.getFilter() instanceof PreferencesBasedFilter) { |
| addFilterButton = new Button(parent, SWT.PUSH); |
| addFilterButton.setText(Messages.UploadPreview_10); |
| addFilterButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| new AddFilterDialog((PreferencesBasedFilter)parameters.getFilter()).prompt(viewer.getTable().getShell(), getFilterSuggestion()); |
| } |
| }); |
| } |
| } |
| |
| private void createRemoveFilterButton(Composite parent) { |
| if (parameters.getFilter() instanceof PreferencesBasedFilter) { |
| removeFilterButton = new Button(parent, SWT.PUSH); |
| removeFilterButton.setText(Messages.UploadPreview_11); |
| removeFilterButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| new RemoveFilterDialog((PreferencesBasedFilter)parameters.getFilter()).prompt(viewer.getTable().getShell()); |
| } |
| }); |
| } |
| } |
| |
| // TODO Return a more interesting suggestion based on the selection. |
| String getFilterSuggestion() { |
| IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); |
| if (selection != null) { |
| if (selection.size() == 1) { |
| return getFilterSuggestionBasedOnSingleSelection(selection); |
| } |
| if (selection.size() > 1) { |
| return getFilterSuggestionBasedOnMultipleSelection(selection); |
| } |
| } |
| |
| return FilterUtils.getDefaultFilterSuggestion(); |
| } |
| |
| String getFilterSuggestionBasedOnSingleSelection( |
| IStructuredSelection selection) { |
| return ((UsageDataEventWrapper)selection.getFirstElement()).getBundleId(); |
| } |
| |
| String getFilterSuggestionBasedOnMultipleSelection(IStructuredSelection selection) { |
| String[] names = new String[selection.size()]; |
| int index = 0; |
| for (Object event : selection.toArray()) { |
| names[index++] = ((UsageDataEventWrapper)event).getBundleId(); |
| } |
| return FilterUtils.getFilterSuggestionBasedOnBundleIds(names); |
| } |
| |
| /** |
| * This method starts the job that populates the list of |
| * events. |
| */ |
| synchronized void startContentJob() { |
| if (contentJob != null) return; |
| contentJob = new Job("Generate Usage Data Upload Preview") { //$NON-NLS-1$ |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| setTableCursor(busyCursor); |
| processFiles(monitor); |
| setTableCursor(null); |
| if (monitor.isCanceled()) return Status.CANCEL_STATUS; |
| return Status.OK_STATUS; |
| } |
| |
| private void setTableCursor(final Cursor cursor) { |
| if (isDisposed()) return; |
| getDisplay().syncExec(new Runnable() { |
| public void run() { |
| if (isDisposed()) return; |
| viewer.getTable().setCursor(cursor); |
| } |
| }); |
| } |
| }; |
| contentJob.setPriority(Job.LONG); |
| contentJob.schedule(); |
| } |
| |
| void processFiles(IProgressMonitor monitor) { |
| File[] files = parameters.getFiles(); |
| monitor.beginTask("Process Files", files.length); //$NON-NLS-1$ |
| for (File file : files) { |
| if (isDisposed()) break; |
| if (monitor.isCanceled()) break; |
| processFile(file, monitor); |
| monitor.worked(1); |
| } |
| monitor.done(); |
| } |
| |
| /** |
| * This method extracts the events found in a {@link File} |
| * and adds them to the list of events displayed by the |
| * receiver. Events are batched into groups to reduce |
| * the number of times the viewer will have to update. |
| * |
| * @param file the {@link File} to process. |
| * @param monitor the monitor. |
| */ |
| void processFile(File file, IProgressMonitor monitor) { |
| // TODO Add a progress bar to the page? |
| final List<UsageDataEventWrapper> events = new ArrayList<UsageDataEventWrapper>(); |
| UsageDataFileReader reader = null; |
| try { |
| reader = new UsageDataFileReader(file); |
| reader.iterate(monitor, new UsageDataFileReader.Iterator() { |
| public void header(String header) { |
| // Ignore the header. |
| } |
| |
| public void event(String line, UsageDataEvent event) { |
| events.add(new UsageDataEventWrapper(parameters, event)); |
| if (events.size() > 25) { |
| addEvents(events); |
| events.clear(); |
| } |
| } |
| }); |
| addEvents(events); |
| } catch (Exception e) { |
| Activator.getDefault().log(IStatus.WARNING, e, "An error occurred while trying to read %1$s", file.getAbsolutePath()); //$NON-NLS-1$ |
| } finally { |
| try { |
| reader.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| |
| boolean isDisposed() { |
| if (viewer == null) return true; |
| if (viewer.getTable() == null) return true; |
| return viewer.getTable().isDisposed(); |
| } |
| |
| /* |
| * This method adds the list of events to the master list maintained |
| * by the instance. It also updates the table. |
| */ |
| void addEvents(List<UsageDataEventWrapper> newEvents) { |
| if (isDisposed()) return; |
| events.addAll(newEvents); |
| |
| final Object[] array = (Object[]) newEvents.toArray(new Object[newEvents.size()]); |
| getDisplay().syncExec(new Runnable() { |
| public void run() { |
| if (isDisposed()) return; |
| viewer.add(array); |
| resizeColumns(array); |
| } |
| }); |
| } |
| |
| private Display getDisplay() { |
| return viewer.getTable().getDisplay(); |
| } |
| |
| /* |
| * Oddly enough, this method resizes the columns. In order to figure out how |
| * wide to make the columns, we need to use a GC (specifically, the |
| * {@link GC#textExtent(String)} method). To avoid creating too many of |
| * them, we create one in this method and pass it into the helper method |
| * {@link #resizeColumn(GC, UsageDataTableViewerColumn)} which does most of |
| * the heavy lifting. |
| * |
| * This method must be run in the UI Thread. |
| */ |
| void resizeColumns(final Object[] events) { |
| if (isDisposed()) return; |
| |
| GC gc = new GC(getDisplay()); |
| gc.setFont(viewer.getTable().getFont()); |
| resizeColumn(gc, includeColumn, events); |
| resizeColumn(gc, whatColumn, events); |
| resizeColumn(gc, kindColumn, events); |
| resizeColumn(gc, bundleIdColumn, events); |
| resizeColumn(gc, bundleVersionColumn, events); |
| resizeColumn(gc, descriptionColumn, events); |
| resizeColumn(gc, timestampColumn, events); |
| gc.dispose(); |
| } |
| |
| void resizeColumn(GC gc, UsageDataTableViewerColumn column, Object[] events) { |
| column.resize(gc, events); |
| } |
| |
| |
| |
| /** |
| * The {@link UsageDataTableViewerColumn} provides a level of abstraction |
| * for building table columns specifically for the table displaying |
| * instances of {@link UsageDataEventWrapper}. Instances automatically know how to |
| * sort themselves (ascending only) with help from the label provider. This |
| * behaviour can be overridden by providing an alternative |
| * {@link Comparator}. |
| */ |
| class UsageDataTableViewerColumn { |
| private TableViewerColumn column; |
| private UsageDataColumnProvider usageDataColumnProvider; |
| /** |
| * The default comparator knows how to compare objects based on the |
| * string value returned for each instance by the |
| * {@link UsageDataColumnProvider#getText(UsageDataEventWrapper)} |
| * method. |
| */ |
| private Comparator<UsageDataEventWrapper> comparator = new Comparator<UsageDataEventWrapper>() { |
| public int compare(UsageDataEventWrapper event1, UsageDataEventWrapper event2) { |
| if (usageDataColumnProvider == null) return 0; |
| String text1 = usageDataColumnProvider.getText(event1); |
| String text2 = usageDataColumnProvider.getText(event2); |
| |
| if (text1 == null && text2 == null) return 0; |
| if (text1 == null) return -1; |
| if (text2 == null) return 1; |
| |
| return text1.compareTo(text2); |
| } |
| }; |
| |
| private ViewerSorter sorter = new ViewerSorter() { |
| @Override |
| public int compare(Viewer viewer, Object object1, Object object2) { |
| return comparator.compare((UsageDataEventWrapper)object1, (UsageDataEventWrapper)object2); |
| } |
| }; |
| |
| private SelectionListener selectionListener = new SelectionAdapter() { |
| /** |
| * When the column is selected (clicked on by the |
| * the user, sort the table based on the value |
| * presented in that column. |
| */ |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| setSortColumn(); |
| } |
| }; |
| |
| public UsageDataTableViewerColumn(int style) { |
| column = new TableViewerColumn(viewer, style); |
| initialize(); |
| } |
| |
| public void setSortColumn() { |
| getTable().setSortColumn(getColumn()); |
| getTable().setSortDirection(SWT.DOWN); |
| viewer.setSorter(sorter); |
| } |
| |
| private void initialize() { |
| getColumn().addSelectionListener(selectionListener); |
| getColumn().setWidth(25); |
| } |
| // |
| // DeferredContentProvider getContentProvider() { |
| // return (DeferredContentProvider)viewer.getContentProvider(); |
| // } |
| |
| TableColumn getColumn() { |
| return column.getColumn(); |
| } |
| |
| Table getTable() { |
| return viewer.getTable(); |
| } |
| |
| public void setSorter(Comparator<UsageDataEventWrapper> comparator) { |
| // TODO May need to handle the case when the active comparator is changed. |
| this.comparator = comparator; |
| } |
| |
| public void resize(GC gc, Object[] objects) { |
| int width = usageDataColumnProvider.getMaximumWidth(gc, objects) + 20; |
| width = Math.max(getColumn().getWidth(), width); |
| getColumn().setWidth(width); |
| } |
| |
| public void setLabelProvider(UsageDataColumnProvider usageDataColumnProvider) { |
| this.usageDataColumnProvider = usageDataColumnProvider; |
| column.setLabelProvider(usageDataColumnProvider); |
| } |
| |
| public void setWidth(int width) { |
| getColumn().setWidth(width); |
| } |
| |
| public void setText(String text) { |
| getColumn().setText(text); |
| } |
| } |
| |
| /** |
| * The {@link UsageDataColumnProvider} is a column label provider |
| * that includes some convenience methods. |
| */ |
| abstract class UsageDataColumnProvider extends ColumnLabelProvider { |
| /** |
| * This convenience method is used to determine an appropriate |
| * width for the column based on the collection of event objects. |
| * The returned value is the maximum width (in pixels) of the |
| * text the receiver associates with each of the events. The |
| * events are provided as Object[] because converting them to |
| * {@link UsageDataEventWrapper}[] would be an unnecessary expense. |
| * |
| * @param gc a {@link GC} loaded with the font used to display the events. |
| * @param events an array of {@link UsageDataEventWrapper} instances. |
| * @return the width of the widest event |
| */ |
| public int getMaximumWidth(GC gc, Object[] events) { |
| int width = 0; |
| for (Object event : events) { |
| Point extent = gc.textExtent(getText(event)); |
| int x = extent.x; |
| Image image = getImage(event); |
| if (image != null) x += image.getBounds().width; |
| if (x > width) width = x; |
| } |
| return width; |
| } |
| |
| /** |
| * This method provides a foreground colour for the cell. |
| * The cell will be black if the filter includes the |
| * includes the provided {@link UsageDataEvent}, or gray if the filter |
| * excludes it. |
| */ |
| @Override |
| public Color getForeground(Object element) { |
| if (((UsageDataEventWrapper)element).isIncludedByFilter()) { |
| return colorBlack; |
| } else { |
| return colorGray; |
| } |
| } |
| |
| @Override |
| public String getText(Object element) { |
| return getText((UsageDataEventWrapper)element); |
| } |
| |
| @Override |
| public Image getImage(Object element) { |
| return getImage((UsageDataEventWrapper)element); |
| } |
| |
| public String getText(UsageDataEventWrapper element) { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| public Image getImage(UsageDataEventWrapper element) { |
| return null; |
| } |
| } |
| } |