/* * This file is part of the OpenSCADA project * Copyright (C) 2006-2011 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.da.client.dataitem.details.extra.part; import java.util.HashMap; import java.util.Map; import org.eclipse.draw2d.BorderLayout; import org.eclipse.draw2d.ChopboxAnchor; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.ConnectionLayer; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FlowLayout; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.GridData; import org.eclipse.draw2d.GridLayout; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.Layer; import org.eclipse.draw2d.LayeredPane; import org.eclipse.draw2d.MarginBorder; import org.eclipse.draw2d.MouseEvent; import org.eclipse.draw2d.MouseListener; import org.eclipse.draw2d.MouseMotionListener; import org.eclipse.draw2d.PolygonDecoration; import org.eclipse.draw2d.PolylineConnection; import org.eclipse.draw2d.RoundedRectangle; import org.eclipse.jface.resource.ColorDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.openscada.core.Variant; import org.openscada.core.ui.styles.Style; import org.openscada.core.ui.styles.StyleInformation; import org.openscada.da.ui.styles.Activator; /** * A detail view for the manual override value, setting and getting the status * @author Jens Reimann * */ public class ManualOverride extends AbstractBaseDraw2DDetailsPart { private Label pvValue; private Label mvValue; private Label rvValue; private RoundedRectangle rvRect; private RoundedRectangle mvRect; private RoundedRectangle pvRect; private PolylineConnection p2rConnection; private PolylineConnection m2rConnection; private Variant manualValue; private RoundedRectangle rmvRect; private Label rmvValue; private RoundedRectangle rpvRect; private Label rpvValue; private PolylineConnection rp2pConnection; private PolylineConnection rm2pConnection; private LocalResourceManager resourceManager; private StyleInformation baseStyle; @Override public void createPart ( final Composite parent ) { this.baseStyle = new StyleInformation ( null, ColorDescriptor.createFrom ( ColorConstants.lightGray ), null ); this.resourceManager = new LocalResourceManager ( JFaceResources.getResources () ); super.createPart ( parent ); } @Override public IFigure createMain () { final LayeredPane root = new LayeredPane (); final Layer figureLayer = new Layer (); figureLayer.setLayoutManager ( new FlowLayout () ); final ConnectionLayer connectionLayer = new ConnectionLayer (); connectionLayer.setAntialias ( SWT.ON ); final Figure figure = new Figure (); figureLayer.add ( figure ); final GridLayout gridLayout = new GridLayout ( 3, true ); gridLayout.horizontalSpacing = 50; gridLayout.verticalSpacing = 50; figure.setLayoutManager ( gridLayout ); final Figure rpvFigure = createRPV (); final Figure pvFigure = createPV (); final Figure rmvFigure = createRMV (); final Figure mvFigure = createMV (); final Figure rvFigure = createRV (); figure.add ( rpvFigure, new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 1 ) ); figure.add ( pvFigure, new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 2 ) ); figure.add ( rvFigure, new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 3 ) ); figure.add ( rmvFigure, new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 1 ) ); figure.add ( mvFigure, new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 1 ) ); figure.add ( new Figure (), new GridData ( GridData.CENTER, GridData.CENTER, true, true, 1, 1 ) ); // placeholder connectionLayer.add ( this.p2rConnection = createConnection ( this.pvRect, this.rvRect ) ); connectionLayer.add ( this.m2rConnection = createConnection ( this.mvRect, this.rvRect ) ); connectionLayer.add ( this.rp2pConnection = createConnection ( this.rpvRect, this.pvRect ) ); connectionLayer.add ( this.rm2pConnection = createConnection ( this.rmvRect, this.pvRect ) ); root.add ( figureLayer ); root.add ( connectionLayer ); return root; } private PolylineConnection createConnection ( final IFigure source, final IFigure target ) { final PolylineConnection c = new PolylineConnection (); final ChopboxAnchor sourceAnchor = new ChopboxAnchor ( source ); final ChopboxAnchor targetAnchor = new ChopboxAnchor ( target ); c.setSourceAnchor ( sourceAnchor ); c.setTargetAnchor ( targetAnchor ); return c; } private Figure createRV () { final Figure rvFigure = new Figure (); rvFigure.setLayoutManager ( new BorderLayout () ); final Label label = new Label ( Messages.ManualOverride_ResetValue_Label ); label.setBorder ( new MarginBorder ( 10 ) ); rvFigure.add ( label, BorderLayout.RIGHT ); this.rvRect = new RoundedRectangle (); this.rvRect.setLayoutManager ( new BorderLayout () ); this.rvValue = new Label (); this.rvRect.setBackgroundColor ( ColorConstants.lightGray ); this.rvValue.setBorder ( new MarginBorder ( 10 ) ); this.rvRect.add ( this.rvValue, BorderLayout.CENTER ); rvFigure.add ( this.rvRect, BorderLayout.CENTER ); return rvFigure; } private Figure createRMV () { final Figure rmvFigure = new Figure (); rmvFigure.setLayoutManager ( new BorderLayout () ); final Label label = new Label ( Messages.ManualOverride_RemoteManualvalue_Label ); label.setBorder ( new MarginBorder ( 10 ) ); rmvFigure.add ( label, BorderLayout.LEFT ); this.rmvRect = new RoundedRectangle (); this.rmvRect.setLayoutManager ( new BorderLayout () ); this.rmvValue = new Label (); this.rmvValue.setBorder ( new MarginBorder ( 10 ) ); this.rmvRect.setBackgroundColor ( ColorConstants.lightGray ); this.rmvRect.add ( this.rmvValue, BorderLayout.CENTER ); this.rmvRect.addMouseMotionListener ( new MouseMotionListener.Stub () { @Override public void mouseEntered ( final MouseEvent me ) { ManualOverride.this.rmvRect.setLineWidth ( 2 ); } @Override public void mouseExited ( final MouseEvent me ) { ManualOverride.this.rmvRect.setLineWidth ( 1 ); } } ); this.rmvRect.addMouseListener ( new MouseListener () { @Override public void mouseDoubleClicked ( final MouseEvent me ) { handleSetRemoteManualValue (); } @Override public void mousePressed ( final MouseEvent me ) { setRemoteManualState ( true ); } @Override public void mouseReleased ( final MouseEvent me ) { // TODO Auto-generated method stub } } ); rmvFigure.add ( this.rmvRect, BorderLayout.CENTER ); return rmvFigure; } protected void setRemoteManualState ( final boolean state ) { final Map<String, Variant> attributes = new HashMap<String, Variant> (); attributes.put ( "remote.manual.active", Variant.valueOf ( state ) ); //$NON-NLS-1$ writeAttributes ( attributes ); } protected void handleSetRemoteManualValue () { Variant var = null; try { var = this.value.getAttributes ().get ( "remote.manual.value" ); //$NON-NLS-1$ } catch ( final Exception e ) { var = null; //just call the editor with his default configuration } final Variant value = new VariantEntryDialog ( this.shell, var ).getValue (); if ( value != null ) { final Map<String, Variant> attributes = new HashMap<String, Variant> (); attributes.put ( "remote.manual.value", value ); //$NON-NLS-1$ writeAttributes ( attributes ); } } private Figure createMV () { final Figure mvFigure = new Figure (); mvFigure.setLayoutManager ( new BorderLayout () ); final Label label = new Label ( Messages.ManualOverride_LocalManualValue_Label ); label.setBorder ( new MarginBorder ( 10 ) ); mvFigure.add ( label, BorderLayout.LEFT ); this.mvRect = new RoundedRectangle (); this.mvRect.setLayoutManager ( new BorderLayout () ); this.mvValue = new Label (); this.mvValue.setBorder ( new MarginBorder ( 10 ) ); this.mvRect.setBackgroundColor ( ColorConstants.lightGray ); this.mvRect.add ( this.mvValue, BorderLayout.CENTER ); this.mvRect.addMouseMotionListener ( new MouseMotionListener.Stub () { @Override public void mouseEntered ( final MouseEvent me ) { ManualOverride.this.mvRect.setLineWidth ( 2 ); } @Override public void mouseExited ( final MouseEvent me ) { ManualOverride.this.mvRect.setLineWidth ( 1 ); } } ); this.mvRect.addMouseListener ( new MouseListener () { @Override public void mouseDoubleClicked ( final MouseEvent me ) { ManualOverride.this.manualValue = null; ManualOverride.this.switchToManual (); } @Override public void mousePressed ( final MouseEvent me ) { ManualOverride.this.switchToManual (); } @Override public void mouseReleased ( final MouseEvent me ) { // TODO Auto-generated method stub } } ); mvFigure.add ( this.mvRect, BorderLayout.CENTER ); return mvFigure; } protected void switchToManual () { if ( this.manualValue == null ) { // enter manual value if we don't have one enterManualValue (); if ( this.manualValue == null ) { // still have none ... abort return; } } final Map<String, Variant> attributes = new HashMap<String, Variant> (); attributes.put ( "org.openscada.da.manual.value", this.manualValue ); //$NON-NLS-1$ writeAttributes ( attributes ); } protected void writeAttributes ( final Map<String, Variant> attributes ) { this.item.writeAtrtibutes ( attributes ); } private Figure createRPV () { final Figure rpvFigure = new Figure (); rpvFigure.setLayoutManager ( new BorderLayout () ); final Label label = new Label ( Messages.ManualOverride_RemoteProcessValue_Label ); label.setBorder ( new MarginBorder ( 10 ) ); rpvFigure.add ( label, BorderLayout.LEFT ); this.rpvRect = new RoundedRectangle (); this.rpvRect.setLayoutManager ( new BorderLayout () ); this.rpvValue = new Label (); this.rpvValue.setBorder ( new MarginBorder ( 10 ) ); this.rpvRect.setBackgroundColor ( ColorConstants.lightGray ); this.rpvRect.add ( this.rpvValue, BorderLayout.CENTER ); rpvFigure.add ( this.rpvRect, BorderLayout.CENTER ); this.rpvRect.addMouseMotionListener ( new MouseMotionListener.Stub () { @Override public void mouseEntered ( final MouseEvent me ) { ManualOverride.this.rpvRect.setLineWidth ( 2 ); } @Override public void mouseExited ( final MouseEvent me ) { ManualOverride.this.rpvRect.setLineWidth ( 1 ); } } ); this.rpvRect.addMouseListener ( new MouseListener () { @Override public void mouseDoubleClicked ( final MouseEvent me ) { } @Override public void mousePressed ( final MouseEvent me ) { setRemoteManualState ( false ); } @Override public void mouseReleased ( final MouseEvent me ) { } } ); return rpvFigure; } private Figure createPV () { final Figure pvFigure = new Figure (); pvFigure.setLayoutManager ( new BorderLayout () ); final Label label = new Label ( Messages.ManualOverride_ProcessValue_Label ); label.setBorder ( new MarginBorder ( 10 ) ); pvFigure.add ( label, BorderLayout.LEFT ); this.pvRect = new RoundedRectangle (); this.pvRect.setLayoutManager ( new BorderLayout () ); this.pvValue = new Label (); this.pvValue.setBorder ( new MarginBorder ( 10 ) ); this.pvRect.setBackgroundColor ( ColorConstants.lightGray ); this.pvRect.add ( this.pvValue, BorderLayout.CENTER ); pvFigure.add ( this.pvRect, BorderLayout.CENTER ); this.pvRect.addMouseMotionListener ( new MouseMotionListener.Stub () { @Override public void mouseEntered ( final MouseEvent me ) { ManualOverride.this.pvRect.setLineWidth ( 2 ); } @Override public void mouseExited ( final MouseEvent me ) { ManualOverride.this.pvRect.setLineWidth ( 1 ); } } ); this.pvRect.addMouseListener ( new MouseListener () { @Override public void mouseDoubleClicked ( final MouseEvent me ) { } @Override public void mousePressed ( final MouseEvent me ) { ManualOverride.this.switchToProcess (); } @Override public void mouseReleased ( final MouseEvent me ) { } } ); return pvFigure; } /** * Enter the manual value */ protected void enterManualValue () { final VariantEntryDialog dlg; if ( this.value != null ) { dlg = new VariantEntryDialog ( this.shell, this.value.getValue () ); } else { dlg = new VariantEntryDialog ( this.shell ); } this.manualValue = dlg.getValue (); } protected void switchToProcess () { final Map<String, Variant> attributes = new HashMap<String, Variant> (); attributes.put ( "org.openscada.da.manual.value", Variant.NULL ); //$NON-NLS-1$ this.item.writeAtrtibutes ( attributes ); } @Override public void dispose () { this.resourceManager.dispose (); super.dispose (); } protected void updateRemote () { final Boolean remoteManual = this.value.isAttribute ( "remote.manual.active" ); //$NON-NLS-1$ final Variant remoteProcessValue = this.value.getAttributes ().get ( "remote.manual.value.original" ); //$NON-NLS-1$ final Variant remoteManualValue = this.value.getAttributes ().get ( "remote.manual.value" ); //$NON-NLS-1$ if ( remoteManual == null ) { setConnectionState ( this.rp2pConnection, false ); setConnectionState ( this.rm2pConnection, false ); } else if ( remoteManual ) { setConnectionState ( this.rp2pConnection, false ); setConnectionState ( this.rm2pConnection, true ); } else { setConnectionState ( this.rp2pConnection, true ); setConnectionState ( this.rm2pConnection, false ); } if ( remoteManualValue != null ) { this.rmvValue.setText ( remoteManualValue.toString () ); } if ( remoteProcessValue != null ) { this.rpvValue.setText ( remoteProcessValue.toString () ); } } private boolean isLocalManual () { return this.value.isAttribute ( "org.openscada.da.manual.active", false ); //$NON-NLS-1$ } private boolean isRemoteManual () { return this.value.isAttribute ( "remote.manual.active", false ); //$NON-NLS-1$ } private void updateLocalManualValue () { if ( this.manualValue == null ) { this.manualValue = this.value.getAttributes ().get ( "org.openscada.da.manual.value" ); //$NON-NLS-1$ } } @Override protected void update () { super.update (); if ( this.value == null ) { return; } updateRemote (); updateLocalManualValue (); // set result value this.rvValue.setText ( this.value.getValue ().toString () ); final StyleInformation rvStyle = Activator.getStyle ( this.baseStyle, this.value ); this.rvRect.setForegroundColor ( rvStyle.createForeground ( this.resourceManager ) ); this.rvRect.setBackgroundColor ( rvStyle.createBackground ( this.resourceManager ) ); this.rvRect.setFont ( rvStyle.createFont ( this.resourceManager ) ); final StyleInformation pvStyle; if ( isRemoteManual () ) { pvStyle = org.openscada.core.ui.styles.Activator.getStyle ( Style.MANUAL ); } else { pvStyle = this.baseStyle; } this.pvRect.setBackgroundColor ( pvStyle.createBackground ( this.resourceManager ) ); this.pvRect.setForegroundColor ( pvStyle.createForeground ( this.resourceManager ) ); this.pvRect.setFont ( pvStyle.createFont ( this.resourceManager ) ); // set manual value final Variant manualValue = this.value.getAttributes ().get ( "org.openscada.da.manual.value" ); //$NON-NLS-1$ final Variant processValue = this.value.getAttributes ().get ( "org.openscada.da.manual.value.original" ); //$NON-NLS-1$ Variant processError = this.value.getAttributes ().get ( "org.openscada.da.manual.error.original" ); //$NON-NLS-1$ if ( processError == null ) { processError = Variant.FALSE; } if ( manualValue != null ) { this.mvValue.setText ( manualValue.toString () ); } else { this.mvValue.setText ( Messages.ManualOverride_None ); } if ( isLocalManual () ) { setConnectionState ( this.p2rConnection, false ); setConnectionState ( this.m2rConnection, true ); // set process value if ( processValue != null ) { this.pvValue.setText ( processValue.toString () ); } else { this.pvValue.setText ( Messages.ManualOverride_None ); } if ( processError.asBoolean () ) { this.pvRect.setBackgroundColor ( ColorConstants.red ); } } else { setConnectionState ( this.p2rConnection, true ); setConnectionState ( this.m2rConnection, false ); this.pvValue.setText ( this.value.getValue ().toString () ); } } /** * Set graphics attribute according to the connection state * @param connection the connection to change * @param state the state */ protected void setConnectionState ( final PolylineConnection connection, final boolean state ) { final PolygonDecoration dec = new PolygonDecoration (); dec.setTemplate ( PolygonDecoration.TRIANGLE_TIP ); connection.setLineStyle ( state ? Graphics.LINE_SOLID : Graphics.LINE_DOT ); connection.setLineWidth ( state ? 2 : 1 ); connection.setTargetDecoration ( state ? dec : null ); } @Override protected boolean isAvailable () { return hasAttribute ( "org.openscada.da.manual.active" ); } }