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:
-3
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
+3
-4
@@ -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);
|
||||
}
|
||||
|
||||
+25
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
-36
@@ -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 {
|
||||
|
||||
+10
-47
@@ -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();
|
||||
// }
|
||||
}
|
||||
|
||||
+35
-12
@@ -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) {
|
||||
|
||||
+35
-40
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
+15
-80
@@ -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]*");
|
||||
}
|
||||
+87
-5
@@ -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 {
|
||||
+6
-6
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário