/* * This file is part of the OpenSCADA project * Copyright (C) 2006-2012 TH4 SYSTEMS GmbH (http://th4-systems.com) * * OpenSCADA is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenSCADA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenSCADA. If not, see * <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License. */ package org.openscada.ae.ui.views.views; import java.sql.Date; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.databinding.beans.BeanProperties; import org.eclipse.core.databinding.observable.set.ISetChangeListener; import org.eclipse.core.databinding.observable.set.SetChangeEvent; import org.eclipse.core.databinding.observable.set.WritableSet; import org.eclipse.core.databinding.property.Properties; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider; import org.eclipse.jface.viewers.ISelectionProvider; 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.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.openscada.ae.MonitorStatusInformation; import org.openscada.ae.ui.views.Messages; import org.openscada.ae.ui.views.Settings; import org.openscada.ae.ui.views.model.DecoratedMonitor; import org.openscada.core.Variant; public class MonitorsViewTable extends Composite { private static final String COLUMN_KEY = "org.openscada.ae.ui.views.views.MonitorsViewTable" + ".column.key"; //$NON-NLS-1$ //$NON-NLS-2$ private static final Date DEFAULT_DATE = new Date ( 0 ); private enum Columns { ID, STATE, LAST_FAIL_TIMESTAMP, VALUE, ACK_USER, ACK_TIMESTAMP, ITEM, MESSAGE, STATUS_TIMESTAMP; } private static class Sorter extends ViewerSorter { private final Columns column; private final int dir; public Sorter ( final Columns column, final int dir ) { this.column = column; this.dir = dir; } @SuppressWarnings ( { "unchecked", "rawtypes" } ) @Override public int compare ( final Viewer viewer, final Object e1, final Object e2 ) { final MonitorStatusInformation m1 = ( (DecoratedMonitor)e1 ).getMonitor (); final MonitorStatusInformation m2 = ( (DecoratedMonitor)e2 ).getMonitor (); Comparable v1 = 0; Comparable v2 = 0; switch ( this.column ) { case ID: v1 = m1.getId (); v2 = m2.getId (); break; case STATE: v1 = m1.getStatus (); v2 = m2.getStatus (); break; case VALUE: v1 = m1.getValue () == null ? Variant.NULL : m1.getValue (); v2 = m2.getValue () == null ? Variant.NULL : m2.getValue (); break; case LAST_FAIL_TIMESTAMP: v1 = m1.getLastFailTimestamp (); v2 = m2.getLastFailTimestamp (); break; case ACK_USER: v1 = m1.getLastAknUser () == null ? "" : m1.getLastAknUser (); //$NON-NLS-1$ v2 = m2.getLastAknUser () == null ? "" : m2.getLastAknUser (); //$NON-NLS-1$ break; case ACK_TIMESTAMP: v1 = m1.getLastAknTimestamp () == null ? DEFAULT_DATE : m1.getLastAknTimestamp (); v2 = m2.getLastAknTimestamp () == null ? DEFAULT_DATE : m2.getLastAknTimestamp (); break; case ITEM: v1 = m1.getAttributes ().get ( "item" ) == null ? Variant.NULL : m1.getAttributes ().get ( "item" ); //$NON-NLS-1$ //$NON-NLS-2$ v2 = m2.getAttributes ().get ( "item" ) == null ? Variant.NULL : m2.getAttributes ().get ( "item" ); //$NON-NLS-1$ //$NON-NLS-2$ break; case MESSAGE: v1 = m1.getAttributes ().get ( "message" ) == null ? Variant.NULL : m1.getAttributes ().get ( "message" ); //$NON-NLS-1$ //$NON-NLS-2$ v2 = m2.getAttributes ().get ( "message" ) == null ? Variant.NULL : m2.getAttributes ().get ( "message" ); //$NON-NLS-1$ //$NON-NLS-2$ break; case STATUS_TIMESTAMP: v1 = m1.getStatusTimestamp (); v2 = m2.getStatusTimestamp (); break; } // first compare the given column int result = v1.compareTo ( v2 ); // use given order for sorting result = this.dir == SWT.DOWN ? -result : result; // if values are the same, order by timestamp in descending order if ( this.column != Columns.LAST_FAIL_TIMESTAMP && result == 0 ) { result = m2.getStatusTimestamp ().compareTo ( m1.getStatusTimestamp () ); } // if values are still the same, order by id in ascending order if ( this.column != Columns.ID && result == 0 ) { result = m1.getId ().compareTo ( m2.getId () ); } return result; } } private static class SortListener extends SelectionAdapter { private final TableViewer tableViewer; public SortListener ( final TableViewer tableViewer ) { this.tableViewer = tableViewer; } @Override public void widgetSelected ( final SelectionEvent e ) { final Table table = this.tableViewer.getTable (); final TableColumn newColumn = (TableColumn)e.widget; final TableColumn currentColumn = table.getSortColumn (); final int currentDir = table.getSortDirection (); int newDir = SWT.UP; if ( newColumn == currentColumn ) { newDir = currentDir == SWT.UP ? SWT.DOWN : SWT.UP; } else { table.setSortColumn ( newColumn ); } table.setSortDirection ( newDir ); this.tableViewer.setSorter ( new Sorter ( (Columns)newColumn.getData ( COLUMN_KEY ), newDir ) ); } } private final AtomicReference<TableViewer> tableRef = new AtomicReference<TableViewer> ( null ); private final WritableSet monitors; private final TableViewer tableViewer; private volatile boolean scrollLock = false; public MonitorsViewTable ( final Composite parent, final IViewSite viewSite, final int style, final WritableSet monitors, final List<ColumnProperties> columnSettings ) { super ( parent, style ); this.monitors = monitors; final FillLayout layout = new FillLayout (); setLayout ( layout ); this.tableViewer = new TableViewer ( this, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI ); this.tableRef.set ( this.tableViewer ); createColumns ( this.tableViewer ); applyColumSettings ( columnSettings ); this.tableViewer.getTable ().setHeaderVisible ( true ); this.tableViewer.getTable ().setLinesVisible ( true ); this.tableViewer.setUseHashlookup ( true ); this.tableViewer.setSorter ( new Sorter ( Columns.LAST_FAIL_TIMESTAMP, SWT.DOWN ) ); this.tableViewer.getTable ().setSortDirection ( SWT.DOWN ); hookContextMenu ( this.tableViewer.getControl (), this.tableViewer, viewSite ); viewSite.setSelectionProvider ( this.tableViewer ); final ObservableSetContentProvider contentProvider = new ObservableSetContentProvider (); this.tableViewer.setContentProvider ( contentProvider ); this.tableViewer.setLabelProvider ( new MonitorTableLabelProvider ( Properties.observeEach ( contentProvider.getKnownElements (), BeanProperties.values ( new String[] { "id", "monitor" } ) ), Settings.getTimeZone () ) ); //$NON-NLS-1$ //$NON-NLS-2$ this.tableViewer.setInput ( this.monitors ); contentProvider.getRealizedElements ().addSetChangeListener ( new ISetChangeListener () { @Override public void handleSetChange ( final SetChangeEvent event ) { if ( !MonitorsViewTable.this.scrollLock ) { MonitorsViewTable.this.tableViewer.getTable ().setTopIndex ( 0 ); } } } ); } protected void hookContextMenu ( final Control control, final ISelectionProvider selectionProvider, final IViewSite viewSite ) { final MenuManager menuMgr = new MenuManager ( "#PopupMenu" ); //$NON-NLS-1$ menuMgr.setRemoveAllWhenShown ( true ); menuMgr.addMenuListener ( new IMenuListener () { @Override public void menuAboutToShow ( final IMenuManager manager ) { fillContextMenu ( manager ); } } ); final Menu menu = menuMgr.createContextMenu ( control ); control.setMenu ( menu ); viewSite.registerContextMenu ( menuMgr, selectionProvider ); } protected void fillContextMenu ( final IMenuManager manager ) { manager.add ( new Separator ( IWorkbenchActionConstants.MB_ADDITIONS ) ); } private void createColumns ( final TableViewer table ) { final SortListener sortListener = new SortListener ( table ); // id final TableViewerColumn idColumn = new TableViewerColumn ( table, SWT.NONE ); idColumn.getColumn ().setText ( Messages.ID ); idColumn.getColumn ().setData ( COLUMN_KEY, Columns.ID ); idColumn.getColumn ().setWidth ( 450 ); idColumn.getColumn ().setResizable ( true ); idColumn.getColumn ().setMoveable ( true ); idColumn.getColumn ().addSelectionListener ( sortListener ); // state final TableViewerColumn stateColumn = new TableViewerColumn ( table, SWT.NONE ); stateColumn.getColumn ().setText ( Messages.State ); stateColumn.getColumn ().setData ( COLUMN_KEY, Columns.STATE ); stateColumn.getColumn ().setWidth ( 150 ); stateColumn.getColumn ().setResizable ( true ); stateColumn.getColumn ().setMoveable ( true ); stateColumn.getColumn ().addSelectionListener ( sortListener ); // last fail timestamp final TableViewerColumn timestampColumn = new TableViewerColumn ( table, SWT.NONE ); timestampColumn.getColumn ().setText ( Messages.Timestamp ); timestampColumn.getColumn ().setData ( COLUMN_KEY, Columns.LAST_FAIL_TIMESTAMP ); timestampColumn.getColumn ().setWidth ( 180 ); timestampColumn.getColumn ().setResizable ( true ); timestampColumn.getColumn ().setMoveable ( true ); timestampColumn.getColumn ().addSelectionListener ( sortListener ); // value final TableViewerColumn valueColumn = new TableViewerColumn ( table, SWT.NONE ); valueColumn.getColumn ().setText ( Messages.Value ); valueColumn.getColumn ().setData ( COLUMN_KEY, Columns.VALUE ); valueColumn.getColumn ().setWidth ( 100 ); valueColumn.getColumn ().setResizable ( true ); valueColumn.getColumn ().setMoveable ( true ); valueColumn.getColumn ().addSelectionListener ( sortListener ); // akn user final TableViewerColumn aknUserColumn = new TableViewerColumn ( table, SWT.NONE ); aknUserColumn.getColumn ().setText ( Messages.AckUser ); aknUserColumn.getColumn ().setData ( COLUMN_KEY, Columns.ACK_USER ); aknUserColumn.getColumn ().setWidth ( 150 ); aknUserColumn.getColumn ().setResizable ( true ); aknUserColumn.getColumn ().setMoveable ( false ); aknUserColumn.getColumn ().addSelectionListener ( sortListener ); // akn timestamp final TableViewerColumn aknTimestampColumn = new TableViewerColumn ( table, SWT.NONE ); aknTimestampColumn.getColumn ().setText ( Messages.AckTimestamp ); aknTimestampColumn.getColumn ().setData ( COLUMN_KEY, Columns.ACK_TIMESTAMP ); aknTimestampColumn.getColumn ().setWidth ( 180 ); aknTimestampColumn.getColumn ().setResizable ( true ); aknTimestampColumn.getColumn ().setMoveable ( true ); aknTimestampColumn.getColumn ().addSelectionListener ( sortListener ); // item final TableViewerColumn itemColumn = new TableViewerColumn ( table, SWT.NONE ); itemColumn.getColumn ().setText ( Messages.Item ); itemColumn.getColumn ().setData ( COLUMN_KEY, Columns.ITEM ); itemColumn.getColumn ().setWidth ( 180 ); itemColumn.getColumn ().setResizable ( true ); itemColumn.getColumn ().setMoveable ( true ); itemColumn.getColumn ().addSelectionListener ( sortListener ); // message final TableViewerColumn messageColumn = new TableViewerColumn ( table, SWT.NONE ); messageColumn.getColumn ().setText ( Messages.Message ); messageColumn.getColumn ().setData ( COLUMN_KEY, Columns.MESSAGE ); messageColumn.getColumn ().setWidth ( 180 ); messageColumn.getColumn ().setResizable ( true ); messageColumn.getColumn ().setMoveable ( true ); messageColumn.getColumn ().addSelectionListener ( sortListener ); // status timestamp final TableViewerColumn statusTimestampColumn = new TableViewerColumn ( table, SWT.NONE ); statusTimestampColumn.getColumn ().setText ( Messages.MonitorsViewTable_StatusTimestamp ); statusTimestampColumn.getColumn ().setData ( COLUMN_KEY, Columns.STATUS_TIMESTAMP ); statusTimestampColumn.getColumn ().setWidth ( 180 ); statusTimestampColumn.getColumn ().setResizable ( true ); statusTimestampColumn.getColumn ().setMoveable ( true ); statusTimestampColumn.getColumn ().addSelectionListener ( sortListener ); } public void clear () { this.monitors.clear (); } public List<DecoratedMonitor> selectedMonitors () { if ( this.tableRef.get ().getTable ().getSelectionCount () == 0 ) { return new ArrayList<DecoratedMonitor> (); } final List<DecoratedMonitor> result = new ArrayList<DecoratedMonitor> (); for ( final TableItem row : this.tableRef.get ().getTable ().getSelection () ) { if ( row.getData () instanceof DecoratedMonitor ) { result.add ( (DecoratedMonitor)row.getData () ); } } return result; } /** * may only be called from GUI thread * @return */ public int numOfEntries () { return this.monitors.size (); } public void applyColumSettings ( final List<ColumnProperties> columnSettings ) { if ( columnSettings == null ) { return; } final int[] colOrder = this.tableViewer.getTable ().getColumnOrder (); int i = 0; for ( final ColumnProperties p : columnSettings ) { if ( i >= colOrder.length ) { break; } colOrder[i] = p.getNo (); i += 1; } this.tableViewer.getTable ().setColumnOrder ( colOrder ); i = 0; for ( final ColumnProperties p : columnSettings ) { if ( i >= this.tableViewer.getTable ().getColumnCount () ) { break; } final TableColumn col = this.tableViewer.getTable ().getColumn ( i ); col.setWidth ( p.getWidth () ); i += 1; } } public List<ColumnProperties> getColumnSettings () { final List<ColumnProperties> result = new ArrayList<ColumnProperties> (); int i = 0; final int[] order = this.tableViewer.getTable ().getColumnOrder (); for ( final TableColumn col : this.tableViewer.getTable ().getColumns () ) { result.add ( new ColumnProperties ( order[i], col.getWidth () ) ); i += 1; } return result; } }