1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * 
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * The contents of this file are subject to the terms of either the Universal Permissive License
   7  * v 1.0 as shown at http://oss.oracle.com/licenses/upl
   8  *
   9  * or the following license:
  10  *
  11  * Redistribution and use in source and binary forms, with or without modification, are permitted
  12  * provided that the following conditions are met:
  13  * 
  14  * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
  15  * and the following disclaimer.
  16  * 
  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  * 
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  * 
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.flightrecorder.ui.pages;
  34 
  35 import java.awt.Color;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.List;
  39 
  40 import org.eclipse.jface.resource.ImageDescriptor;
  41 import org.eclipse.osgi.util.NLS;
  42 import org.eclipse.swt.SWT;
  43 import org.eclipse.swt.custom.CTabFolder;
  44 import org.eclipse.swt.custom.CTabItem;
  45 import org.eclipse.swt.custom.SashForm;
  46 import org.eclipse.swt.events.SelectionAdapter;
  47 import org.eclipse.swt.events.SelectionEvent;
  48 import org.eclipse.swt.widgets.Composite;
  49 import org.eclipse.ui.forms.widgets.Form;
  50 import org.eclipse.ui.forms.widgets.FormToolkit;
  51 import org.openjdk.jmc.common.IState;
  52 import org.openjdk.jmc.common.IWritableState;
  53 import org.openjdk.jmc.common.item.IItem;
  54 import org.openjdk.jmc.common.item.IItemCollection;
  55 import org.openjdk.jmc.common.item.IItemFilter;
  56 import org.openjdk.jmc.common.item.ItemFilters;
  57 import org.openjdk.jmc.common.unit.IQuantity;
  58 import org.openjdk.jmc.common.unit.IRange;
  59 import org.openjdk.jmc.common.unit.UnitLookup;
  60 import org.openjdk.jmc.common.util.ColorToolkit;
  61 import org.openjdk.jmc.flightrecorder.JfrAttributes;
  62 import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
  63 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
  64 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
  65 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  66 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
  67 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
  68 import org.openjdk.jmc.flightrecorder.ui.IDataPageFactory;
  69 import org.openjdk.jmc.flightrecorder.ui.IDisplayablePage;
  70 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
  71 import org.openjdk.jmc.flightrecorder.ui.IPageDefinition;
  72 import org.openjdk.jmc.flightrecorder.ui.IPageUI;
  73 import org.openjdk.jmc.flightrecorder.ui.ItemCollectionToolkit;
  74 import org.openjdk.jmc.flightrecorder.ui.StreamModel;
  75 import org.openjdk.jmc.flightrecorder.ui.common.AbstractDataPage;
  76 import org.openjdk.jmc.flightrecorder.ui.common.DataPageToolkit;
  77 import org.openjdk.jmc.flightrecorder.ui.common.FilterComponent;
  78 import org.openjdk.jmc.flightrecorder.ui.common.FlavorSelector;
  79 import org.openjdk.jmc.flightrecorder.ui.common.FlavorSelector.FlavorSelectorState;
  80 import org.openjdk.jmc.flightrecorder.ui.common.ImageConstants;
  81 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram;
  82 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram.HistogramSelection;
  83 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram.ItemHistogramBuilder;
  84 import org.openjdk.jmc.flightrecorder.ui.common.ItemList;
  85 import org.openjdk.jmc.flightrecorder.ui.common.ItemList.ItemListBuilder;
  86 import org.openjdk.jmc.flightrecorder.ui.common.TypeLabelProvider;
  87 import org.openjdk.jmc.flightrecorder.ui.messages.internal.Messages;
  88 import org.openjdk.jmc.flightrecorder.ui.selection.SelectionStoreActionToolkit;
  89 import org.openjdk.jmc.ui.charts.IXDataRenderer;
  90 import org.openjdk.jmc.ui.charts.RendererToolkit;
  91 import org.openjdk.jmc.ui.charts.XYChart;
  92 import org.openjdk.jmc.ui.column.ColumnManager.SelectionState;
  93 import org.openjdk.jmc.ui.column.ColumnMenusFactory;
  94 import org.openjdk.jmc.ui.column.TableSettings;
  95 import org.openjdk.jmc.ui.column.TableSettings.ColumnSettings;
  96 import org.openjdk.jmc.ui.handlers.MCContextMenuManager;
  97 import org.openjdk.jmc.ui.misc.ChartCanvas;
  98 import org.openjdk.jmc.ui.misc.PersistableSashForm;
  99 
 100 public class FileIOPage extends AbstractDataPage {
 101         public static class FileIOPageFactory implements IDataPageFactory {
 102 
 103                 @Override
 104                 public String getName(IState state) {
 105                         return Messages.FileIOPage_PAGE_NAME;
 106                 }
 107 
 108                 @Override
 109                 public ImageDescriptor getImageDescriptor(IState state) {
 110                         return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_IO);
 111                 }
 112 
 113                 @Override
 114                 public String[] getTopics(IState state) {
 115                         return new String[] {JfrRuleTopics.FILE_IO_TOPIC};
 116                 }
 117 
 118                 @Override
 119                 public IDisplayablePage createPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
 120                         return new FileIOPage(dpd, items, editor);
 121                 }
 122 
 123         }
 124 
 125         private static final Color WRITE_COLOR = TypeLabelProvider.getColor(JdkTypeIDs.FILE_WRITE);
 126         private static final Color READ_COLOR = TypeLabelProvider.getColor(JdkTypeIDs.FILE_READ);
 127         private static final Color WRITE_ALPHA_COLOR = ColorToolkit.withAlpha(WRITE_COLOR, 80);
 128         private static final Color READ_ALPHA_COLOR = ColorToolkit.withAlpha(READ_COLOR, 80);
 129         private static final IItemFilter TABLE_ITEMS = ItemFilters.type(JdkTypeIDs.FILE_READ, JdkTypeIDs.FILE_WRITE);
 130         private static final String TOTAL_TIME = "totalTime"; //$NON-NLS-1$
 131         private static final String MAX_TIME = "maxTime"; //$NON-NLS-1$
 132         private static final String AVG_TIME = "avgTime"; //$NON-NLS-1$
 133         private static final String STDDEV_TIME = "stddevTime"; //$NON-NLS-1$
 134         private static final String READ_COUNT = "readCount"; //$NON-NLS-1$
 135         private static final String WRITE_COUNT = "writeCount"; //$NON-NLS-1$
 136         private static final String READ_SIZE = "readSize"; //$NON-NLS-1$
 137         private static final String WRITE_SIZE = "writeSize"; //$NON-NLS-1$
 138         private static final String READ_EOF = "endOfFile"; //$NON-NLS-1$
 139 
 140         private static final ItemHistogramBuilder HISTOGRAM = new ItemHistogramBuilder();
 141         private static final ItemListBuilder LIST = new ItemListBuilder();
 142 
 143         static {
 144                 HISTOGRAM.addCountColumn();
 145                 HISTOGRAM.addColumn(TOTAL_TIME, JdkAggregators.TOTAL_IO_TIME);
 146                 HISTOGRAM.addColumn(MAX_TIME, JdkAggregators.MAX_IO_TIME);
 147                 HISTOGRAM.addColumn(AVG_TIME, JdkAggregators.AVG_IO_TIME);
 148                 HISTOGRAM.addColumn(STDDEV_TIME, JdkAggregators.STDDEV_IO_TIME);
 149                 HISTOGRAM.addColumn(READ_COUNT, JdkAggregators.FILE_READ_COUNT);
 150                 HISTOGRAM.addColumn(WRITE_COUNT, JdkAggregators.FILE_WRITE_COUNT);
 151                 HISTOGRAM.addColumn(READ_SIZE, JdkAggregators.FILE_READ_SIZE);
 152                 HISTOGRAM.addColumn(WRITE_SIZE, JdkAggregators.FILE_WRITE_SIZE);
 153                 LIST.addColumn(JdkAttributes.IO_PATH);
 154                 LIST.addColumn(JfrAttributes.START_TIME);
 155                 LIST.addColumn(JfrAttributes.END_TIME);
 156                 LIST.addColumn(JfrAttributes.DURATION);
 157                 LIST.addColumn(JdkAttributes.IO_FILE_BYTES_READ);
 158                 LIST.addColumn(JdkAttributes.IO_FILE_BYTES_WRITTEN);
 159                 LIST.addColumn(JfrAttributes.EVENT_THREAD);
 160                 LIST.addColumn(JdkAttributes.IO_FILE_READ_EOF);
 161         }
 162 
 163         private class IOPageUi implements IPageUI {
 164                 private static final String FILE_IO_TABLE = "fileIoTable"; //$NON-NLS-1$
 165                 private static final String FILE_IO_LIST = "fileIoList"; //$NON-NLS-1$
 166                 private static final String SASH_ELEMENT = "sash"; //$NON-NLS-1$
 167                 private static final String LIST_ELEMENT = "eventList"; //$NON-NLS-1$
 168                 private static final String TABLE_ELEMENT = "table"; //$NON-NLS-1$
 169 
 170                 private final ChartCanvas timelineCanvas;
 171                 private final ChartCanvas durationCanvas;
 172                 private XYChart timelineChart;
 173                 private IRange<IQuantity> timeRange;
 174                 private IItemCollection selectionItems;
 175                 private final ItemList itemList;
 176                 private final ItemHistogram table;
 177                 private final SashForm sash;
 178                 private final IPageContainer pageContainer;
 179                 private FilterComponent tableFilter;
 180                 private FilterComponent itemListFilter;
 181                 private FlavorSelector flavorSelector;
 182 
 183                 IOPageUi(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
 184                         this.pageContainer = pageContainer;
 185                         Form form = DataPageToolkit.createForm(parent, toolkit, getName(), getIcon());
 186                         sash = new SashForm(form.getBody(), SWT.VERTICAL);
 187                         toolkit.adapt(sash);
 188 
 189                         addResultActions(form);
 190 
 191                         table = HISTOGRAM.buildWithoutBorder(sash, JdkAttributes.IO_PATH,
 192                                         getTableSettings(state.getChild(TABLE_ELEMENT)));
 193                         MCContextMenuManager mm = MCContextMenuManager.create(table.getManager().getViewer().getControl());
 194                         ColumnMenusFactory.addDefaultMenus(table.getManager(), mm);
 195                         SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), table,
 196                                         Messages.FileIOPage_HISTOGRAM_SELECTION, mm);
 197                         table.getManager().getViewer().addSelectionChangedListener(e -> updateDetails());
 198                         table.getManager().getViewer()
 199                                         .addSelectionChangedListener(e -> pageContainer.showSelection(table.getSelection().getItems()));
 200                         tableFilter = FilterComponent.createFilterComponent(table, FileIOPage.this.tableFilter,
 201                                         getDataSource().getItems().apply(TABLE_ITEMS), pageContainer.getSelectionStore()::getSelections,
 202                                         this::onTableFilterChange);
 203                         mm.add(tableFilter.getShowFilterAction());
 204                         mm.add(tableFilter.getShowSearchAction());
 205 
 206                         CTabFolder tabFolder = new CTabFolder(sash, SWT.NONE);
 207                         toolkit.adapt(tabFolder);
 208                         CTabItem t1 = new CTabItem(tabFolder, SWT.NONE);
 209                         t1.setToolTipText(Messages.IO_PAGE_TIMELINE_DESCRIPTION);
 210                         timelineCanvas = new ChartCanvas(tabFolder);
 211                         t1.setText(Messages.PAGES_TIMELINE);
 212                         t1.setControl(timelineCanvas);
 213                         DataPageToolkit.createChartTimestampTooltip(timelineCanvas);
 214 
 215                         CTabItem t2 = new CTabItem(tabFolder, SWT.NONE);
 216                         t2.setToolTipText(Messages.IO_PAGE_DURATIONS_DESCRIPTION);
 217                         durationCanvas = new ChartCanvas(tabFolder);
 218                         t2.setText(Messages.PAGES_DURATIONS);
 219                         t2.setControl(durationCanvas);
 220                         DataPageToolkit.createChartTooltip(durationCanvas);
 221 
 222                         CTabItem t3 = new CTabItem(tabFolder, SWT.NONE);
 223                         t3.setToolTipText(Messages.IO_PAGE_EVENT_LOG_DESCRIPTION);
 224                         itemList = LIST.buildWithoutBorder(tabFolder, getTableSettings(state.getChild(LIST_ELEMENT)));
 225                         MCContextMenuManager itemListMm = MCContextMenuManager
 226                                         .create(itemList.getManager().getViewer().getControl());
 227                         ColumnMenusFactory.addDefaultMenus(itemList.getManager(), itemListMm);
 228                         SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), itemList,
 229                                         Messages.FileIOPage_LOG_SELECTION, itemListMm);
 230                         itemList.getManager().getViewer().addSelectionChangedListener(
 231                                         e -> pageContainer.showSelection(ItemCollectionToolkit.build(itemList.getSelection().get())));
 232                         t3.setText(Messages.PAGES_EVENT_LOG);
 233                         itemListFilter = FilterComponent.createFilterComponent(itemList, FileIOPage.this.itemListFilter,
 234                                         getDataSource().getItems().apply(TABLE_ITEMS), pageContainer.getSelectionStore()::getSelections,
 235                                         this::onListFilterChange);
 236                         itemListMm.add(itemListFilter.getShowFilterAction());
 237                         itemListMm.add(itemListFilter.getShowSearchAction());
 238                         t3.setControl(itemListFilter.getComponent());
 239 
 240                         tableFilter.loadState(state.getChild(FILE_IO_TABLE));
 241                         itemListFilter.loadState(state.getChild(FILE_IO_LIST));
 242 
 243                         tabFolder.setSelection(tabFolderIndex);
 244                         tabFolder.addSelectionListener(new SelectionAdapter() {
 245                                 @Override
 246                                 public void widgetSelected(SelectionEvent e) {
 247                                         tabFolderIndex = ((CTabFolder) e.getSource()).getSelectionIndex();
 248                                 }
 249                         });
 250 
 251                         timelineChart = createTimelineChart(pageContainer);
 252                         hookUpTimeLineChart();
 253                         PersistableSashForm.loadState(sash, state.getChild(SASH_ELEMENT));
 254 
 255                         flavorSelector = FlavorSelector.itemsWithTimerange(form, TABLE_ITEMS, getDataSource().getItems(),
 256                                         pageContainer, this::onInputSelected, this::onShowFlavor, flavorSelectorState);
 257 
 258                         table.getManager().setSelectionState(tableSelection);
 259                         itemList.getManager().setSelectionState(itemListSelection);
 260                 }
 261 
 262                 private XYChart createTimelineChart(IPageContainer pageContainer) {
 263                         XYChart timelineChart = new XYChart(pageContainer.getRecordingRange(), RendererToolkit.empty(), 180);
 264                         timelineChart.setVisibleRange(timelineRange.getStart(), timelineRange.getEnd());
 265                         timelineChart.addVisibleRangeListener(range -> timelineRange = range);
 266                         return timelineChart;
 267                 }
 268 
 269                 private void onTableFilterChange(IItemFilter filter) {
 270                         tableFilter.filterChangeHelper(filter, table, getDataSource().getItems().apply(TABLE_ITEMS));
 271                         itemListFilter.notifyListener();
 272                         FileIOPage.this.tableFilter = filter;
 273                 }
 274 
 275                 private void onListFilterChange(IItemFilter filter) {
 276                         itemListFilter.filterChangeHelper(filter, itemList, getDataSource().getItems().apply(TABLE_ITEMS));
 277                         FileIOPage.this.itemListFilter = filter;
 278                 }
 279 
 280                 @Override
 281                 public void saveTo(IWritableState writableState) {
 282                         PersistableSashForm.saveState(sash, writableState.createChild(SASH_ELEMENT));
 283                         table.getManager().getSettings().saveState(writableState.createChild(TABLE_ELEMENT));
 284                         tableFilter.saveState(writableState.createChild(FILE_IO_TABLE));
 285                         itemList.getManager().getSettings().saveState(writableState.createChild(LIST_ELEMENT));
 286                         itemListFilter.saveState(writableState.createChild(FILE_IO_LIST));
 287 
 288                         saveToLocal();
 289                 }
 290 
 291                 private void saveToLocal() {
 292                         tableSelection = table.getManager().getSelectionState();
 293                         itemListSelection = itemList.getManager().getSelectionState();
 294                         flavorSelectorState = flavorSelector.getFlavorSelectorState();
 295                 }
 296 
 297                 private void onShowFlavor(Boolean show) {
 298                         IRange<IQuantity> range = show ? timeRange : pageContainer.getRecordingRange();
 299                         timelineChart.setVisibleRange(range.getStart(), range.getEnd());
 300                         hookUpTimeLineChart();
 301                 }
 302 
 303                 private void hookUpTimeLineChart() {
 304                         DataPageToolkit.setChart(timelineCanvas, timelineChart, pageContainer::showSelection);
 305                         SelectionStoreActionToolkit.addSelectionStoreRangeActions(pageContainer.getSelectionStore(), timelineChart,
 306                                         JfrAttributes.LIFETIME, Messages.FileIOPage_TIMELINE_SELECTION, timelineCanvas.getContextMenu());
 307                 }
 308 
 309                 private void onInputSelected(IItemCollection items, IRange<IQuantity> timeRange) {
 310                         this.selectionItems = items;
 311                         this.timeRange = timeRange;
 312                         updateDetails();
 313                 }
 314 
 315                 private void updateDetails() {
 316                         IItemCollection items = selectionItems != null ? selectionItems.apply(TABLE_ITEMS)
 317                                         : getDataSource().getItems().apply(TABLE_ITEMS);
 318                         table.show(items);
 319                         HistogramSelection histogramSelection = table.getSelection();
 320                         IItemCollection selectedItems = histogramSelection.getRowCount() == 0 ? items
 321                                         : histogramSelection.getItems();
 322 
 323                         String pathCount = pathCount(histogramSelection.getRowCount());
 324                         List<IXDataRenderer> timelineRows = new ArrayList<>();
 325                         List<IXDataRenderer> durationRows = new ArrayList<>();
 326                         IItemCollection readItems = selectedItems.apply(JdkFilters.FILE_READ);
 327                         if (readItems.hasItems()) {
 328                                 timelineRows.add(DataPageToolkit.buildSizeRow(Messages.FileIOPage_ROW_FILE_READ + pathCount,
 329                                                 JdkAggregators.FILE_READ_SIZE.getDescription(), readItems, JdkAggregators.FILE_READ_SIZE,
 330                                                 READ_COLOR, FileIOPage::getColor));
 331                                 durationRows.add(DataPageToolkit.buildDurationHistogram(Messages.FileIOPage_ROW_FILE_READ + pathCount,
 332                                                 JdkAggregators.FILE_READ_COUNT.getDescription(), readItems, JdkAggregators.FILE_READ_COUNT,
 333                                                 READ_COLOR));
 334                         }
 335                         IItemCollection writeItems = selectedItems.apply(JdkFilters.FILE_WRITE);
 336                         if (writeItems.hasItems()) {
 337                                 timelineRows.add(DataPageToolkit.buildSizeRow(Messages.FileIOPage_ROW_FILE_WRITE + pathCount,
 338                                                 JdkAggregators.FILE_WRITE_SIZE.getDescription(), writeItems, JdkAggregators.FILE_WRITE_SIZE,
 339                                                 WRITE_COLOR, FileIOPage::getColor));
 340                                 durationRows.add(DataPageToolkit.buildDurationHistogram(Messages.FileIOPage_ROW_FILE_WRITE + pathCount,
 341                                                 JdkAggregators.FILE_WRITE_COUNT.getDescription(), writeItems, JdkAggregators.FILE_WRITE_COUNT,
 342                                                 WRITE_COLOR));
 343                         }
 344 //                      ItemRow[] pathRows = selection.getSelectedRows(FileIOPage::buildPathLane).toArray(ItemRow[]::new);
 345 
 346                         timelineCanvas.replaceRenderer(RendererToolkit.uniformRows(timelineRows));
 347 
 348                         IXDataRenderer durationRoot = RendererToolkit.uniformRows(durationRows);
 349                         // FIXME: X-auto-range should be done properly
 350                         IQuantity max = selectedItems.getAggregate(JdkAggregators.LONGEST_EVENT);
 351                         // FIXME: Workaround to make max value included
 352                         max = max == null ? UnitLookup.MILLISECOND.quantity(20) : max.add(UnitLookup.MILLISECOND.quantity(20));
 353                         XYChart durationChart = new XYChart(UnitLookup.MILLISECOND.quantity(0), max, durationRoot, 180);
 354                         DataPageToolkit.setChart(durationCanvas, durationChart, JfrAttributes.DURATION,
 355                                         selection -> pageContainer.showSelection(selection));
 356                         durationChart.setVisibleRange(durationRange.getStart(), durationRange.getEnd());
 357                         durationChart.addVisibleRangeListener(range -> durationRange = range);
 358                         durationCanvas.setChart(durationChart);
 359                         SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), durationChart,
 360                                         JfrAttributes.DURATION, Messages.FileIOPage_DURATION_SELECTION, durationCanvas.getContextMenu());
 361                         itemList.show(selectedItems);
 362                 }
 363         }
 364 
 365         private static TableSettings getTableSettings(IState state) {
 366                 if (state == null) {
 367                         return new TableSettings(TOTAL_TIME, Arrays.asList(
 368                                         new ColumnSettings(ItemHistogram.KEY_COL_ID, false, 500, null),
 369                                         new ColumnSettings(TOTAL_TIME, true, 120, false), new ColumnSettings(MAX_TIME, false, 120, false),
 370                                         new ColumnSettings(AVG_TIME, false, 120, false), new ColumnSettings(STDDEV_TIME, false, 120, false),
 371                                         new ColumnSettings(READ_COUNT, false, 120, false),
 372                                         new ColumnSettings(WRITE_COUNT, false, 120, false),
 373                                         new ColumnSettings(READ_SIZE, false, 120, false), new ColumnSettings(WRITE_SIZE, false, 120, false),
 374                                         new ColumnSettings(READ_EOF, false, 80, false)));
 375                 } else {
 376                         return new TableSettings(state);
 377                 }
 378         }
 379 
 380         @Override
 381         public IPageUI display(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
 382                 return new IOPageUi(parent, toolkit, pageContainer, state);
 383         }
 384 
 385         private SelectionState tableSelection;
 386         private SelectionState itemListSelection;
 387         private IItemFilter tableFilter = null;
 388         private IItemFilter itemListFilter = null;
 389         private int tabFolderIndex = 0;
 390         private IRange<IQuantity> timelineRange;
 391         private IRange<IQuantity> durationRange;
 392         public FlavorSelectorState flavorSelectorState;
 393 
 394         public FileIOPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
 395                 super(dpd, items, editor);
 396                 timelineRange = editor.getRecordingRange();
 397                 durationRange = editor.getRecordingRange();
 398         }
 399 
 400 //      private static ItemRow buildPathLane(Object path, Supplier<Stream<ItemStream>> pathItems) {
 401 //              String pathName = String.valueOf(path);
 402 //              pathName = pathName.length() > 26 ? pathName.substring(0, 23) + "..." : pathName; //$NON-NLS-1$
 403 //              return new ItemRow(pathName, buildSpanRenderer(pathItems), pathItems);
 404 //      }
 405 
 406         private static Color getColor(IItem item) {
 407                 return JdkTypeIDs.FILE_READ.equals(item.getType().getIdentifier()) ? READ_ALPHA_COLOR : WRITE_ALPHA_COLOR;
 408         }
 409 
 410         @Override
 411         public IItemFilter getDefaultSelectionFilter() {
 412                 return TABLE_ITEMS;
 413         }
 414 
 415         private static String pathCount(int count) {
 416                 switch (count) {
 417                 case 0:
 418                         return ""; //$NON-NLS-1$
 419                 case 1:
 420                         return " (" + Messages.FileIOPage_SELECTED_PATH + ")"; //$NON-NLS-1$ //$NON-NLS-2$
 421                 default:
 422                         return " (" + NLS.bind(Messages.FileIOPage_SELECTED_PATHS, count) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
 423                 }
 424         }
 425 }