/******************************************************************************* * Copyright (c) 2006, 2016 IBM Corporation. * 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 - Jeff Briggs, Henry Hughes, Ryan Morse * Red Hat Inc. - ongoing maintenance *******************************************************************************/ package org.eclipse.linuxtools.systemtap.graphing.ui.datadisplay; import java.text.MessageFormat; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.linuxtools.internal.systemtap.graphing.ui.GraphingUIPlugin; import org.eclipse.linuxtools.internal.systemtap.graphing.ui.Localization; import org.eclipse.linuxtools.internal.systemtap.graphing.ui.preferences.GraphingPreferenceConstants; import org.eclipse.linuxtools.internal.systemtap.graphing.ui.wizards.filter.AvailableFilterTypes; import org.eclipse.linuxtools.internal.systemtap.graphing.ui.wizards.filter.SelectFilterWizard; import org.eclipse.linuxtools.systemtap.graphing.core.datasets.IFilteredDataSet; import org.eclipse.linuxtools.systemtap.graphing.core.filters.IDataSetFilter; import org.eclipse.linuxtools.systemtap.structures.IFormattingStyles; import org.eclipse.linuxtools.systemtap.structures.StringFormatter; import org.eclipse.linuxtools.systemtap.structures.listeners.IUpdateListener; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuAdapter; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; public class DataGrid implements IUpdateListener { public static final int NONE = 0; public static final int FULL_UPDATE = 1; private IFilteredDataSet filteredDataSet; private IFormattingStyles columnFormat[]; private Table table; private Point clickLocation; private IPreferenceStore prefs; private Menu filterMenu; private MenuItem autoResizeMenuItem; private MenuItem jumpToEntryMenuItem; private MenuItem removeFiltersMenuItem; private MenuItem formatMenuItem; private IPropertyChangeListener propertyChangeListener; /** * @param composite The {@link Composite} in which the grid will reside. * @param set The data set this grid is associated with. * @since 3.0 set must be a IFilteredDataSet. */ public DataGrid(Composite composite, IFilteredDataSet set) { prefs = GraphingUIPlugin.getDefault().getPreferenceStore(); filteredDataSet = set; clickLocation = new Point(-1, -1); createPartControl(composite); propertyChangeListener = event -> { if (event.getProperty().equals(GraphingPreferenceConstants.P_MAX_DATA_ITEMS)) { handleUpdateEvent(); } }; prefs.addPropertyChangeListener(propertyChangeListener); } public Control getControl() { return table; } private void createPartControl(Composite parent) { table = new Table(parent, SWT.SINGLE | SWT.FULL_SELECTION); table.setHeaderVisible(true); table.setLinesVisible(true); table.getVerticalBar().setVisible(true); String[] names = filteredDataSet.getTitles(); TableColumn column = new TableColumn(table, SWT.LEFT); column.setText(Localization.getString("DataGrid.Row")); //$NON-NLS-1$ column.pack(); column.setMoveable(false); column.setResizable(false); columnFormat = new IFormattingStyles[names.length]; for (int i = 0; i < names.length; i++) { column = new TableColumn(table, SWT.LEFT); column.setText(names[i]); column.pack(); column.setMoveable(true); columnFormat[i] = new StringFormatter(); } table.setMenu(this.initMenus()); table.addListener(SWT.MouseDown, event -> { clickLocation.x = event.x; clickLocation.y = event.y; }); handleUpdateEvent(); } private Menu initMenus() { Menu menu = new Menu(table.getShell(), SWT.POP_UP); Menu formatMenu = new Menu(menu); formatMenuItem = new MenuItem(menu, SWT.CASCADE); formatMenuItem.setText(Localization.getString("DataGrid.FormatAs")); //$NON-NLS-1$ formatMenuItem.setMenu(formatMenu); filterMenu = new Menu(menu); MenuItem item = new MenuItem(menu, SWT.CASCADE); item.setText(Localization.getString("DataGrid.AddFilter")); //$NON-NLS-1$ item.addSelectionListener(new AddFilterSelection()); removeFiltersMenuItem = new MenuItem(menu, SWT.CASCADE); removeFiltersMenuItem.setText(Localization.getString("DataGrid.RemoveFilter")); //$NON-NLS-1$ removeFiltersMenuItem.setMenu(filterMenu); IDataSetFilter[] filters = filteredDataSet.getFilters(); if (filters != null && filters.length > 0) { for (int i = 0; i < filters.length; i++) { item = new MenuItem(filterMenu, SWT.CASCADE); item.setText(AvailableFilterTypes.getFilterName(filters[i].getID())); item.setData(filters[i]); item.addSelectionListener(new RemoveFilterSelection()); } } else { removeFiltersMenuItem.setEnabled(false); } autoResizeMenuItem = new MenuItem(menu, SWT.CHECK); autoResizeMenuItem.setText(Localization.getString("DataGrid.AutoResize")); //$NON-NLS-1$ autoResizeMenuItem.setSelection(prefs.getBoolean(GraphingPreferenceConstants.P_AUTO_RESIZE)); jumpToEntryMenuItem = new MenuItem(menu, SWT.CHECK); jumpToEntryMenuItem.setText(Localization.getString("DataGrid.JumpToEntry")); //$NON-NLS-1$ jumpToEntryMenuItem.setSelection(prefs.getBoolean(GraphingPreferenceConstants.P_JUMP_NEW_TABLE_ENTRY)); for (int i = 0; i < IFormattingStyles.FORMAT_TITLES.length; i++) { item = new MenuItem(formatMenu, SWT.RADIO); item.setText(IFormattingStyles.FORMAT_TITLES[i]); item.addSelectionListener(new MenuFormatSelection()); } formatMenuItem.setEnabled(filteredDataSet.getRowCount() > 0); formatMenu.addMenuListener(new FormatMenuListener()); return menu; } private int getSelectedColumn() { TableColumn[] cols = table.getColumns(); int location = 0; for (int i = 0; i < cols.length; i++) { if (clickLocation.x > location && clickLocation.x < (location += cols[i].getWidth())) { return i; } } return cols.length-1; } private class AddFilterSelection extends SelectionAdapter { @Override public void widgetSelected(SelectionEvent e) { SelectFilterWizard wizard = new SelectFilterWizard(filteredDataSet.getTitles()); IWorkbench workbench = PlatformUI.getWorkbench(); wizard.init(workbench, null); WizardDialog dialog = new WizardDialog(workbench.getActiveWorkbenchWindow().getShell(), wizard); dialog.create(); int result = dialog.open(); if (result != Window.CANCEL) { IDataSetFilter filter = wizard.getFilter(); removeFiltersMenuItem.setEnabled(true); filteredDataSet.addFilter(filter); table.removeAll(); handleUpdateEvent(); MenuItem item = new MenuItem(filterMenu, SWT.CASCADE); item.setText(MessageFormat.format(Localization.getString("DataGrid.FilterLabel"), //$NON-NLS-1$ AvailableFilterTypes.getFilterName(filter.getID()), filteredDataSet.getTitles()[filter.getColumn()], filter.getInfo())); item.setData(filter); item.addSelectionListener(new RemoveFilterSelection()); } wizard.dispose(); } } private class RemoveFilterSelection implements SelectionListener { @Override public void widgetSelected(SelectionEvent e) { IDataSetFilter idsf = (IDataSetFilter)((MenuItem)e.widget).getData(); e.widget.dispose(); if (filterMenu.getItemCount() == 0) { removeFiltersMenuItem.setEnabled(false); } if (filteredDataSet.removeFilter(idsf)) { table.removeAll(); handleUpdateEvent(); } } @Override public void widgetDefaultSelected(SelectionEvent e) {} } private class FormatMenuListener extends MenuAdapter { @Override public void menuShown(MenuEvent e) { MenuItem[] items = ((Menu)e.widget).getItems(); boolean doubleValid = false, longValid = false; String itemText; int selectedCol = Math.max(1, getSelectedColumn()); for (int i = 0; i < items.length; i++) { items[i].setSelection(false); } items[columnFormat[selectedCol-1].getFormat()].setSelection(true); items[IFormattingStyles.UNFORMATED].setEnabled(true); items[IFormattingStyles.STRING].setEnabled(true); itemText = filteredDataSet.getRow(0)[selectedCol-1].toString(); try { Double.parseDouble(itemText); doubleValid = true; } catch (NumberFormatException nfe) {} try { Long.parseLong(itemText); longValid = true; } catch (NumberFormatException nfe) {} items[IFormattingStyles.DOUBLE].setEnabled(doubleValid); items[IFormattingStyles.HEX].setEnabled(longValid); items[IFormattingStyles.OCTAL].setEnabled(longValid); items[IFormattingStyles.BINARY].setEnabled(longValid); items[IFormattingStyles.DATE].setEnabled(longValid); } } private class MenuFormatSelection extends SelectionAdapter { @Override public void widgetSelected(SelectionEvent e) { int format = IFormattingStyles.UNFORMATED; int column = Math.max(1, getSelectedColumn()); int i; for (i = 0; i < IFormattingStyles.FORMAT_TITLES.length; i++) { if (IFormattingStyles.FORMAT_TITLES[i].equals(((MenuItem)e.getSource()).getText())) { format = i; } } Object[] data = filteredDataSet.getColumn(column-1); columnFormat[column-1].setFormat(format); for (i = 0; i < table.getItemCount(); i++) { table.getItem(i).setText(column, columnFormat[column-1].format(data[i].toString())); } table.redraw(); } } @Override public void handleUpdateEvent() { if (table.isDisposed()) { return; } table.getDisplay().asyncExec(() -> { if (table.isDisposed()) { return; } TableItem item; int startLocation; int endLocation = filteredDataSet.getRowCount(); int maxItems = prefs.getInt(GraphingPreferenceConstants.P_MAX_DATA_ITEMS); int oldSelection = table.getSelectionIndex(); //Remove old items to refresh table, and only read in as many items as will fit. //Note that a full refresh is necessary in order for filtered data to appear correctly. table.removeAll(); startLocation = Math.max(endLocation-maxItems, 0); //Add all the new items to the table Object[] os; for (int j, i1 = startLocation; i1 < endLocation; i1++) { item = new TableItem(table, SWT.NONE); os = filteredDataSet.getRow(i1); //Add 1 to the index/row num since graphs start counting rows at 1, not 0. item.setText(0, Integer.toString(i1 + 1)); for (j = 0; j < os.length; j++) { //Ignore null items if (os[j] != null) { item.setText(j+1, columnFormat[j].format(os[j].toString())); } } } //Re-select the old table selection, if there was one if (oldSelection != -1) { table.select(oldSelection); } //Resize the columns TableColumn col = table.getColumn(0); col.pack(); if (autoResizeMenuItem.getSelection()) { TableColumn[] cols = table.getColumns(); for (int i2 = 1; i2 < cols.length; i2++) { cols[i2].pack(); } } //Use if we want to set focus to newly added item. //Run async so the table can be fully constructed before jumping to an entry. if (jumpToEntryMenuItem.getSelection() && table.getItemCount() > 0) { table.getDisplay().asyncExec(() -> table.showItem(table.getItem(table.getItemCount()-1))); } formatMenuItem.setEnabled(table.getItemCount() > 0); }); } public void dispose() { filteredDataSet = null; table.dispose(); table = null; clickLocation = null; columnFormat = null; prefs.removePropertyChangeListener(propertyChangeListener); propertyChangeListener = null; } }