Add observers to graph and tables for auto-refreshing tables.

Fix occasional bug when changing workspace in data laboratory (wrong graphstore columns were used).
Re factor some code.
Esse commit está contido em:
Eduardo Ramos
2014-08-20 01:57:29 +02:00
commit 4eb53b9f6a
12 arquivos alterados com 305 adições e 234 exclusões
@@ -53,10 +53,7 @@ import org.gephi.attribute.time.TimestampSet;
import org.gephi.datalab.api.AttributeColumnsMergeStrategiesController;
import org.gephi.datalab.api.AttributeColumnsController;
import org.gephi.graph.api.Element;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.GraphController;
import org.gephi.graph.store.GraphStoreConfiguration;
import org.gephi.graph.store.TimestampMap;
import org.gephi.utils.StatisticsUtils;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
+4
Ver Arquivo
@@ -24,6 +24,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>graph-api</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>dynamic-api</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>core-library-wrapper</artifactId>
@@ -51,8 +51,7 @@ import org.gephi.datalab.plugin.manipulators.columns.ConvertColumnToDynamic;
import org.gephi.datalab.spi.DialogControls;
import org.gephi.datalab.spi.columns.AttributeColumnsManipulator;
import org.gephi.datalab.spi.columns.AttributeColumnsManipulatorUI;
import org.gephi.datalab.utils.DynamicParser;
import org.gephi.dynamic.utils.DynamicUtilities;
import org.gephi.ui.utils.ColumnTitleValidator;
import org.gephi.ui.utils.IntervalBoundValidator;
import org.netbeans.validation.api.ui.ValidationGroup;
@@ -135,8 +134,8 @@ public class ConvertColumnToDynamicUI extends javax.swing.JPanel implements Attr
manipulator.setTitle(titleTextField.getText());
try {
manipulator.setReplaceColumn(replaceColumn);
manipulator.setLow(DynamicParser.parseTime(intervalStart));
manipulator.setHigh(DynamicParser.parseTime(intervalEnd));
manipulator.setLow(DynamicUtilities.parseTime(intervalStart));
manipulator.setHigh(DynamicUtilities.parseTime(intervalEnd));
} catch (ParseException ex) {
Exceptions.printStackTrace(ex);
}
@@ -44,7 +44,9 @@ package org.gephi.desktop.datalab;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.gephi.attribute.api.Column;
import org.gephi.attribute.api.Table;
/**
* Class to keep available state (in data laboratory) of the columns of a table of a workspace.
@@ -54,7 +56,12 @@ import org.gephi.attribute.api.Column;
public class AvailableColumnsModel {
private static final int MAX_AVAILABLE_COLUMNS = 20;
private ArrayList<Column> availableColumns = new ArrayList<Column>();
private final List<Column> availableColumns = new ArrayList<Column>();
private final Table table;
public AvailableColumnsModel(Table table) {
this.table = table;
}
public boolean isColumnAvailable(Column column) {
return availableColumns.contains(column);
@@ -117,4 +124,21 @@ public class AvailableColumnsModel {
public int getAvailableColumnsCount() {
return availableColumns.size();
}
/**
* Syncronizes this AvailableColumnsModel to contain the table current columns, checking for deleted and new columns.
*/
public void syncronizeTableColumns(){
List<Column> availableColumnsCopy = new ArrayList<Column>(availableColumns);
for (Column column : availableColumnsCopy) {
if(!table.hasColumn(column.getId())){
removeAvailableColumn(column);
}
}
for (Column column : table) {
addAvailableColumn(column);
}
}
}
@@ -53,6 +53,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
@@ -60,6 +61,7 @@ import javax.swing.event.DocumentListener;
import org.gephi.attribute.api.AttributeModel;
import org.gephi.attribute.api.Column;
import org.gephi.attribute.api.Table;
import org.gephi.attribute.api.TableObserver;
import org.gephi.datalab.api.DataLaboratoryHelper;
import org.gephi.datalab.api.datatables.AttributeTableCSVExporter;
import org.gephi.datalab.api.datatables.DataTablesController;
@@ -108,7 +110,8 @@ persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.OpenActionRegistration(displayName = "#CTL_DataTableTopComponent",
preferredID = "DataTableTopComponent")
public class DataTableTopComponent extends TopComponent implements AWTEventListener, DataTablesEventListener {
//TODO Add a Graph observer to auto-update tables
private final ProjectController pc;
private final GraphController gc;
private enum ClassDisplayed {
@@ -130,10 +133,17 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
private Map<Integer, ContextMenuItemManipulator> edgesActionMappings = new HashMap<Integer, ContextMenuItemManipulator>();//For key bindings
//Data
private GraphModel graphModel;
private GraphObserver graphObserver;
private DataTablesModel dataTablesModel;
private AvailableColumnsModel nodeAvailableColumnsModel;
private AvailableColumnsModel edgeAvailableColumnsModel;
//Observers for auto-refreshing:
private GraphObserver graphObserver;
private TableObserver nodesTableObserver;
private TableObserver edgesTableObserver;
//Timer for the obsevers:
private java.util.Timer observersTimer;
//Table
private NodeDataTable nodeTable;
private EdgeDataTable edgeTable;
@@ -145,8 +155,10 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
private int previousNodeColumnsFilterIndex = 0;
private ArrayList previousEdgeFilterColumns = new ArrayList();
private int previousEdgeColumnsFilterIndex = 0;
//Executor
//Refresh executor
private RefreshOnceHelperThread refreshOnceHelperThread;
public DataTableTopComponent() {
@@ -184,7 +196,8 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
edgeTable.setShowEdgesNodesLabels(showEdgesNodesLabels);
//Init
ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
pc = Lookup.getDefault().lookup(ProjectController.class);
gc = Lookup.getDefault().lookup(GraphController.class);
Workspace workspace = pc.getCurrentWorkspace();
if (workspace == null) {
clearAll();
@@ -202,11 +215,45 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
bannerPanel.setVisible(false);
}
private void initEvents() {
private void activateWorkspace(Workspace workspace){
//Prepare DataTablesEvent listener
Lookup.getDefault().lookup(DataTablesController.class).setDataTablesEventListener(DataTableTopComponent.this);
dataTablesModel = workspace.getLookup().lookup(DataTablesModel.class);
nodeAvailableColumnsModel = dataTablesModel.getNodeAvailableColumnsModel();
edgeAvailableColumnsModel = dataTablesModel.getEdgeAvailableColumnsModel();
hideTable();
enableTableControls();
graphModel = gc.getGraphModel(workspace);
nodesTableObserver = gc.getAttributeModel(workspace).getNodeTable().createTableObserver();
edgesTableObserver = gc.getAttributeModel(workspace).getEdgeTable().createTableObserver();
graphObserver = graphModel.createGraphObserver(graphModel.getGraph(), false);
refreshAllOnce();
}
private void deactivateAll(){
graphObserver = null;
if(nodesTableObserver != null){
nodesTableObserver.destroy();
nodesTableObserver = null;
}
if(edgesTableObserver != null){
edgesTableObserver.destroy();
edgesTableObserver = null;
}
graphModel = null;
dataTablesModel = null;
nodeAvailableColumnsModel = null;
edgeAvailableColumnsModel = null;
clearAll();
}
private void initEvents() {
//Workspace Listener
ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
final GraphController gc = Lookup.getDefault().lookup(GraphController.class);
pc.addWorkspaceListener(new WorkspaceListener() {
public void initialize(Workspace workspace) {
@@ -218,29 +265,11 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
}
public void select(Workspace workspace) {
//Prepare DataTablesEvent listener
Lookup.getDefault().lookup(DataTablesController.class).setDataTablesEventListener(DataTableTopComponent.this);
dataTablesModel = workspace.getLookup().lookup(DataTablesModel.class);
nodeAvailableColumnsModel = dataTablesModel.getNodeAvailableColumnsModel();
edgeAvailableColumnsModel = dataTablesModel.getEdgeAvailableColumnsModel();
hideTable();
enableTableControls();
graphModel = gc.getGraphModel();
graphObserver = graphModel.getGraphObserver(graphModel.getGraph(), false);
refreshAllOnce();
activateWorkspace(workspace);
}
public void unselect(Workspace workspace) {
graphObserver = null;
graphModel = null;
dataTablesModel = null;
nodeAvailableColumnsModel = null;
edgeAvailableColumnsModel = null;
clearAll();
deactivateAll();
}
public void close(Workspace workspace) {
@@ -252,13 +281,27 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
Lookup.getDefault().lookup(DataTablesController.class).setDataTablesEventListener(null);
}
});
if (pc.getCurrentWorkspace() != null) {
//Prepare DataTablesEvent listener
Lookup.getDefault().lookup(DataTablesController.class).setDataTablesEventListener(DataTableTopComponent.this);
graphModel = gc.getGraphModel();
graphObserver = graphModel.getGraphObserver(graphModel.getGraph(), false);
activateWorkspace(pc.getCurrentWorkspace());
}
observersTimer = new java.util.Timer("DataLaboratoryGraphObservers");
observersTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
boolean hasChanges =
(graphObserver != null && graphObserver.hasGraphChanged())
|| (nodesTableObserver != null && nodesTableObserver.hasTableChanged())
|| (edgesTableObserver != null && edgesTableObserver.hasTableChanged());
if(hasChanges){
graphChanged();//Execute refresh
}
}
}
, 0, 100);//Check graph and tables for changes every 100 ms
//Filter
if (dynamicFiltering) {
@@ -343,6 +386,9 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
}
}
/**
* Start an auto-refresh if necessary.
*/
public void graphChanged() {
SwingUtilities.invokeLater(new Runnable() {
@@ -421,11 +467,12 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
busylabel.setBusy(true);
//Attributes columns
nodeAvailableColumnsModel.syncronizeTableColumns();
final Column[] cols = nodeAvailableColumnsModel.getAvailableColumns();
refreshAvailableColumnsButton(nodeAvailableColumnsModel, Lookup.getDefault().lookup(GraphController.class).getAttributeModel().getNodeTable());
//Nodes from DHNS
//Nodes from graph
Graph graph;
if (visibleOnly) {
graph = graphModel.getGraphVisible();
@@ -467,11 +514,12 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
busylabel.setBusy(true);
//Attributes columns
edgeAvailableColumnsModel.syncronizeTableColumns();
final Column[] cols = edgeAvailableColumnsModel.getAvailableColumns();
refreshAvailableColumnsButton(edgeAvailableColumnsModel, Lookup.getDefault().lookup(GraphController.class).getAttributeModel().getEdgeTable());
//Edges from DHNS
//Edges from graph
Graph graph;
if (visibleOnly) {
graph = graphModel.getGraphVisible();
@@ -794,11 +842,10 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
Column[] columns;
if (classDisplayed == ClassDisplayed.NODE) {
table = attributeModel.getNodeTable();
columns = nodeAvailableColumnsModel.getAvailableColumns();
} else {
table = attributeModel.getEdgeTable();
columns = edgeAvailableColumnsModel.getAvailableColumns();
}
columns = getTableAvailableColumnsModel(table).getAvailableColumns();
DataLaboratoryHelper dlh = DataLaboratoryHelper.getDefault();
AttributeColumnsManipulator[] manipulators = dlh.getAttributeColumnsManipulators();
@@ -1095,6 +1142,7 @@ public class DataTableTopComponent extends TopComponent implements AWTEventListe
moreEvents = false;
Thread.sleep(CHECK_TIME_INTERVAL);
} while (moreEvents);
if (refreshTableOnly) {
DataTableTopComponent.this.refreshTable();
} else {
@@ -42,9 +42,7 @@
package org.gephi.desktop.datalab;
import org.gephi.attribute.api.AttributeModel;
import org.gephi.attribute.api.Column;
import org.gephi.attribute.api.Table;
import org.gephi.datalab.api.datatables.DataTablesController;
import org.gephi.graph.api.GraphController;
import org.gephi.project.api.Workspace;
import org.openide.util.Lookup;
@@ -53,29 +51,22 @@ import org.openide.util.Lookup;
*
* @author Mathieu Bastian
*/
public class DataTablesModel /*implements AttributeListener*/ {
public class DataTablesModel {
private AvailableColumnsModel nodeAvailableColumnsModel;
private AvailableColumnsModel edgeAvailableColumnsModel;
private AttributeModel attributeModel;
private final AvailableColumnsModel nodeAvailableColumnsModel;
private final AvailableColumnsModel edgeAvailableColumnsModel;
private final AttributeModel attributeModel;
public DataTablesModel(Workspace workspace) {
nodeAvailableColumnsModel = new AvailableColumnsModel();
edgeAvailableColumnsModel = new AvailableColumnsModel();
attributeModel = Lookup.getDefault().lookup(GraphController.class).getAttributeModel(workspace);
nodeAvailableColumnsModel = new AvailableColumnsModel(attributeModel.getNodeTable());
edgeAvailableColumnsModel = new AvailableColumnsModel(attributeModel.getEdgeTable());
//Try to make available all columns at start by default:
for (Column column : attributeModel.getNodeTable().getColumns()) {
System.out.println("");
nodeAvailableColumnsModel.addAvailableColumn(column);
}
for (Column column : attributeModel.getEdgeTable().getColumns()) {
edgeAvailableColumnsModel.addAvailableColumn(column);
}
// attributeModel.addAttributeListener(this);
nodeAvailableColumnsModel.syncronizeTableColumns();
edgeAvailableColumnsModel.syncronizeTableColumns();
}
public AvailableColumnsModel getEdgeAvailableColumnsModel() {
@@ -95,32 +86,4 @@ public class DataTablesModel /*implements AttributeListener*/ {
return null;//Graph table or other table, not supported in data laboratory for now.
}
}
// public void attributesChanged(AttributeEvent event) {
// Table table = event.getSource();
// AvailableColumnsModel tableAvailableColumnsModel = getTableAvailableColumnsModel(table);
// if (tableAvailableColumnsModel != null) {
// switch (event.getEventType()) {
// case ADD_COLUMN:
// for (Column c : event.getData().getAddedColumns()) {
// if (!tableAvailableColumnsModel.addAvailableColumn(c)) {//Add as available by default. Will only be added if the max number of available columns is not surpassed
// break;
// }
// }
// break;
// case REMOVE_COLUMN:
// for (Column c : event.getData().getRemovedColumns()) {
// tableAvailableColumnsModel.removeAvailableColumn(c);
// }
// break;
// case REPLACE_COLUMN:
// for (Column c : event.getData().getRemovedColumns()) {
// tableAvailableColumnsModel.removeAvailableColumn(c);
// tableAvailableColumnsModel.addAvailableColumn(table.getColumn(c.getId()));
// }
// break;
// }
// }
// Lookup.getDefault().lookup(DataTablesController.class).refreshCurrentTable();
// }
}
@@ -50,6 +50,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.PatternSyntaxException;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
@@ -264,8 +265,7 @@ public class EdgeDataTable {
model = new EdgeDataTableModel(graph.getEdges().toArray(), columns.toArray(new EdgeDataColumn[0]));
table.setModel(model);
} else {
model.setEdges(graph.getEdges().toArray());
model.setColumns(columns.toArray(new EdgeDataColumn[0]));
model.configure(graph.getEdges().toArray(), columns.toArray(new EdgeDataColumn[0]));
}
setEdgesSelection(selectedEdges);//Keep row selection before refreshing.
@@ -395,21 +395,23 @@ public class EdgeDataTable {
return columns;
}
public void setColumns(EdgeDataColumn[] columns) {
boolean columnsChanged = columns.length != this.columns.length;
this.columns = columns;
if (columnsChanged) {
fireTableStructureChanged();
}
}
public Edge[] getEdges() {
return edges;
}
public void configure(Edge[] edges, EdgeDataColumn[] columns){
Set<EdgeDataColumn> oldColumns = new HashSet<EdgeDataColumn>(Arrays.asList(this.columns));
Set<EdgeDataColumn> newColumns = new HashSet<EdgeDataColumn>(Arrays.asList(columns));
public void setEdges(Edge[] edges) {
boolean columnsChanged = !oldColumns.equals(newColumns);
this.columns = columns;
this.edges = edges;
fireTableDataChanged();
if (columnsChanged) {
fireTableStructureChanged();//Only firing this event if columns change is useful because JXTable will not reset columns width if there is no change
}else{
fireTableDataChanged();
}
}
}
@@ -470,6 +472,27 @@ public class EdgeDataTable {
return null;
}
}
}
@Override
public int hashCode() {
int hash = 5;
hash = 89 * hash + (this.column != null ? this.column.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AttributeEdgeDataColumn other = (AttributeEdgeDataColumn) obj;
return this.column == other.column || (this.column != null && this.column.equals(other.column));
}
public void setValueFor(Edge edge, Object value) {
@@ -49,7 +49,7 @@ import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.PatternSyntaxException;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
@@ -65,8 +65,6 @@ import org.gephi.graph.api.Graph;
import org.gephi.graph.api.Node;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.decorator.HighlighterFactory;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.swingx.table.TableColumnModelExt;
import org.openide.awt.MouseUtils;
import org.openide.util.Lookup;
@@ -206,12 +204,12 @@ public class NodeDataTable {
columns.add(new AttributeNodeDataColumn(c));
}
if (model == null) {
model = new NodeDataTableModel(graph.getNodes().toArray(), columns.toArray(new NodeDataColumn[0]));
table.setModel(model);
} else {
model.setNodes(graph.getNodes().toArray());
model.setColumns(columns.toArray(new NodeDataColumn[0]));
model.configure(graph.getNodes().toArray(), columns.toArray(new NodeDataColumn[0]));
}
setNodesSelection(selectedNodes);//Keep row selection before refreshing.
@@ -267,30 +265,6 @@ public class NodeDataTable {
this.showEdgesNodesLabels = showEdgesNodesLabels;
}
private String[] getHiddenColumns() {
List<String> hiddenCols = new ArrayList<String>();
TableColumnModelExt columnModel = (TableColumnModelExt) table.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumnExt col = columnModel.getColumnExt(i);
if (!col.isVisible()) {
hiddenCols.add((String) col.getHeaderValue());
}
}
return hiddenCols.toArray(new String[0]);
}
private void setHiddenColumns(String[] columns) {
TableColumnModelExt columnModel = (TableColumnModelExt) table.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumnExt col = columnModel.getColumnExt(i);
for (String column : columns) {
if (column.equals(col.getHeaderValue())) {
col.setVisible(false);
}
}
}
}
private class NodeDataTableModel extends AbstractTableModel {
private Node[] nodes;
@@ -341,21 +315,23 @@ public class NodeDataTable {
return columns;
}
public void setColumns(NodeDataColumn[] columns) {
boolean columnsChanged = columns.length != this.columns.length;
this.columns = columns;
if (columnsChanged) {
fireTableStructureChanged();
}
}
public Node[] getNodes() {
return nodes;
}
public void setNodes(Node[] edges) {
this.nodes = edges;
fireTableDataChanged();
public void configure(Node[] nodes, NodeDataColumn[] columns){
Set<NodeDataColumn> oldColumns = new HashSet<NodeDataColumn>(Arrays.asList(this.columns));
Set<NodeDataColumn> newColumns = new HashSet<NodeDataColumn>(Arrays.asList(columns));
boolean columnsChanged = !oldColumns.equals(newColumns);
this.columns = columns;
this.nodes = nodes;
if (columnsChanged) {
fireTableStructureChanged();//Only firing this event if columns change is useful because JXTable will not reset columns width if there is no change
}else{
fireTableDataChanged();
}
}
}
@@ -425,6 +401,25 @@ public class NodeDataTable {
public boolean isEditable() {
return attributeColumnsController.canChangeColumnData(column);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AttributeNodeDataColumn other = (AttributeNodeDataColumn) obj;
return this.column == other.column || (this.column != null && this.column.equals(other.column));
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + (this.column != null ? this.column.hashCode() : 0);
return hash;
}
}
private abstract class PropertyNodeDataColumn implements NodeDataTable.NodeDataColumn {
+1
Ver Arquivo
@@ -39,6 +39,7 @@
<publicPackages>
<publicPackage>org.gephi.dynamic</publicPackage>
<publicPackage>org.gephi.dynamic.api</publicPackage>
<publicPackage>org.gephi.dynamic.utils</publicPackage>
</publicPackages>
</configuration>
</plugin>
@@ -39,27 +39,23 @@
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.datalab.utils;
package org.gephi.dynamic.utils;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import org.gephi.attribute.api.AttributeUtils;
import org.gephi.attribute.time.Interval;
import org.gephi.attribute.time.IntervalWithValue;
/**
* <p>
* Class for parsing dynamic types with several intervals.</p>
* Class for parsing dynamic types with several intervals.
* </p>
*
* <p>
* Examples of valid dynamic intervals are:
@@ -82,7 +78,7 @@ import org.gephi.attribute.time.IntervalWithValue;
*
* @author Eduardo Ramos<eduramiba@gmail.com>
*/
public final class DynamicParser {
public final class DynamicIntervalsParser {
private static final char LOPEN = '(';
private static final char LCLOSE = '[';
@@ -123,7 +119,13 @@ public final class DynamicParser {
return result;
}
/**
* Parses intervals with values (of <code>type</code> Class) or without values (null <code>type</code> Class)
* @param type Class of the intervals' values or null to parse intervals without values
* @param input Input to parse
* @return List<Interval>
*/
public static List<Interval> parseIntervals(Class type, String input) throws IOException, ParseException, IllegalArgumentException {
if (input.equalsIgnoreCase("<empty>")) {
return null;
@@ -263,8 +265,8 @@ public final class DynamicParser {
private static Interval buildInterval(Class type, ArrayList<String> values, boolean lopen, boolean ropen) throws ParseException {
double low, high;
low = parseTime(values.get(0));
high = parseTime(values.get(1));
low = DynamicUtilities.parseTime(values.get(0));
high = DynamicUtilities.parseTime(values.get(1));
if (type == null) {
return new Interval(low, high, lopen, ropen);
@@ -279,12 +281,12 @@ public final class DynamicParser {
|| type.equals(Long.class)
|| type.equals(BigInteger.class)
) {
valString = removeDecimalDigitsFromString(valString);
valString = DynamicUtilities.removeDecimalDigitsFromString(valString);
} else if (type.equals(Float.class)
|| type.equals(Double.class)
|| type.equals(BigDecimal.class)
) {
valString = infinityIgnoreCase(valString);
valString = DynamicUtilities.infinityIgnoreCase(valString);
}
value = AttributeUtils.parse(valString, type);
@@ -293,71 +295,4 @@ public final class DynamicParser {
return new IntervalWithValue(low, high, lopen, ropen, value);
}
}
//For date parsing:
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static DatatypeFactory dateFactory;
static {
try {
dateFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException ex) {
}
}
//Throws exception when a date can't be parsed
public static double getDoubleFromXMLDateString(String str) throws ParseException {
try {
return dateFactory.newXMLGregorianCalendar(str.length() > 23 ? str.substring(0, 23) : str).
toGregorianCalendar().getTimeInMillis();
} catch (IllegalArgumentException ex) {
//Try simple format
Date date = dateFormat.parse(str);
return date.getTime();
}
}
public static double parseTime(String time) throws ParseException {
double value;
try {
//Try first to parse as a single double:
value = Double.parseDouble(infinityIgnoreCase(time));
if (Double.isNaN(value)) {
throw new IllegalArgumentException("NaN is not allowed as an interval bound");
}
} catch (Exception ex) {
//Try to parse as date instead
value = getDoubleFromXMLDateString(time);
}
return value;
}
/**
* Method for allowing inputs such as "infinity" when parsing decimal numbers
*
* @param value Input String
* @return Input String with fixed "Infinity" syntax if necessary.
*/
private static String infinityIgnoreCase(String value) {
if (value.equalsIgnoreCase("Infinity")) {
return "Infinity";
}
if (value.equalsIgnoreCase("-Infinity")) {
return "-Infinity";
}
return value;
}
/**
* Removes the decimal digits and point of the numbers of string when necessary. Used for trying to parse decimal numbers as not decimal. For example BigDecimal to BigInteger.
*
* @param s String to remove decimal digits
* @return String without dot and decimal digits.
*/
private static String removeDecimalDigitsFromString(String s) {
return removeDecimalDigitsFromStringPattern.matcher(s).replaceAll("");
}
private static final Pattern removeDecimalDigitsFromStringPattern = Pattern.compile("\\.[0-9]*");
}
@@ -1,6 +1,6 @@
/*
* Copyright 2008-2010 Gephi
* Authors : Cezary Bartosiak
* Authors : Cezary Bartosiak, Eduardo Ramos
* Website : http://www.gephi.org
*
* This file is part of Gephi.
@@ -39,15 +39,97 @@
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.dynamic;
package org.gephi.dynamic.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
/**
* Contains only static, and toolkit functions, like type conversion for the
* needs of dynamic stuff.
* Contains only static, and toolkit functions, like type conversion for the needs of dynamic stuff.
*
* @author Cezary Bartosiak
* @author Cezary Bartosiak, Eduardo Ramos
*/
public final class DynamicUtilities {
//For date parsing:
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static DatatypeFactory dateFactory;
static {
try {
dateFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException ex) {
}
}
//Throws exception when a date can't be parsed
public static double getDoubleFromXMLDateString(String str) throws ParseException {
try {
return dateFactory.newXMLGregorianCalendar(str.length() > 23 ? str.substring(0, 23) : str).
toGregorianCalendar().getTimeInMillis();
} catch (IllegalArgumentException ex) {
//Try simple format
Date date = dateFormat.parse(str);
return date.getTime();
}
}
/**
* Method for allowing inputs such as "infinity" when parsing decimal numbers
*
* @param value Input String
* @return Input String with fixed "Infinity" syntax if necessary.
*/
public static String infinityIgnoreCase(String value) {
if (value.equalsIgnoreCase("Infinity")) {
return "Infinity";
}
if (value.equalsIgnoreCase("-Infinity")) {
return "-Infinity";
}
return value;
}
/**
* Tries to parse a string as a timestamp.
* First checks if the input is a timestamp number.
* Then tries to parse it as a date.
* @param time Input string
* @return timestamp
*/
public static double parseTime(String time) throws ParseException {
double value;
try {
//Try first to parse as a single double:
value = Double.parseDouble(infinityIgnoreCase(time));
if (Double.isNaN(value)) {
throw new IllegalArgumentException("NaN is not allowed as an interval bound");
}
} catch (Exception ex) {
//Try to parse as date instead
value = getDoubleFromXMLDateString(time);
}
return value;
}
/**
* Removes the decimal digits and point of the numbers of string when necessary. Used for trying to parse decimal numbers as not decimal. For example BigDecimal to BigInteger.
*
* @param s String to remove decimal digits
* @return String without dot and decimal digits.
*/
protected static String removeDecimalDigitsFromString(String s) {
return removeDecimalDigitsFromStringPattern.matcher(s).replaceAll("");
}
protected static final Pattern removeDecimalDigitsFromStringPattern = Pattern.compile("\\.[0-9]*");
// private static DatatypeFactory dateFactory;
//
// static {
@@ -39,7 +39,7 @@
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.datalab.utils;
package org.gephi.dynamic.utils;
import java.util.Iterator;
import java.util.List;
@@ -51,7 +51,7 @@ import org.junit.Test;
*
* @author Eduardo Ramos<eduramiba@gmail.com>
*/
public class DynamicParserTest {
public class DynamicIntervalsParserTest {
private String parseDynamic(String str) throws Exception{
return parseDynamic(str, String.class);
@@ -79,11 +79,11 @@ public class DynamicParserTest {
private String parseDynamic(String str, Class type) throws Exception{
if(type != null){
System.out.println(representListAsIntervalsString(DynamicParser.parseIntervalsWithValues(type, str)));
return representListAsIntervalsString(DynamicParser.parseIntervalsWithValues(type, str));
System.out.println(representListAsIntervalsString(DynamicIntervalsParser.parseIntervalsWithValues(type, str)));
return representListAsIntervalsString(DynamicIntervalsParser.parseIntervalsWithValues(type, str));
}else{
System.out.println(representListAsIntervalsString(DynamicParser.parseIntervals(str)));
return representListAsIntervalsString(DynamicParser.parseIntervals(str));
System.out.println(representListAsIntervalsString(DynamicIntervalsParser.parseIntervals(str)));
return representListAsIntervalsString(DynamicIntervalsParser.parseIntervals(str));
}
}