/******************************************************************************* * Copyright (c) 2015 MINRES Technologies GmbH 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: * MINRES Technologies GmbH - initial API and implementation *******************************************************************************/ package com.minres.scviewer.e4.application.parts; import java.util.Vector; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.di.Focus; import org.eclipse.e4.ui.di.UIEventTopic; import org.eclipse.e4.ui.services.IServiceConstants; import org.eclipse.e4.ui.workbench.modeling.ESelectionService; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import com.minres.scviewer.database.ITx; import com.minres.scviewer.database.ITxAttribute; import com.minres.scviewer.database.ITxRelation; import com.minres.scviewer.database.DataType; import com.minres.scviewer.e4.application.Messages; import com.minres.scviewer.e4.application.provider.TxPropertiesLabelProvider; /** * The Class TransactionDetails shows the details of a selected transaction. */ public class TransactionDetails { /** The Constant COLUMN_FIRST. */ // Column constants public static final int COLUMN_FIRST = 0; /** The Constant COLUMN_SECOND. */ public static final int COLUMN_SECOND = 1; /** The Constant COLUMN_THIRD. */ public static final int COLUMN_THIRD = 2; /** The event broker. */ @Inject IEventBroker eventBroker; /** The selection service. */ @Inject ESelectionService selectionService; /** The name filter. */ private Text nameFilter; /** The tree viewer. */ private TreeViewer treeViewer; /** The col3. */ private TreeViewerColumn col1, col2, col3; /** The attribute filter. */ TxAttributeFilter attributeFilter; /** The view sorter. */ TxAttributeViewerSorter viewSorter; /** The waveform viewer part. */ private WaveformViewer waveformViewerPart; /** * Creates the composite. * * @param parent the parent */ @PostConstruct public void createComposite(final Composite parent) { parent.setLayout(new GridLayout(1, false)); nameFilter = new Text(parent, SWT.BORDER); nameFilter.setMessage(Messages.TransactionDetails_0); nameFilter.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { attributeFilter.setSearchText(((Text) e.widget).getText()); treeViewer.refresh(); } }); nameFilter.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); attributeFilter = new TxAttributeFilter(); viewSorter = new TxAttributeViewerSorter(); treeViewer = new TreeViewer(parent); treeViewer.setContentProvider(new TransactionTreeContentProvider()); treeViewer.setLabelProvider(new TxPropertiesLabelProvider()); treeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); treeViewer.addFilter(attributeFilter); treeViewer.setComparator(viewSorter); treeViewer.setAutoExpandLevel(2); // Set up the table Tree tree = treeViewer.getTree(); tree.setLayoutData(new GridData(GridData.FILL_BOTH)); // Add the name column col1 = new TreeViewerColumn(treeViewer, SWT.NONE); col1.getColumn().setText(Messages.TransactionDetails_1); col1.getColumn().setResizable(true); col1.setLabelProvider(new DelegatingStyledCellLabelProvider(new AttributeLabelProvider(AttributeLabelProvider.NAME))); col1.getColumn().addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { ((TxAttributeViewerSorter) treeViewer.getComparator()).doSort(COLUMN_FIRST); treeViewer.refresh(); } }); // Add the type column col2 = new TreeViewerColumn(treeViewer, SWT.NONE); col2.getColumn().setText(Messages.TransactionDetails_2); col2.getColumn().setResizable(true); col2.setLabelProvider(new DelegatingStyledCellLabelProvider(new AttributeLabelProvider(AttributeLabelProvider.TYPE))); col2.getColumn().addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { ((TxAttributeViewerSorter) treeViewer.getComparator()).doSort(COLUMN_SECOND); treeViewer.refresh(); } }); // Add the value column col3 = new TreeViewerColumn(treeViewer, SWT.NONE); col3.getColumn().setText(Messages.TransactionDetails_3); col3.getColumn().setResizable(true); col3.setLabelProvider(new DelegatingStyledCellLabelProvider(new AttributeLabelProvider(AttributeLabelProvider.VALUE))); col3.getColumn().addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { ((TxAttributeViewerSorter) treeViewer.getComparator()).doSort(COLUMN_SECOND); treeViewer.refresh(); } }); // Pack the columns // for (int i = 0, n = table.getColumnCount(); i < n; i++) { // table.getColumn(i).pack(); // } // Turn on the header and the lines tree.setHeaderVisible(true); tree.setLinesVisible(true); treeViewer.addDoubleClickListener(new IDoubleClickListener(){ @Override public void doubleClick(DoubleClickEvent event) { ISelection selection = treeViewer.getSelection(); if(selection instanceof IStructuredSelection){ IStructuredSelection structuredSelection = (IStructuredSelection) selection; Object selected = structuredSelection.getFirstElement(); if(selected instanceof Object[]){ Object[] selectedArray = (Object[]) selected; if(selectedArray.length==3 && selectedArray[2] instanceof ITx){ waveformViewerPart.setSelection(new StructuredSelection(selectedArray[2])); treeViewer.setInput(selectedArray[2]); } } } } }); parent.addControlListener(new ControlAdapter() { public void controlResized(ControlEvent e) { Tree table = treeViewer.getTree(); Rectangle area = parent.getClientArea(); Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT); int width = area.width - 2*table.getBorderWidth(); if (preferredSize.y > area.height + table.getHeaderHeight()) { // Subtract the scrollbar width from the total column width // if a vertical scrollbar will be required Point vBarSize = table.getVerticalBar().getSize(); width -= vBarSize.x; } Point oldSize = table.getSize(); if (oldSize.x > area.width) { // table is getting smaller so make the columns // smaller first and then resize the table to // match the client area width col1.getColumn().setWidth(width/3); col2.getColumn().setWidth(width/4); col3.getColumn().setWidth(width - col1.getColumn().getWidth()); table.setSize(area.width, area.height); } else { // table is getting bigger so make the table // bigger first and then make the columns wider // to match the client area width table.setSize(area.width, area.height); col1.getColumn().setWidth(width/3); col2.getColumn().setWidth(width/4); col3.getColumn().setWidth(width - col1.getColumn().getWidth()- col2.getColumn().getWidth()); } } }); } /** * Sets the focus. */ @Focus public void setFocus() { treeViewer.getTree().setFocus(); } /** * Gets the status event. * * @param part the part * @return the status event */ @Inject @Optional public void getStatusEvent(@UIEventTopic(WaveformViewer.ACTIVE_WAVEFORMVIEW) WaveformViewer part) { this.waveformViewerPart=part; } /** * Sets the selection. * * @param selection the new selection */ @Inject public void setSelection(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional IStructuredSelection selection){ if(treeViewer!=null && selection!=null && !treeViewer.getTree().isDisposed()){ if( selection instanceof IStructuredSelection) { Object object= ((IStructuredSelection)selection).getFirstElement(); if(object instanceof ITx){ treeViewer.setInput(object); } else { treeViewer.setInput(null); } } } } /** * Time to string. * * @param time the time * @return the string */ String timeToString(Long time){ return waveformViewerPart.getScaledTime(time); } /** * Tx to string. * * @param tx the tx * @return the string */ String txToString(ITx tx){ StringBuilder sb = new StringBuilder(); sb.append("tx#").append(tx.getId()).append("[").append(timeToString(tx.getBeginTime())). //$NON-NLS-1$ //$NON-NLS-2$ append(" - ").append(timeToString(tx.getEndTime())).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ return sb.toString(); } /** * The Class TxAttributeViewerSorter. */ class TxAttributeViewerSorter extends ViewerComparator { /** The Constant ASCENDING. */ private static final int ASCENDING = 0; /** The Constant DESCENDING. */ private static final int DESCENDING = 1; /** The column. */ private int column; /** The direction. */ private int direction; /** * Does the sort. If it's a different column from the previous sort, do an * ascending sort. If it's the same column as the last sort, toggle the sort * direction. * * @param column the column */ public void doSort(int column) { if (column == this.column) { // Same column as last sort; toggle the direction direction = 1 - direction; } else { // New column; do an ascending sort this.column = column; direction = ASCENDING; } } /** * Compares the object for sorting. * * @param viewer the viewer * @param e1 the e1 * @param e2 the e2 * @return the int */ public int compare(Viewer viewer, Object e1, Object e2) { int rc = 0; if(e1 instanceof ITxAttribute && e2 instanceof ITxAttribute){ ITxAttribute p1 = (ITxAttribute) e1; ITxAttribute p2 = (ITxAttribute) e2; // Determine which column and do the appropriate sort switch (column) { case COLUMN_FIRST: rc = getComparator().compare(p1.getName(), p2.getName()); break; case COLUMN_SECOND: rc = getComparator().compare(p1.getDataType().name(), p2.getDataType().name()); break; case COLUMN_THIRD: rc = getComparator().compare(p1.getValue().toString(), p2.getValue().toString()); break; } // If descending order, flip the direction if (direction == DESCENDING) rc = -rc; } return rc; } } /** * The Class TxAttributeFilter. */ class TxAttributeFilter extends ViewerFilter { /** The search string. */ private String searchString; /** * Sets the search text. * * @param s the new search text */ public void setSearchText(String s) { this.searchString = ".*" + s + ".*"; //$NON-NLS-1$ //$NON-NLS-2$ } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (searchString == null || searchString.length() == 0) { return true; } if(element instanceof ITxAttribute){ ITxAttribute p = (ITxAttribute) element; if (p.getName().matches(searchString)) { return true; } } else if(element instanceof TreeNode) return true; return false; } } /** * The Enum Type. */ enum Type {/** The props. */ PROPS, /** The attrs. */ ATTRS, /** The in rel. */ IN_REL, /** The out rel. */ OUT_REL} /** * The Class TreeNode. */ class TreeNode{ /** The type. */ public Type type; /** The element. */ public ITx element; /** * Instantiates a new tree node. * * @param element the element * @param type the type */ public TreeNode(ITx element, Type type){ this.element=element; this.type=type; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString(){ switch(type){ case PROPS: return Messages.TransactionDetails_10; case ATTRS: return Messages.TransactionDetails_11; case IN_REL: return Messages.TransactionDetails_12; case OUT_REL: return Messages.TransactionDetails_13; } return ""; //$NON-NLS-1$ } } /** * The Class TransactionTreeContentProvider. */ class TransactionTreeContentProvider implements ITreeContentProvider { /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ @Override public void dispose() { } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getElements(java.lang.Object) */ @Override public Object[] getElements(Object element) { return new Object[]{ new TreeNode((ITx)element, Type.PROPS), new TreeNode((ITx)element, Type.ATTRS), new TreeNode((ITx)element, Type.IN_REL), new TreeNode((ITx)element, Type.OUT_REL) }; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) */ @Override public Object[] getChildren(Object element) { if(element instanceof TreeNode){ TreeNode propertyHolder=(TreeNode) element; if(propertyHolder.type == Type.PROPS){ return new Object[][]{ {Messages.TransactionDetails_1, Messages.TransactionDetails_16, propertyHolder.element.getStream().getFullName()}, {Messages.TransactionDetails_2, Messages.TransactionDetails_16, propertyHolder.element.getGenerator().getName()}, {Messages.TransactionDetails_19, Messages.TransactionDetails_20, timeToString(propertyHolder.element.getBeginTime())}, {Messages.TransactionDetails_21, Messages.TransactionDetails_20, timeToString(propertyHolder.element.getEndTime())} }; }else if(propertyHolder.type == Type.ATTRS) return propertyHolder.element.getAttributes().toArray(); else if(propertyHolder.type == Type.IN_REL){ Vector res = new Vector<>(); for(ITxRelation rel:propertyHolder.element.getIncomingRelations()){ res.add(new Object[]{ rel.getRelationType(), rel.getSource().getGenerator().getName(), rel.getSource()}); } return res.toArray(); } else if(propertyHolder.type == Type.OUT_REL){ Vector res = new Vector<>(); for(ITxRelation rel:propertyHolder.element.getOutgoingRelations()){ res.add(new Object[]{ rel.getRelationType(), rel.getTarget().getGenerator().getName(), rel.getTarget()}); } return res.toArray(); } } return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) */ @Override public Object getParent(Object element) { return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) */ @Override public boolean hasChildren(Object element) { return getChildren(element)!=null; } } /** * The Class AttributeLabelProvider. */ class AttributeLabelProvider extends LabelProvider implements IStyledLabelProvider { /** The field. */ final int field; /** The Constant NAME. */ public static final int NAME=0; /** The Constant TYPE. */ public static final int TYPE=1; /** The Constant VALUE. */ public static final int VALUE=2; /** * Instantiates a new attribute label provider. * * @param field the field */ public AttributeLabelProvider(int field) { this.field=field; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider#getStyledText(java.lang.Object) */ @Override public StyledString getStyledText(Object element) { switch(field){ case NAME: if (element instanceof ITxAttribute) { ITxAttribute attribute = (ITxAttribute) element; return new StyledString(attribute.getName()); }else if (element instanceof ITxRelation) { return new StyledString(Messages.TransactionDetails_4); }else if(element instanceof Object[]){ Object[] elements = (Object[]) element; return new StyledString(elements[field].toString()); } else return new StyledString(element.toString()); case TYPE: if (element instanceof ITxAttribute) { ITxAttribute attribute = (ITxAttribute) element; return new StyledString(attribute.getDataType().toString()); }else if(element instanceof Object[]){ Object[] elements = (Object[]) element; return new StyledString(elements[field].toString()); }else return new StyledString(""); //$NON-NLS-1$ default: if (element instanceof ITxAttribute) { ITxAttribute attribute = (ITxAttribute) element; String value = attribute.getValue().toString(); if((DataType.UNSIGNED == attribute.getDataType() || DataType.INTEGER==attribute.getDataType()) && !"0".equals(value)) { try { value = attribute.getValue().toString() + " [0x"+Long.toHexString(Long.parseLong(attribute.getValue().toString()))+"]"; } catch(NumberFormatException e) { } } return new StyledString(value); }else if(element instanceof Object[]){ Object[] elements = (Object[]) element; return new StyledString(elements[field].toString()); } else if(element instanceof ITx){ return new StyledString(txToString((ITx) element)); }else return new StyledString(""); //$NON-NLS-1$ } } } }