android: AndrOBD library vendored (no submodule, no git link)

This commit is contained in:
“Naeel”
2026-05-25 09:36:38 +04:00
parent 361fe8803d
commit b3b044572c
193 changed files with 61446 additions and 8 deletions
+38
View File
@@ -0,0 +1,38 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.util.Map;
/**
* generic Handler interface for mapped Data
*
* @author $Author: erwin $
*/
interface DataMapHandler
{
/**
* handle a set/map of data attributes
*
* @param data Map of new data attributes to handle
* @return previous value of corresponding data item
*/
@SuppressWarnings("rawtypes")
Object handleData(Map data);
}
+142
View File
@@ -0,0 +1,142 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Vector;
import java.util.logging.Level;
/**
* Database backed process variable
*
* @author erwin
*/
public class DbProcessVar extends IndexedProcessVar
{
/**
*
*/
private static final long serialVersionUID = 1080116313924821619L;
@SuppressWarnings({"rawtypes", "unchecked"})
private static final Vector<String> fields = new Vector();
/**
* Holds value of property dbConnection.
*/
private Connection dbConnection;
/**
* Holds value of property tableName.
*/
private String tableName;
/** Creates a new instance of DbProcessVar */
private DbProcessVar()
{
}
public DbProcessVar(Connection dbConn)
{
this();
setDbConnection(dbConn);
}
public DbProcessVar(Connection dbConn, String tableName)
{
this();
setDbConnection(dbConn);
setTableName(tableName);
}
/**
* return all available field names
*/
public String[] getFields()
{
return ((String[]) fields.toArray());
}
/**
* Getter for property dbConnection.
*
* @return Value of property dbConnection.
*/
public Connection getDbConnection()
{
return this.dbConnection;
}
/**
* Setter for property dbConnection.
*
* @param dbConnection New value of property dbConnection.
*/
private void setDbConnection(Connection dbConnection)
{
this.dbConnection = dbConnection;
}
/**
* Getter for property tableName.
*
* @return Value of property tableName.
*/
public String getTableName()
{
return this.tableName;
}
/**
* Setter for property tableName.
*
* @param tableName New value of property tableName.
*/
private void setTableName(String tableName)
{
this.tableName = tableName;
}
protected String getSelectSQL()
{
return ("SELECT * from " + tableName);
}
protected ResultSet getResultSet(String sqlQuery)
{
ResultSet set = null;
ResultSetMetaData rsMd;
try
{
set = dbConnection.createStatement().executeQuery(sqlQuery);
rsMd = set.getMetaData();
for (int i = 0; i < rsMd.getColumnCount(); i++)
{
fields.add(i, rsMd.getColumnName(i));
}
} catch (Exception e)
{
log.log(Level.SEVERE, e.toString(), e);
}
return (set);
}
}
+88
View File
@@ -0,0 +1,88 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
/**
* Process variable @see ProcessVar which allows indexed access
* to attribute fields
*
* @author $Author: erwin $
*/
public abstract class IndexedProcessVar extends ProcessVar
{
/**
*
*/
private static final long serialVersionUID = 8478458496218575203L;
/** return all available field names */
public abstract String[] getFields();
protected IndexedProcessVar()
{
String flds[] = getFields();
for (int i = 0; i < flds.length; i++)
{
put(flds[i], null);
}
}
/** indexed get for specified field id */
public Object get(int fieldID)
{
return (get(getFields()[fieldID]));
}
/** indexed put for specified field id */
public void put(int fieldID, Object newValue)
{
put(getFields()[fieldID], newValue);
}
/**
* get attribute of selected key
* overridden method to allow synchronized access
*
* @param fieldIndex index to key of attribute
* @return value of attribute
*/
public int getAsInt(int fieldIndex)
{
return (getAsInt(getFields()[fieldIndex]));
}
/**
* set attribute of selected key to selected value
* overridden method to allow notification of process var changes
*
* @param fieldIndex index to key of attribute
* @param value value of attribute
*/
public void putAsInt(int fieldIndex, int value)
{
putAsInt(getFields()[fieldIndex], value);
}
/** indexed put for specified field id */
public Object remove(int fieldID)
{
return (remove(getFields()[fieldID]));
}
}
+466
View File
@@ -0,0 +1,466 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
// For logging ...
/**
* single Process variable containing all attributes of a process object
*
* @author $Author: erwin $
*/
@SuppressWarnings("rawtypes")
public class ProcessVar
extends HashMap
implements PvChangeListener, Serializable
{
/**
*
*/
private static final long serialVersionUID = 7072161686290674442L;
/** name of key attribute */
private Object KeyAttribute = null;
/** default key attribute name */
static final String DEF_KEYNAME = "key";
/** time of last change * */
private long lastChange = 0;
/** type of last change * */
private int lastChangeType = PvChangeEvent.PV_ADDED;
/** default change action */
int defaultAction = PvChangeEvent.PV_NOACTION;
/** flag if to allow ChangeEvents to be fired */
boolean allowEvents = false;
/** list of process var change listeners */
private transient Map<PvChangeListener, Integer> PvChangeListeners =
Collections.synchronizedMap(new HashMap<PvChangeListener, Integer>());
/** Map of attribute changes */
private final Map<Object, PvChangeEvent> changes =
Collections.synchronizedMap(new HashMap<Object, PvChangeEvent>());
/** The logger object */
public static final Logger log = Logger.getLogger(ProcessVar.class.getPackage().getName());
public ProcessVar()
{
clear();
}
public ProcessVar(int initialSize)
{
super(initialSize);
clear();
}
/** construct with a existing Map */
public ProcessVar(Map map)
{
if (map != null)
{
putAll(map);
}
}
/**
* put all attributes from map into current ProcessVar
* - use action for all notifications
*
* @param map data map to put into ProcessVar
* @param action Action code to be used for notifications
* @param allowChildEvents are child events (for each attribute) allowed?
*/
@SuppressWarnings("unchecked")
public synchronized void putAll(Map map, int action, boolean allowChildEvents)
{
// remember flag for event creation
boolean oldAllowEvents = allowEvents;
// disable event creation for each map field
// (we want to send one single event after the full map is handled)
allowEvents = allowChildEvents;
// remember old default action
int oldAction = defaultAction;
// set new action as the default action for all fields
defaultAction = action;
// put all fields to hashmap (using default action)
super.putAll(map);
// restore old default action
defaultAction = oldAction;
// enable event creation again
allowEvents = oldAllowEvents;
// now fire the one and only event for this map change
firePvChanged(new PvChangeEvent(this, getKeyAttribute(), map.values().toArray(), action));
}
/**
* put all attributes from map into current ProcessVar
* - use action for all notifications
*
* @param map data map to put into ProcessVar
* @param action Action code to be used for notifications
*/
private synchronized void putAll(Map map, int action)
{
putAll(map, action, true);
}
/**
* put all attributes from map into current ProcessVar
* - use default action for all notifications
*
* @param map data map to put into ProcessVar
*/
@Override
public synchronized void putAll(Map map)
{
putAll(map, defaultAction);
}
/**
* handler for process variable changes
* forwarding of child process variables to current handler
*/
public synchronized void pvChanged(PvChangeEvent event)
{
log.finer(toString() + ":Child PvChange:" + event.toString());
firePvChanged(new PvChangeEvent(this,
((ProcessVar) event.getSource()).getKeyValue(),
event.getSource(),
event.getType() | PvChangeEvent.PV_CHILDCHANGE));
}
/** return String representation */
@Override
public String toString()
{
return (getClass().getName() + "[" + getKeyValue() + "]");
}
/**
* set attribute of selected key to selected value
* overridden method to allow notification of process var changes
*
* @param key key of attribute
* @param value value of attribute
* @param action type of action event @see PvChangeEvent
* @return previous value of attribute
*/
@SuppressWarnings("unchecked")
public synchronized Object put(Object key, Object value, int action)
{
Object oldvalue;
// if new value is a child process variable, try to re-use previous one ...
if (value instanceof ProcessVar)
{
// get previous PV
oldvalue = get(key);
if (oldvalue instanceof ProcessVar)
{
// PV is existing
((HashMap) oldvalue).putAll((Map) value);
} else
{
// this will be a new child PV
oldvalue = super.put(key, value);
}
} else
{
// NON child PV
oldvalue = super.put(key, value);
}
if (oldvalue == null)
{
// new attribute -> PV_ADDED
if (value != null)
{
action |= PvChangeEvent.PV_ADDED;
// if we add a new child process variable, add listener for child
if (value instanceof ProcessVar)
{
((ProcessVar) value).addPvChangeListener(this);
}
}
} else
{
// Attribute has changed -> PV_MODIFIED
if (!oldvalue.equals(value))
{
action |= PvChangeEvent.PV_MODIFIED;
} else
{
// Attribute MANUAL_MOD confirmed -> PV_CONFIRMED
PvChangeEvent lstChange = changes.get(key);
if (lstChange != null && (lstChange.getType() & PvChangeEvent.PV_MANUAL_MOD) != 0)
{
action |= PvChangeEvent.PV_CONFIRMED;
}
}
}
firePvChanged(new PvChangeEvent(this, key, value, action));
// .. and return
return (oldvalue);
}
/**
* set attribute of selected key to selected value
* overridden method to allow notification of process var changes
*
* @param key key of attribute
* @param value value of attribute
* @return previous value of attribute
*/
@Override
public synchronized Object put(Object key, Object value)
{
// find out the type of the action
int action = containsKey(key) ? defaultAction : PvChangeEvent.PV_ADDED;
// and perform the put operation
return (put(key, value, action));
}
/**
* get attribute of selected key
* overridden method to allow synchronized access
*
* @param key key of attribute
* @return value of attribute
*/
@Override
public synchronized Object get(Object key)
{
return (super.get(key));
}
/**
* get attribute of selected key as int value
* overridden method to allow synchronized access
*
* @param key key of attribute
* @return value of attribute
*/
synchronized int getAsInt(Object key)
{
int result = 0;
Object val = get(key);
try
{
if (val != null)
{
result = Integer.valueOf(val.toString()).intValue();
}
} catch (NumberFormatException e)
{
// Intentionally do nothing
}
return (result);
}
/**
* set attribute of selected key to selected value
* overridden method to allow notification of process var changes
*
* @param key key of attribute
* @param value value of attribute
*/
synchronized void putAsInt(Object key, int value)
{
put(key, Integer.valueOf(value));
}
/**
* remove attribute with selected key
* overridden method to allow notification of process var changes
*
* @param key key of attribute
* @return previous value of attribute
*/
@Override
public synchronized Object remove(Object key)
{
Object result = super.remove(key);
if (result != null)
{
firePvChanged(new PvChangeEvent(this, key, null, PvChangeEvent.PV_DELETED));
}
// if old object was a process variable, we need to remove change listener
if (result instanceof ProcessVar)
{
((ProcessVar) result).removePvChangeListener(this);
}
return (result);
}
/**
* remove all attributes from process var
* overridden clear method to allow notification of process var changes
*/
@Override
public synchronized void clear()
{
// now really clear the hashmap
super.clear();
// notify listeners of removal
firePvChanged(new PvChangeEvent(this, null, null, PvChangeEvent.PV_CLEARED));
}
/** get object/name of key attribute */
public Object getKeyAttribute()
{
return (KeyAttribute != null ? KeyAttribute : DEF_KEYNAME);
}
/** set object/name of key attribute */
public void setKeyAttribute(Object newKeyAttribute)
{
KeyAttribute = newKeyAttribute;
}
/** get value of key attribute */
public Object getKeyValue()
{
return (get(getKeyAttribute()));
}
/** set value of key attribute */
public void setKeyValue(Object newKeyValue)
{
put(getKeyAttribute(), newKeyValue);
}
/**
* ensure there is a list of PvChangeListeners
* * it may be null, if PV has been de-serialized
*/
private void ensurePvChangeListeners()
{
if (PvChangeListeners == null)
PvChangeListeners = new HashMap<PvChangeListener, Integer>();
}
/**
* Handling for list of PvChangeListeners
*/
/** remove listener for Pv changes */
public synchronized void removePvChangeListener(PvChangeListener l)
{
ensurePvChangeListeners();
PvChangeListeners.remove(l);
allowEvents = !PvChangeListeners.isEmpty();
log.finer("-PvListener:" + toString() + "->" + String.valueOf(l));
}
/**
* add listener for Pv changes with specified change events
*
* @param l event listener to be registered
* @param eventMask events the listener wants to be notified about
*/
public synchronized void addPvChangeListener(PvChangeListener l, int eventMask)
{
ensurePvChangeListeners();
PvChangeListeners.put(l, Integer.valueOf(eventMask));
allowEvents = true;
log.finer("+PvListener:" + toString() + "->" + String.valueOf(l));
}
/**
* add listener for Pv changes
*
* @param l event listener to be registered
*/
public synchronized void addPvChangeListener(PvChangeListener l)
{
addPvChangeListener(l, PvChangeEvent.PV_ALLEVENTS);
}
/**
* fire a Pv Change event
*
* @param e the event to be fired
*/
public synchronized void firePvChanged(PvChangeEvent e)
{
if (allowEvents && e.getType() != PvChangeEvent.PV_NOACTION)
{
log.finer("PvChange:" + e.toString());
Integer evtMask;
Map.Entry curr;
ensurePvChangeListeners();
// loop through all registered listeners ...
Set entries = PvChangeListeners.entrySet();
Iterator it = entries.iterator();
while (it.hasNext())
{
curr = (Map.Entry) it.next();
if (curr.getKey() != null && curr.getKey() != this)
{
// check if listener wants to be notified by this event
evtMask = (Integer) curr.getValue();
if ((evtMask.intValue() & e.getType()) != 0)
{
log.finer("Notify:" + curr);
((PvChangeListener) curr.getKey()).pvChanged(e);
}
}
}
// set time and type of last change
lastChange = e.getTime();
lastChangeType = e.getType();
changes.put(e.getKey(), e);
}
}
/**
* Getter for property values.
*
* @return Value of property values.
*/
public Map getValueMap()
{
return this;
}
/**
* Setter for property values.
*
* @param values New value of property values.
*/
public void setValueMap(Map values)
{
putAll(values);
}
}
+111
View File
@@ -0,0 +1,111 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.util.EventObject;
/**
* Event to notify about changes to a process variable
*
* @author $Author: erwin $
*/
public class PvChangeEvent extends EventObject
{
/**
*
*/
private static final long serialVersionUID = 4378855847270229897L;
public static final int PV_NOACTION = 0x00; /**< NO specified PV action */
public static final int PV_ADDED = 0x01; /**< new Process var was added */
public static final int PV_DELETED = 0x02; /**< process var was deleted */
public static final int PV_MODIFIED = 0x04; /**< process var was modified */
public static final int PV_CONFIRMED = 0x08; /**< process var was confirmed */
public static final int PV_MANUAL_MOD = 0x10; /**< process var was modified manually */
public static final int PV_CLEARED = 0x20; /**< process var was cleared */
public static final int PV_ERROR = 0x40; /**< process var has an error */
public static final int PV_ELIMINATED = 0x80; /**< process var got eliminated */
public static final int PV_CHILDCHANGE = 0x8000000; /**< child process var change */
private static final int PV_ALLACTIONS = ~PV_CHILDCHANGE; /**< mask for all actions */
public static final int PV_ALLEVENTS = 0xFFFFFFFF; /**< mask for all change types */
private int type = PV_MODIFIED;
private Object key = ProcessVar.DEF_KEYNAME;
private Object value = ProcessVar.DEF_KEYNAME;
private long time = System.currentTimeMillis();
public PvChangeEvent(Object source, Object Key, Object Value, int Type)
{
super(source);
setType(Type);
setKey(Key);
setValue(Value);
}
public int getType()
{
return (type & PV_ALLACTIONS);
}
public boolean isChildEvent()
{
return (type & PV_CHILDCHANGE) != 0;
}
private void setType(int newType)
{
type = newType;
}
private void setKey(Object newKey)
{
key = newKey;
}
public Object getKey()
{
return (key);
}
private void setValue(Object newValue)
{
value = newValue;
}
public Object getValue()
{
return (value);
}
/** return String Representation of Event */
@Override
public String toString()
{
return (String.valueOf(getType()) + ":" + getKey() + "=" + getValue());
}
public long getTime()
{
return time;
}
public void setTime(long time)
{
this.time = time;
}
}
+36
View File
@@ -0,0 +1,36 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.util.EventListener;
/**
* Listener interface for notification of process variable changes
*
* @author $Author: erwin $
*/
public interface PvChangeListener extends EventListener
{
/**
* handler for process variable changes
*/
void pvChanged(PvChangeEvent event);
}
+174
View File
@@ -0,0 +1,174 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
/**
* Range check to allow checking a process var to be within certain range
*
* @author erwin
*/
public class PvLimits
{
/** result codes */
/** value is within specified range */
private static final byte RC_WITHIN_RANGE = 0x00;
/** value is above specified range */
private static final byte RC_ABOVE_RANGE = 0x01;
/** value is below specified range */
private static final byte RC_BELOW_RANGE = 0x02;
/** minimum limit for range check */
@SuppressWarnings("rawtypes")
private Comparable minValue;
/** maximum limit for range check */
@SuppressWarnings("rawtypes")
private Comparable maxValue;
/**
* Creates a new instance of PvLimits
*/
public PvLimits()
{
}
/**
* Creates a new instance of PvLimits
*
* @param minVal minimum Limit for range check. Setting this value to NULL disables
* the check for value above limit
* @param maxVal maximum Limit for range check. Setting this value to NULL disables
* the check for value below limit
*/
@SuppressWarnings("rawtypes")
public PvLimits(Comparable minVal, Comparable maxVal)
{
minValue = minVal;
maxValue = maxVal;
}
/**
* Getter for property minValue.
*
* @return Value of property minValue.
*/
@SuppressWarnings("rawtypes")
public Comparable getMinValue()
{
return this.minValue;
}
/**
* Setter for property minValue.
*
* @param minValue New value of property minValue.
*/
@SuppressWarnings("rawtypes")
public void setMinValue(Comparable minValue)
{
this.minValue = minValue;
}
/**
* Getter for property maxValue.
*
* @return Value of property maxValue.
*/
@SuppressWarnings("rawtypes")
public Comparable getMaxValue()
{
return this.maxValue;
}
/**
* Setter for property maxValue.
*
* @param maxValue New value of property maxValue.
*/
@SuppressWarnings("rawtypes")
public void setMaxValue(Comparable maxValue)
{
this.maxValue = maxValue;
}
/**
* check a value against defined range This method may be called from a static
* context
*
* @param value the value to be checked
* @param minLimit minimum Limit for range check.
* @param maxLimit maximum Limit for range check.
* @return bitmasked check result
* @see PvLimits#RC_WITHIN_RANGE
* @see PvLimits#RC_ABOVE_RANGE
* @see PvLimits#RC_BELOW_RANGE
*/
private static byte checkRange(Object value, Comparable<Object> minLimit,
Comparable<Object> maxLimit)
{
byte retVal = RC_WITHIN_RANGE;
// check Range Minimum
if (minLimit != null && minLimit.compareTo(value) > 0)
retVal |= RC_BELOW_RANGE;
// check Range Maximum
if (maxLimit != null && maxLimit.compareTo(value) < 0)
retVal |= RC_ABOVE_RANGE;
return (retVal);
}
/**
* check a value against range defined within class instance
*
* @param value the value to be checked
* @return bitmasked check result
* @see PvLimits#RC_WITHIN_RANGE
* @see PvLimits#RC_ABOVE_RANGE
* @see PvLimits#RC_BELOW_RANGE
*/
@SuppressWarnings("unchecked")
public byte checkRange(Object value)
{
return (checkRange(value, minValue, maxValue));
}
/**
* return value limited against range defined within class instance
*
* @param value the value to be checked
* @return value limited to limits
*/
@SuppressWarnings("unchecked")
public Object limitedValue(Object value)
{
Object result;
switch (checkRange(value, minValue, maxValue))
{
case RC_BELOW_RANGE:
result = minValue;
break;
case RC_ABOVE_RANGE:
result = maxValue;
break;
default:
result = value;
}
return result;
}
}
+105
View File
@@ -0,0 +1,105 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs;
import java.util.Map;
/**
* List of multiple Process vars of the same type<br>
* all the process variables are stored/identified by their key value
*
* @author $Author: erwin $
*/
public class PvList extends ProcessVar
implements DataMapHandler
{
/**
*
*/
private static final long serialVersionUID = -4024558082429586661L;
public PvList()
{
}
public PvList(Object key)
{
super.setKeyAttribute(key);
}
/**
* handle a set/map of data attributes with specified notification action
*
* @param data Map of new data attributes to handle
* @param action PvChangeEvent-Action code to be used for notifications
* @param allowChildEvents are child events (for each attribute) allowed?
* @return previous value of corresponding data item
*/
@SuppressWarnings("rawtypes")
private synchronized Object handleData(Map data, int action, boolean allowChildEvents)
{
Object result = null;
if (data.containsKey(getKeyAttribute()))
{
// remember flag for event creation
boolean oldAllowEvents = allowEvents;
// set flag for event creation
allowEvents = allowChildEvents;
ProcessVar dataset = (ProcessVar) get(data.get(getKeyAttribute()));
if (dataset == null)
{
dataset = new ProcessVar();
dataset.setKeyAttribute(getKeyAttribute());
}
dataset.putAll(data, action, allowChildEvents);
// restore flag for event creation
allowEvents = oldAllowEvents;
result = put(dataset.getKeyValue(), dataset, action);
}
return (result);
}
/**
* handle a set/map of data attributes with specified notification action
*
* @param data Map of new data attributes to handle
* @param action PvChangeEvent-Action code to be used for notifications
* @return previous value of corresponding data item
*/
@SuppressWarnings("rawtypes")
private synchronized Object handleData(Map data, int action)
{
return (handleData(data, action, false));
}
/**
* handle a set/map of data attributes with default notification action
*
* @param data Map of new data attributes to handle
* @return previous value of corresponding data item
*/
@SuppressWarnings("rawtypes")
public synchronized Object handleData(Map data)
{
return (handleData(data, defaultAction));
}
}
+275
View File
@@ -0,0 +1,275 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.SimpleBeanInfo;
/**
* @author esh
*/
class ProcessVarBeanInfo extends SimpleBeanInfo
{
// Bean descriptor//GEN-FIRST:BeanDescriptor
/*lazy BeanDescriptor*/
private static BeanDescriptor getBdescriptor()
{
// Here you can add code for customizing the BeanDescriptor.
return new BeanDescriptor(ProcessVar.class, PvDetailPanel.class);
}//GEN-LAST:BeanDescriptor
// Property identifiers//GEN-FIRST:Properties
private static final int PROPERTY_empty = 0;
private static final int PROPERTY_keyAttribute = 1;
private static final int PROPERTY_keyValue = 2;
private static final int PROPERTY_valueMap = 3;
// Property array
/*lazy PropertyDescriptor*/
private static PropertyDescriptor[] getPdescriptor()
{
PropertyDescriptor[] properties = new PropertyDescriptor[4];
try
{
properties[PROPERTY_empty] = new PropertyDescriptor("empty", ProcessVar.class, "isEmpty", null);
properties[PROPERTY_keyAttribute] = new PropertyDescriptor("keyAttribute", ProcessVar.class, "getKeyAttribute", "setKeyAttribute");
properties[PROPERTY_keyValue] = new PropertyDescriptor("keyValue", ProcessVar.class, "getKeyValue", "setKeyValue");
properties[PROPERTY_valueMap] = new PropertyDescriptor("valueMap", ProcessVar.class, "getValueMap", "setValueMap");
properties[PROPERTY_valueMap].setPropertyEditorClass(PvDetailPanel.class);
} catch (IntrospectionException ignored)
{
}//GEN-HEADEREND:Properties
// Here you can add code for customizing the properties array.
return properties;
}//GEN-LAST:Properties
// EventSet identifiers//GEN-FIRST:Events
private static final int EVENT_pvChangeListener = 0;
// EventSet array
/*lazy EventSetDescriptor*/
private static EventSetDescriptor[] getEdescriptor()
{
EventSetDescriptor[] eventSets = new EventSetDescriptor[1];
try
{
eventSets[EVENT_pvChangeListener] = new EventSetDescriptor(com.fr3ts0n.pvs.ProcessVar.class, "pvChangeListener", com.fr3ts0n.pvs.PvChangeListener.class, new String[]{"pvChanged"}, "addPvChangeListener", "removePvChangeListener");
} catch (IntrospectionException ignored)
{
}//GEN-HEADEREND:Events
// Here you can add code for customizing the event sets array.
return eventSets;
}//GEN-LAST:Events
// Method identifiers//GEN-FIRST:Methods
private static final int METHOD_addPvChangeListener0 = 0;
private static final int METHOD_clear1 = 1;
private static final int METHOD_clone2 = 2;
private static final int METHOD_containsKey3 = 3;
private static final int METHOD_containsValue4 = 4;
private static final int METHOD_entrySet5 = 5;
private static final int METHOD_equals6 = 6;
private static final int METHOD_get7 = 7;
private static final int METHOD_hashCode8 = 8;
private static final int METHOD_keySet9 = 9;
private static final int METHOD_put10 = 10;
private static final int METHOD_putAll11 = 11;
private static final int METHOD_pvChanged12 = 12;
private static final int METHOD_remove13 = 13;
private static final int METHOD_size14 = 14;
private static final int METHOD_toString15 = 15;
private static final int METHOD_values16 = 16;
// Method array
/*lazy MethodDescriptor*/
private static MethodDescriptor[] getMdescriptor()
{
MethodDescriptor[] methods = new MethodDescriptor[17];
try
{
methods[METHOD_addPvChangeListener0] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("addPvChangeListener",
com.fr3ts0n.pvs.PvChangeListener.class, Integer.TYPE));
methods[METHOD_addPvChangeListener0].setDisplayName("");
methods[METHOD_clear1] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("clear"));
methods[METHOD_clear1].setDisplayName("");
methods[METHOD_clone2] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("clone"));
methods[METHOD_clone2].setDisplayName("");
methods[METHOD_containsKey3] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("containsKey",
Object.class));
methods[METHOD_containsKey3].setDisplayName("");
methods[METHOD_containsValue4] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("containsValue",
Object.class));
methods[METHOD_containsValue4].setDisplayName("");
methods[METHOD_entrySet5] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("entrySet"));
methods[METHOD_entrySet5].setDisplayName("");
methods[METHOD_equals6] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("equals",
Object.class));
methods[METHOD_equals6].setDisplayName("");
methods[METHOD_get7] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("get",
Object.class));
methods[METHOD_get7].setDisplayName("");
methods[METHOD_hashCode8] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("hashCode"));
methods[METHOD_hashCode8].setDisplayName("");
methods[METHOD_keySet9] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("keySet"));
methods[METHOD_keySet9].setDisplayName("");
methods[METHOD_put10] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("put",
Object.class, Object.class, Integer.TYPE));
methods[METHOD_put10].setDisplayName("");
methods[METHOD_putAll11] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("putAll",
java.util.Map.class, Integer.TYPE, Boolean.TYPE));
methods[METHOD_putAll11].setDisplayName("");
methods[METHOD_pvChanged12] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("pvChanged",
com.fr3ts0n.pvs.PvChangeEvent.class));
methods[METHOD_pvChanged12].setDisplayName("");
methods[METHOD_remove13] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("remove",
Object.class));
methods[METHOD_remove13].setDisplayName("");
methods[METHOD_size14] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("size"));
methods[METHOD_size14].setDisplayName("");
methods[METHOD_toString15] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("toString"));
methods[METHOD_toString15].setDisplayName("");
methods[METHOD_values16] = new MethodDescriptor(com.fr3ts0n.pvs.ProcessVar.class.getMethod("values"));
methods[METHOD_values16].setDisplayName("");
} catch (Exception ignored)
{
}//GEN-HEADEREND:Methods
// Here you can add code for customizing the methods array.
return methods;
}//GEN-LAST:Methods
private static final int defaultPropertyIndex = -1;//GEN-BEGIN:Idx
private static final int defaultEventIndex = -1;//GEN-END:Idx
@SuppressWarnings("rawtypes")
public BeanInfo[] getAdditionalBeanInfo()
{//GEN-FIRST:Superclass
Class superclass = ProcessVar.class.getSuperclass();
BeanInfo sbi = null;
try
{
sbi = Introspector.getBeanInfo(superclass);//GEN-HEADEREND:Superclass
// Here you can add code for customizing the Superclass BeanInfo.
} catch (IntrospectionException ignored)
{
}
return new BeanInfo[]{sbi};
}//GEN-LAST:Superclass
/**
* Gets the bean's <code>BeanDescriptor</code>s.
*
* @return BeanDescriptor describing the editable
* properties of this bean. May return null if the
* information should be obtained by automatic analysis.
*/
public BeanDescriptor getBeanDescriptor()
{
return getBdescriptor();
}
/**
* Gets the bean's <code>PropertyDescriptor</code>s.
*
* @return An array of PropertyDescriptors describing the editable
* properties supported by this bean. May return null if the
* information should be obtained by automatic analysis.
* If a property is indexed, then its entry in the result array will
* belong to the IndexedPropertyDescriptor subclass of PropertyDescriptor.
* A client of getPropertyDescriptors can use "instanceof" to check
* if a given PropertyDescriptor is an IndexedPropertyDescriptor.
*/
public PropertyDescriptor[] getPropertyDescriptors()
{
return getPdescriptor();
}
/**
* Gets the bean's <code>EventSetDescriptor</code>s.
*
* @return An array of EventSetDescriptors describing the kinds of
* events fired by this bean. May return null if the information
* should be obtained by automatic analysis.
*/
public EventSetDescriptor[] getEventSetDescriptors()
{
return getEdescriptor();
}
/**
* Gets the bean's <code>MethodDescriptor</code>s.
*
* @return An array of MethodDescriptors describing the methods
* implemented by this bean. May return null if the information
* should be obtained by automatic analysis.
*/
public MethodDescriptor[] getMethodDescriptors()
{
return getMdescriptor();
}
/**
* A bean may have a "default" property that is the property that will
* mostly commonly be initially chosen for update by human's who are
* customizing the bean.
*
* @return Index of default property in the PropertyDescriptor array
* returned by getPropertyDescriptors.
* <P> Returns -1 if there is no default property.
*/
public int getDefaultPropertyIndex()
{
return defaultPropertyIndex;
}
/**
* A bean may have a "default" event that is the event that will
* mostly commonly be used by human's when using the bean.
*
* @return Index of default event in the EventSetDescriptor array
* returned by getEventSetDescriptors.
* <P> Returns -1 if there is no default event.
*/
public int getDefaultEventIndex()
{
return defaultEventIndex;
}
}
@@ -0,0 +1,32 @@
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import java.awt.datatransfer.DataFlavor;
class PvDataFlavor extends DataFlavor
{
private static final String PV_MIME_TYPE = "application/processvar";
public PvDataFlavor()
{
super(ProcessVar.class, PV_MIME_TYPE);
}
public PvDataFlavor(String arg0) throws ClassNotFoundException
{
super(arg0);
}
public PvDataFlavor(String arg0, String arg1)
{
super(arg0, arg1);
}
public PvDataFlavor(String arg0, String arg1, ClassLoader arg2)
throws ClassNotFoundException
{
super(arg0, arg1, arg2);
}
}
+255
View File
@@ -0,0 +1,255 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import com.fr3ts0n.pvs.PvChangeListener;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.Customizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.text.JTextComponent;
/**
* panel class to display / edit a parocess variable and all it's attributes
*
* @author $Author: erwin $
*/
public class PvDetailPanel extends JPanel
implements ActionListener, PvChangeListener, Customizer
{
/**
*
*/
private static final long serialVersionUID = 740664204205911504L;
// field background colors
private static final Color unchangedColor = Color.white;
private static final Color changedColor = Color.lightGray;
private static final Color labelColor = Color.lightGray;
private static final LineBorder lineBorder = new LineBorder(Color.BLACK);
private final HashMap<Object, JComponent> fields = new HashMap<Object, JComponent>();
private ProcessVar dataSource = null;
private boolean editable = false;
public PvDetailPanel()
{
setLayout(new GridBagLayout());
setBackground(labelColor);
setBorder(lineBorder);
}
/**
* create a panel of detailed information on current process variable
*/
public PvDetailPanel(ProcessVar data)
{
this();
setProcessVar(data);
}
/**
* create a panel of detailed information on current process variable
*/
public PvDetailPanel(ProcessVar data, boolean allowEdit)
{
this();
setEditable(allowEdit);
setProcessVar(data);
}
/**
* set the process var which is assigned to this editor panel
* this creates all corresponding data fields
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private void setProcessVar(ProcessVar data)
{
if (dataSource == null || !dataSource.equals(data))
{
// remove all child components, if they have been set already
if (dataSource != null && !dataSource.equals(data))
{
dataSource.removePvChangeListener(this);
fields.clear();
removeAll();
}
// update data source variable
dataSource = data;
// if data source is anything real ...
if (data != null)
{
Object currKey;
Object currVal;
JLabel hdrCmp;
JComponent dataCmp;
GridBagConstraints attr = new GridBagConstraints();
// ... fill content panel with data
ArrayList keys = new ArrayList(data.keySet());
// sort list alphabetically
Collections.sort(keys);
Iterator it = keys.iterator();
// loop through all attributes
while (it.hasNext())
{
/* set default attributes */
attr.gridwidth = 1;
attr.gridheight = 1;
attr.weightx = 0.0;
attr.fill = GridBagConstraints.BOTH;
if ((currKey = it.next()) != null)
{
hdrCmp = new JLabel(currKey.toString());
hdrCmp.setBackground(labelColor);
hdrCmp.setBorder(lineBorder);
// setup data component based on it's value
if ((currVal = data.get(currKey)) == null)
{
dataCmp = new JLabel();
} else
{
if (currVal instanceof ProcessVar)
{
dataCmp = new PvDetailPanel((ProcessVar) currVal, editable);
} else
{
dataCmp = new JTextField(data.get(currKey).toString());
((JTextField) dataCmp).setEditable(editable);
((JTextField) dataCmp).addActionListener(this);
}
}
dataCmp.setName(currKey.toString());
// add the components
add(hdrCmp, attr);
attr.gridwidth = GridBagConstraints.REMAINDER;
attr.weightx = 1.0;
add(dataCmp, attr);
// add data component to Hashmap of fields
fields.put(currKey, dataCmp);
}
}
// add 'this' panel as PvChangeListener to Process variable
data.addPvChangeListener(this, PvChangeEvent.PV_ADDED | PvChangeEvent.PV_MODIFIED);
}
validate();
}
}
/** Implementation of Customizer interface */
public void setObject(Object bean)
{
setEditable(true);
setProcessVar((ProcessVar) bean);
}
/** return the process var which is assigned to this editor panel */
public ProcessVar getProcessVar()
{
return (dataSource);
}
/** return if the process this editor panel is editable */
public boolean getEditable()
{
return (editable);
}
/** set this editor panel to be non-/editable */
private void setEditable(boolean newEditable)
{
editable = newEditable;
}
/**
* action handler for edit fields within panel
* this handler also temporarily changes the color of the edit field to
* visibly indicate the update action.
*/
public void actionPerformed(ActionEvent e)
{
// find out which field sends the event
JTextField edit = (JTextField) e.getSource();
// update the corresponding process var
dataSource.put(edit.getName(), edit.getText(), PvChangeEvent.PV_MANUAL_MOD);
// indicate change by changing field's background color
edit.setBackground(changedColor);
Toolkit.getDefaultToolkit().beep();
}
protected void finalize() throws Throwable
{
dataSource.removePvChangeListener(this);
fields.clear();
removeAll();
super.finalize();
}
/**
* handler for process variable changes
* update dialog element from process variable
*/
public void pvChanged(PvChangeEvent event)
{
// only update panel if it is displayable
if (isDisplayable())
{
Component edit = fields.get(event.getKey());
Object value = event.getValue();
// if we have found the corresponding editor field ...
if (edit != null)
{
// set the value and background for it
edit.setBackground(event.getType() == PvChangeEvent.PV_MANUAL_MOD ? changedColor : unchangedColor);
if (edit instanceof JTextComponent)
{
((JTextComponent) edit).setText(value != null ? value.toString() : "");
} else if (edit instanceof JLabel)
{
((JLabel) edit).setText(value != null ? value.toString() : "");
} else if (edit instanceof PvDetailPanel)
{
((PvDetailPanel) edit).setProcessVar((ProcessVar) value);
}
}
}
}
}
+143
View File
@@ -0,0 +1,143 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvList;
import java.awt.Dimension;
import java.awt.ScrollPane;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.DropMode;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;
public class PvExplorer extends JSplitPane implements TreeSelectionListener
{
/** unique serial version ID */
private static final long serialVersionUID = 182596839340890403L;
/** root process variable for tree and initial table display */
ProcessVar pvRoot;
/** PV tree display */
private final JTree pvTree;
/** PV table display */
private final PvTable pvTable;
/** PV List as container for single process variables to be displayed in table */
private final PvList tblList = new PvList();
/** PV transfer handler to handle data transfers within explorer */
private final PvTransferHandler xferHdlr = new PvTransferHandler();
public PvExplorer(ProcessVar pv)
{
setDividerSize(2);
setPreferredSize(new Dimension(640, 480));
pvTree = new JTree(new PvTreeNode(pv));
pvTree.getSelectionModel().addTreeSelectionListener(this);
pvTree.setDragEnabled(true);
pvTree.setDropMode(DropMode.ON_OR_INSERT);
pvTree.setTransferHandler(xferHdlr);
pvTable = new PvTable(pv);
pvTable.setDragEnabled(true);
pvTable.setDropMode(DropMode.ON_OR_INSERT);
pvTable.addMouseListener(tblMouseLstnr);
pvTable.setTransferHandler(xferHdlr);
JScrollPane spPvTree = new JScrollPane(pvTree);
add(spPvTree, JSplitPane.LEFT);
JScrollPane spPvTable = new JScrollPane(pvTable);
add(spPvTable, JSplitPane.RIGHT);
}
@Override
public void valueChanged(TreeSelectionEvent e)
{
TreePath selPath = e.getNewLeadSelectionPath();
if (selPath == null)
return;
ProcessVar pv = PvTreeNode.getPvFromTreePath(selPath);
if (pv instanceof PvList)
{
// if process var is a PV list itself then show it in table
pvTable.setProcessVar(pv);
} else
{
// ... otherwise create a list with PV as contained element
tblList.clear();
tblList.put(pv.getKeyValue(), pv);
pvTable.setProcessVar(tblList);
}
}
/**
* Listener for mouse events on table side
*/
private final MouseListener tblMouseLstnr = new MouseListener()
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() > 1)
{
// find the process var to selected row ...
ProcessVar pv = pvTable.getPvModel().getElementAt(pvTable.getSelectedRow());
// and show a detail panel about it ...
if (pv != null)
{
PvDetailPanel panDetail = new PvDetailPanel(pv, true);
ScrollPane panScr = new ScrollPane();
panScr.setPreferredSize(new Dimension(640, 480));
panScr.add(panDetail);
JOptionPane.showMessageDialog(null, panScr);
}
}
}
@Override
public void mouseEntered(MouseEvent e)
{
}
@Override
public void mouseExited(MouseEvent e)
{
}
@Override
public void mousePressed(MouseEvent e)
{
}
@Override
public void mouseReleased(MouseEvent e)
{
}
};
}
+89
View File
@@ -0,0 +1,89 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import javax.swing.JTable;
/**
* Table GUI object for process variables
*
* @author erwin
*/
public class PvTable extends JTable
{
/**
*
*/
private static final long serialVersionUID = 6339359674123198139L;
private ProcessVar pv;
private PvTableModel pvModel = new PvTableModel();
private final PvTableCellRenderer renderer = new PvTableCellRenderer();
/** Creates a new instance of PvTable */
public PvTable()
{
setRowSelectionAllowed(true);
setDefaultRenderer(Object.class, renderer);
setModel(new javax.swing.table.DefaultTableModel(
new Object[][]{
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}},
new String[]{
"Title 1", "Title 2", "Title 3", "Title 4"
}));
}
/**
* Creates a new instance of PvTable
*
* @param list The process var to display in table
*/
public PvTable(ProcessVar list)
{
setProcessVar(list);
setRowSelectionAllowed(true);
}
/**
* set the process var
*
* @param list The process var to display in table
*/
public void setProcessVar(ProcessVar list)
{
pv = list;
pvModel.setProcessVar(pv);
setModel(pvModel);
}
public PvTableModel getPvModel()
{
return pvModel;
}
public void setPvModel(PvTableModel pvModel)
{
this.pvModel = pvModel;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellRenderer;
/**
* Cell Renderer for PvTable component
*
* @author erwin
*/
public class PvTableCellRenderer extends JLabel
implements TableCellRenderer
{
/**
*
*/
private static final long serialVersionUID = -7686049090382566048L;
private static final EmptyBorder brdr = new EmptyBorder(0, 5, 0, 5);
/** Creates a new instance of PvTableCellRenderer */
public PvTableCellRenderer()
{
setOpaque(true);
setBorder(brdr);
}
/** render a single pv attribute based on location within table */
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column)
{
setFont(table.getFont());
setHorizontalAlignment(value instanceof Number ? RIGHT : LEFT);
setText(String.valueOf(value));
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return (this);
}
}
+218
View File
@@ -0,0 +1,218 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.IndexedProcessVar;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import com.fr3ts0n.pvs.PvChangeListener;
import java.util.Arrays;
import javax.swing.table.AbstractTableModel;
/**
* Data Model to represent a ProcessVar within a Table object
*
* @author erwin
*/
public class PvTableModel extends AbstractTableModel
implements PvChangeListener
{
/**
*
*/
private static final long serialVersionUID = -6777148395276846388L;
protected ProcessVar pv;
protected IndexedProcessVar currRow;
protected Object[] keys;
private String[] colHeaders = {};
/** Creates a new instance of PvTableModel */
public PvTableModel()
{
}
/**
* Creates a new instance of PvTableModel
*
* @param pVar the process variable to represent
*/
public PvTableModel(ProcessVar pVar)
{
setProcessVar(pVar);
}
/**
* update th list of key items for correct location of coordinates
*
* @param pv Process variable
*/
private void updateKeys(ProcessVar pv)
{
keys = pv.keySet().toArray();
Arrays.sort(keys);
}
/**
* set the process variable to be represented
*
* @param pVar the process variable to represent
*/
public synchronized void setProcessVar(ProcessVar pVar)
{
// set the pv
pv = pVar;
updateKeys(pVar);
if (keys.length > 0)
{
currRow = (IndexedProcessVar) pv.get(keys[0]);
colHeaders = currRow.getFields();
fireTableStructureChanged();
}
pv.addPvChangeListener(this, PvChangeEvent.PV_ALLEVENTS);
}
/**
* get number of table rows
*
* @return number of rows to show
*/
public int getRowCount()
{
return (keys != null ? keys.length : 0);
}
/**
* return number of columns
*
* @return number of columns
*/
public int getColumnCount()
{
return (colHeaders.length);
}
/**
* get process var for row
* @param rowIndex row index
* @return process var
*/
public IndexedProcessVar getElementAt(int rowIndex)
{
if (rowIndex < getRowCount())
currRow = (IndexedProcessVar) pv.get(keys[rowIndex]);
return currRow;
}
/**
* get the value for table location (x,y)
*
* @param rowIndex row number
* @param columnIndex column number
* @return value for table location
*/
public Object getValueAt(int rowIndex, int columnIndex)
{
Object result = null;
// if the pv is set ...
if (pv != null)
{
// get the column value
if((currRow = getElementAt(rowIndex)) != null)
{
result = currRow.get(columnIndex);
}
}
return (result);
}
/**
* handle a process variable change
*
* @param event the change event to be handled
*/
public synchronized void pvChanged(PvChangeEvent event)
{
Object key;
int rowId;
try
{
if(event.isChildEvent())
{
key = String.valueOf(event.getValue());
}
else
{
key = event.getKey();
}
rowId = key != null ? Arrays.binarySearch(keys, key) : 0;
switch (event.getType())
{
case PvChangeEvent.PV_CONFIRMED:
case PvChangeEvent.PV_MODIFIED:
case PvChangeEvent.PV_MANUAL_MOD:
fireTableRowsUpdated(rowId, rowId);
break;
case PvChangeEvent.PV_ADDED:
if (pv.size() == 1)
{
setProcessVar(pv);
} else
{
updateKeys(pv);
fireTableRowsInserted(rowId, rowId);
}
break;
case PvChangeEvent.PV_DELETED:
updateKeys(pv);
fireTableRowsDeleted(rowId, rowId);
break;
case PvChangeEvent.PV_CLEARED:
if (keys.length > 0)
{
updateKeys(pv);
}
// w/o data there are NO columns available -> structure change
fireTableStructureChanged();
break;
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/**
* return column name of PID field
*
* @param column specified column number to get name for ...
*/
@Override
public String getColumnName(int column)
{
return (colHeaders[column]);
}
}
+157
View File
@@ -0,0 +1,157 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import java.awt.Point;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
/**
* @author se82wi
*/
public class PvTransferHandler extends TransferHandler
{
/** Serial Version ID */
private static final long serialVersionUID = -3156199604384589468L;
private static final PvDataFlavor processVarFlavor = new PvDataFlavor();
public PvTransferHandler()
{
super("userObject");
}
/* (non-Javadoc)
* @see javax.swing.TransferHandler#getSourceActions(JComponent c)
*/
@Override
public int getSourceActions(JComponent c)
{
return COPY_OR_MOVE;
}
/* (non-Javadoc)
* @see javax.swing.TransferHandler#createTransferable(javax.swing.JComponent)
*/
@Override
protected Transferable createTransferable(JComponent c)
{
if (c instanceof JTree)
{
try
{
JTree tree = (JTree) c;
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getSelectionPath().getLastPathComponent();
ProcessVar pv = (ProcessVar) node.getUserObject();
return (Transferable) pv;
} catch (ClassCastException ex)
{
ProcessVar.log.severe(this.toString() + ":" + ex.getMessage());
}
} else if (c instanceof PvTable)
{
PvTable tab = (PvTable) c;
ProcessVar pv = tab.getPvModel().getElementAt(tab.getSelectedRow());
return (Transferable) pv;
}
// anything else is handled by superclass
return super.createTransferable(c);
}
/* (non-Javadoc)
* @see javax.swing.TransferHandler#exportDone(javax.swing.JComponent, java.awt.datatransfer.Transferable, int)
*/
@Override
protected void exportDone(JComponent c, Transferable t, int action)
{
try
{
if (action == MOVE)
{
ProcessVar pv = (ProcessVar) t.getTransferData(processVarFlavor);
pv.firePvChanged(new PvChangeEvent(pv, pv.getKeyAttribute(), pv, PvChangeEvent.PV_ELIMINATED));
}
} catch (UnsupportedFlavorException e)
{
ProcessVar.log.severe(this.toString() + ":" + e.getMessage());
} catch (IOException e)
{
ProcessVar.log.severe(this.toString() + ":" + e.getMessage());
}
}
/* (non-Javadoc)
* @see javax.swing.TransferHandler#importData(javax.swing.TransferHandler.TransferSupport)
*/
@Override
public boolean importData(TransferSupport support)
{
try
{
if (support.getComponent() instanceof JTree)
{
JTree tree = (JTree) support.getComponent();
Point dropPoint = support.getDropLocation().getDropPoint();
TreePath path = tree.getPathForLocation(dropPoint.x, dropPoint.y);
Object node = path.getLastPathComponent();
if (support.isDataFlavorSupported(processVarFlavor))
{
ProcessVar tVar = (ProcessVar) ((PvTreeNode) node).getUserObject();
ProcessVar chldPv = (ProcessVar) support.getTransferable().getTransferData(processVarFlavor);
Object chldKey = chldPv.getKeyValue();
tVar.put(chldKey, chldPv, PvChangeEvent.PV_ADDED);
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.nodeStructureChanged((TreeNode) model.getRoot());
return true;
}
}
} catch (UnsupportedFlavorException e)
{
ProcessVar.log.severe(this.toString() + ":" + e.getMessage());
} catch (IOException e)
{
ProcessVar.log.severe(this.toString() + ":" + e.getMessage());
}
// anything else is handled by superclass
return super.importData(support);
}
/* (non-Javadoc)
* @see javax.swing.TransferHandler#canImport(javax.swing.TransferHandler.TransferSupport)
*/
@Override
public boolean canImport(TransferSupport support)
{
return support != null
&& support.isDataFlavorSupported(processVarFlavor);
}
}
+152
View File
@@ -0,0 +1,152 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.gui;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import com.fr3ts0n.pvs.PvChangeListener;
import java.util.Iterator;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
/**
* @author se82wi
* Tree node from a process variable
*/
public class PvTreeNode extends DefaultMutableTreeNode
implements PvChangeListener
{
/**
* ProcessVar tree node Renderer
*/
private static final long serialVersionUID = 8478304706986978587L;
public PvTreeNode()
{
super();
}
public PvTreeNode(Object userObject)
{
super(userObject);
setUserObject(userObject);
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.tree.DefaultMutableTreeNode#setUserObject(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public void setUserObject(Object userObject)
{
super.setUserObject(userObject);
if (userObject instanceof ProcessVar)
{
Object currVal;
ProcessVar pv = (ProcessVar) userObject;
// loop through attributes
Iterator<Object> it = pv.values().iterator();
while (it.hasNext())
{
currVal = it.next();
// if there is a child PV, then add it as a tree node
if (currVal instanceof ProcessVar)
add(new PvTreeNode(currVal));
}
pv.addPvChangeListener(this, PvChangeEvent.PV_ADDED
| PvChangeEvent.PV_DELETED
| PvChangeEvent.PV_CLEARED
| PvChangeEvent.PV_ELIMINATED);
}
}
/**
* get process variable from tree node
*
* @param path tree path to find object for
* @return process variable, or null if no process variable found
*/
public static ProcessVar getPvFromTreePath(TreePath path)
{
PvTreeNode selNode = (PvTreeNode) path.getLastPathComponent();
if (selNode == null)
return null;
Object pvObj = selNode.getUserObject();
if (!(pvObj instanceof ProcessVar))
return null;
return (ProcessVar) pvObj;
}
/**
* Find child node containing matching user Object
*
* @param userObject user object to match
* @return matching child node, or
* <pre>null</pre> if nothing has been found
*/
private PvTreeNode findChild(Object userObject)
{
PvTreeNode currNode;
// search through children for matching user object
@SuppressWarnings("unchecked")
Iterator<PvTreeNode> it = children.iterator();
while (it.hasNext())
{
currNode = it.next();
if (userObject == currNode.userObject)
return currNode;
}
// haven't found it -> return NULL
return null;
}
/**
* Handler for PvChangeEvents
*/
@Override
public synchronized void pvChanged(PvChangeEvent pvchangeevent)
{
Object currVal = pvchangeevent.getValue();
if (!(currVal instanceof ProcessVar))
return;
switch (pvchangeevent.getType())
{
case PvChangeEvent.PV_ADDED:
add(new PvTreeNode(currVal));
break;
case PvChangeEvent.PV_CLEARED:
removeAllChildren();
break;
case PvChangeEvent.PV_DELETED:
PvTreeNode pvNode = findChild(currVal);
if (pvNode != null)
pvNode.removeFromParent();
}
}
}
+6
View File
@@ -0,0 +1,6 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
Process variable visualization classes
</body>
</html>
+337
View File
@@ -0,0 +1,337 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.io;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import com.fr3ts0n.pvs.PvChangeListener;
import com.fr3ts0n.pvs.PvList;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* Content handler for ProcessVar XML-Streams
*
* @author $Author: erwin $
*/
public class PvXMLHandler
extends DefaultHandler
{
/** List of XML-Tags handled by this Handler */
private static final String[] XML_TAGS =
{
PvXMLWriter.TAG_PVLIST,
PvXMLWriter.TAG_PROCESSVAR,
PvXMLWriter.TAG_PVATTRIBUTE
};
// numeric indices to above List
/** ID of TAG for PV-List */
static final int TAG_ID_PVLIST = 0;
/** ID for Tag Processvar */
private static final int TAG_ID_PROCESSVAR = 1;
/** ID for tag Attribute */
private static final int TAG_ID_PVATTRIBUTE = 2;
/** Stack of recursive process variables */
private final Stack<Object[]> pvStack = new Stack<Object[]>();
/** The root Process variable to be parsed on */
private com.fr3ts0n.pvs.PvList rootPv = new PvList();
/** currently parsed process variable */
private ProcessVar currPv = rootPv;
/** currently parsed attribute */
private Object currAttrib;
/** currently parsed value for attribute */
private Object currValue;
/** list of process var change listeners */
private final HashMap<PvChangeListener, Integer> PvChangeListeners = new HashMap<PvChangeListener, Integer>();
/** the logger object */
private static final Logger log = Logger.getLogger(PvXMLHandler.class.getPackage().getName());
/**
* Creates a new instance of PvXMLContentHandler
*
* @throws org.xml.sax.SAXException Exception thrown at Instantiation of SAX-parser
*/
private PvXMLHandler()
{
rootPv.setKeyValue("root");
}
/**
* Creates a new instance of PvXMLContentHandler
*
* @throws org.xml.sax.SAXException Exception thrown at Instantiation of SAX-parser
*/
private PvXMLHandler(PvList rootPv)
{
setRootPv(rootPv);
}
/**
* get the numeric ID of XML-Tag
*
* @param tagName Name of XML-Tag
* @return numeric ID for XML-Tag or -1 if nott found
*/
private int getTagID(String tagName)
{
int result = -1;
for (int i = 0; i < XML_TAGS.length; i++)
{
if (XML_TAGS[i].equals(tagName))
{
result = i;
break;
}
}
return (result);
}
/**
* handle incoming Text
*
* @param ch incoming text
* @param start start position
* @param length length of text
*/
public void characters(char[] ch, int start, int length)
{
String currStr = String.copyValueOf(ch, start, length).trim();
// If this is a valid String, then handle it as the new data
if (currStr.length() > 0)
{
log.fine("Chars:'" + currStr + "'");
currValue = currStr;
}
}
/**
* handle start tag of a nw element
*
* @param namespaceURI element's namespace
* @param localName element's local name
* @param qName element's qualified name
* @param atts attributes within element tag
*/
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
{
if (log.isLoggable(Level.FINE))
{
StringBuffer sb = new StringBuffer("StartElement:" + qName + ":");
for (int i = 0; i < atts.getLength(); i++)
{
sb.append(atts.getQName(i)).append("=").append(atts.getValue(i)).append(",");
}
log.fine(sb.toString());
}
int tagID = getTagID(qName);
try
{
switch (tagID)
{
case TAG_ID_PROCESSVAR:
if (currPv != null)
{
pvStack.push(new Object[]{currPv, currAttrib});
}
currPv = (ProcessVar) Class.forName(atts.getValue(PvXMLWriter.ATTR_TYPE)).newInstance();
currPv.setKeyValue(atts.getValue(PvXMLWriter.ATTR_KEY));
break;
case TAG_ID_PVATTRIBUTE:
currAttrib = atts.getValue(PvXMLWriter.ATTR_NAME);
break;
}
} catch (Exception e)
{
e.printStackTrace();
}
}
/**
* handle end tag of element
*
* @param namespaceURI element's namespace
* @param localName element's local name
* @param qName element's qualified name
*/
public void endElement(String namespaceURI, String localName, String qName)
{
log.fine("EndElement:" + qName);
int tagID = getTagID(qName);
switch (tagID)
{
case TAG_ID_PROCESSVAR:
log.fine("PV:" + currPv.toString());
firePvChanged(new PvChangeEvent(this, currPv.getKeyValue(), currPv, PvChangeEvent.PV_CONFIRMED));
currValue = currPv;
// If we have PV's on stack, the new PV is a recursive attribute
if (!pvStack.empty())
{
Object[] stackElems = pvStack.pop();
currPv = (ProcessVar) stackElems[0];
currAttrib = stackElems[1];
} else
{
log.severe("NO more PV's on Stack");
}
if (currPv == rootPv)
{
currAttrib = ((ProcessVar) currValue).getKeyValue();
}
currPv.put(currAttrib, currValue);
break;
case TAG_ID_PVATTRIBUTE:
// if currently parsed PV is null, then we just finished a recursive one
if (currPv != null)
{
// This is a plain attribute
currPv.put(currAttrib, currValue);
}
currValue = null;
break;
}
}
/**
* Handling for list of PvChangeListeners
*/
/**
* remove listener for Pv changes
*
* @param l Listener to be removed
*/
public synchronized void removePvChangeListener(PvChangeListener l)
{
log.fine("-PvListener:" + String.valueOf(this) + "->" + String.valueOf(l));
PvChangeListeners.remove(l);
}
/**
* add listener for Pv changes with specified change events
*
* @param l Listener to be added
* @param eventMask events (Bitmask) which this listener wants to listen on
*/
private synchronized void addPvChangeListener(PvChangeListener l, int eventMask)
{
Object oldListener = PvChangeListeners.get(l);
PvChangeListeners.put(l, Integer.valueOf(eventMask));
if (oldListener == null)
{
log.fine("+PvListener:" + String.valueOf(this) + "->" + String.valueOf(l));
}
}
/**
* add listener for Pv changes
*
* @param l Listener to be added
*/
public void addPvChangeListener(PvChangeListener l)
{
addPvChangeListener(l, PvChangeEvent.PV_ALLEVENTS);
}
/**
* fire a Pv Change event
*
* @param e Event for Process variable change
*/
@SuppressWarnings("rawtypes")
private void firePvChanged(PvChangeEvent e)
{
log.fine("PvChange:" + e.toString());
Integer evtMask;
Map.Entry curr;
Set entries = PvChangeListeners.entrySet();
Iterator it = entries.iterator();
while (it.hasNext())
{
curr = (Map.Entry) it.next();
if (curr.getKey() != null && curr.getKey() != this)
{
// check if listener wants to be notified by this event
evtMask = (Integer) curr.getValue();
if ((evtMask.intValue() & e.getType()) != 0)
{
log.fine("Notify:" + curr);
((PvChangeListener) curr.getKey()).pvChanged(e);
}
}
}
}
public PvList getRootPv()
{
return rootPv;
}
private void setRootPv(PvList mainPV)
{
this.rootPv = mainPV;
this.currPv = mainPV;
}
/**
* main routine for testing class implementation
*
* @param argv command line arguments
*/
public static void main(String[] argv)
{
try
{
// Create a new Parser
PvXMLHandler handler = new PvXMLHandler();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new FileInputStream(argv[0]), handler);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
+241
View File
@@ -0,0 +1,241 @@
/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.pvs.io;
import com.fr3ts0n.pvs.ProcessVar;
import com.fr3ts0n.pvs.PvChangeEvent;
import com.fr3ts0n.pvs.PvChangeListener;
import org.xml.sax.helpers.AttributesImpl;
import java.io.OutputStream;
import java.util.Iterator;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
/**
* XML writer to write Process Variables into an XML-Stream
*
* @author $Author: erwin $
*/
public class PvXMLWriter
implements PvChangeListener
{
private Result xFormResult;
private SAXTransformerFactory factory;
private TransformerHandler handler;
private Transformer serializer;
private boolean documentStarted = false;
/** XML Tag-Names */
public static final String TAG_PVLIST = "PV-LIST";
public static final String TAG_PROCESSVAR = "PV";
public static final String TAG_PVATTRIBUTE = "AT";
/** XML attribute values */
public static final String ATTR_TYPE = "type";
public static final String ATTR_KEY = "key";
public static final String ATTR_NAME = "name";
/**
* Creates a new instance of PvXMLWriter
*/
private PvXMLWriter()
{
try
{
factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
handler = factory.newTransformerHandler();
serializer = handler.getTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
} catch (Exception e)
{
e.printStackTrace();
}
}
/**
* Creates a new instance of PvXMLWriter
*/
public PvXMLWriter(OutputStream oStream)
{
this();
setOutputStream(oStream);
}
/**
* set a stream writer for the handler
*/
private void setOutputStream(OutputStream oStream)
{
try
{
xFormResult = new StreamResult(oStream);
handler.setResult(xFormResult);
} catch (Exception e)
{
e.printStackTrace();
}
}
/**
* initialize document writing
*/
private void startDocument()
{
AttributesImpl attrs = new AttributesImpl();
try
{
handler.startDocument();
handler.startElement("", TAG_PVLIST, TAG_PVLIST, attrs);
documentStarted = true;
} catch (Throwable e)
{
e.printStackTrace();
}
}
/**
* finalize Document writing
*/
private void endDocument()
{
try
{
handler.endElement("", TAG_PVLIST, TAG_PVLIST);
handler.endDocument();
documentStarted = false;
} catch (Throwable e)
{
e.printStackTrace();
}
}
/**
* write a process variable as XML to an output stream
*
* @param pv processVar to write
* @param recursiveDepth Depth of recursive PV writing
* @param completeDoc if TRUE, XML document will be initialized before,
* and finalized after writing this PV
*/
@SuppressWarnings("rawtypes")
private void writePv(ProcessVar pv, int recursiveDepth, boolean completeDoc)
{
Object currKey;
Object currVal;
// Initialize XML-Document
if (completeDoc || !documentStarted)
{
startDocument();
}
try
{
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute("", ATTR_TYPE, ATTR_TYPE, "CDATA", pv.getClass().getName());
attrs.addAttribute("", ATTR_KEY, ATTR_KEY, "CDATA", String.valueOf(pv.getKeyValue()));
handler.startElement("", TAG_PROCESSVAR, TAG_PROCESSVAR, attrs);
if (recursiveDepth > 0)// Loop through all PV-Attributes
{
Iterator it = pv.keySet().iterator();
while (it.hasNext())
{
currKey = it.next();
currVal = pv.get(currKey);
attrs.clear();
attrs.addAttribute("", ATTR_NAME, ATTR_NAME, "CDADTA", currKey.toString());
handler.startElement("", TAG_PVATTRIBUTE, TAG_PVATTRIBUTE, attrs);
if (currVal != null)
{
// If current value is a PV itself ...
if (currVal instanceof ProcessVar)
{
// write recursively
writePv((ProcessVar) currVal, recursiveDepth - 1, false);
} else
{
// Otherwise write PV-Data as attribute
String currStr = currVal.toString();
handler.characters(currStr.toCharArray(), 0, currStr.length());
}
}
// finish attribute XML-element
handler.endElement("", TAG_PVATTRIBUTE, TAG_PVATTRIBUTE);
}
}
// finish PV XNL-element
handler.endElement("", TAG_PROCESSVAR, TAG_PROCESSVAR);
} catch (Throwable e)
{
e.printStackTrace();
}
// Finalize XML document
if (completeDoc)
{
endDocument();
}
}
/**
* write a process variable as XML to an output stream
*
* @param pv processVar to write
* @param recursiveDepth Depth of recursive PV writing
*/
public void writePv(ProcessVar pv, int recursiveDepth)
{
writePv(pv, recursiveDepth, false);
}
/**
* Standard writing of PV
* (uses recursive depth=100, NON complete Doc
*
* @param pv processVar to write
*/
private void writePv(ProcessVar pv)
{
writePv(pv, 100, false);
}
/**
* Implementation of PvChangeListener
*/
public void pvChanged(PvChangeEvent event)
{
// Test für XML-Ausgabe
if (event.getValue() instanceof ProcessVar)
{
writePv((ProcessVar) event.getValue());
}
}
}
+7
View File
@@ -0,0 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
Input / Output and serialisation for Process variables
</body>
</html>
+6
View File
@@ -0,0 +1,6 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
Process variables and PV-related stuff
</body>
</html>