/*** * Copyright (c) 2008, Endless Loop Software, Inc. * * This file is part of EgoNet. * * EgoNet 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 3 of the License, or * (at your option) any later version. * * EgoNet 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, see <http://www.gnu.org/licenses/>. */ package org.egonet.graph; import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.algorithms.layout.LayoutDecorator; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.visualization.VisualizationModel; import java.util.*; import java.util.List; import java.awt.*; import java.io.*; import org.egonet.graph.EdgeProperty.EdgePropertyType; import org.egonet.graph.EdgeProperty.EdgeShape; import org.egonet.graph.GraphSettingsEntry.GraphSettingType; import org.egonet.graph.NodeProperty.NodePropertyType; import org.egonet.graph.NodeProperty.NodeShape; import org.egonet.gui.interview.*; import org.egonet.model.QuestionList; import org.egonet.model.Study; import org.egonet.model.answer.*; import org.egonet.model.question.AlterQuestion; import org.egonet.model.question.Question; import org.egonet.model.question.Selection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.*; import org.xml.sax.SAXException; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; //test comment public class GraphSettings { final private static Logger logger = LoggerFactory.getLogger(GraphSettings.class); private Map<Vertex, NodeProperty> nodeSettingsMap = Collections .synchronizedMap(new HashMap<Vertex, NodeProperty>()); private Map<Edge, EdgeProperty> edgeSettingsMap = Collections .synchronizedMap(new HashMap<Edge, EdgeProperty>()); private java.util.List<GraphSettingsEntry> QAsettings = Collections .synchronizedList(new ArrayList<GraphSettingsEntry>()); private boolean detailedTooltips = false; public boolean isDetailedTooltips() { return detailedTooltips; } public void setDetailedTooltips(boolean detailedTooltips) { this.detailedTooltips = detailedTooltips; } GraphRenderer renderer; private EgoClient egoClient; public GraphSettings(EgoClient egoClient, GraphRenderer renderer) { this.egoClient = egoClient; this.renderer = renderer; init(); } public void reset() { for(Map.Entry<Vertex,NodeProperty> entry : nodeSettingsMap.entrySet()) { NodeProperty nodeProperty = entry.getValue(); NodeShape shape = NodeShape.Circle; Color color = Color.RED; int size = 1; nodeProperty.setColor(color); nodeProperty.setShape(shape); nodeProperty.setSize(size); } for(Map.Entry<Edge,EdgeProperty> entry : edgeSettingsMap.entrySet()) { EdgeProperty edgeProperty = entry.getValue(); edgeProperty.setColor(Color.BLACK); edgeProperty.setShape(EdgeShape.Line); edgeProperty.setSize(1); edgeProperty.setVisible(true); } QAsettings.clear(); renderer.updateGraphSettings(); } private void init() { int noOfAlters = egoClient.getInterview().getNumberAlters(); String[] renderAlterList = renderer.getAlterList(); if(renderAlterList.length < 1) throw new IllegalArgumentException("Graph renderer was called with an empty alter list!"); // initialize nodes with default settings for (int i = 0; i < noOfAlters; i++) { String alterName = egoClient.getInterview().getAlterList()[i]; Color color = Color.RED; int size = 1; NodeShape shape = NodeShape.Circle; NodeProperty nodeProperty = new NodeProperty(alterName, color,shape, size); nodeProperty.setToolTipText(getAlterInfo(i, false)); nodeProperty.setDetailedToolTipText(getAlterInfo(i, true)); nodeSettingsMap.put(new Vertex(renderAlterList[i]), nodeProperty); } // initialize edges with default settings Graph<Vertex, Edge> g = GraphRenderer.getGraph(); while(g.getEdgeCount() > 0) { Collection<Edge> oldEdges = g.getEdges(); for(Edge ed : oldEdges) g.removeEdge(ed); } GraphData graphData = new GraphData(egoClient); Graph<Vertex, Edge> graph = GraphRenderer.getGraph(); int[][] adjacencyMatrix = graphData.getAdjacencyMatrix(); for (int i = 0; i < adjacencyMatrix.length; ++i) { for (int j = i + 1; j < adjacencyMatrix[i].length; ++j) { if (adjacencyMatrix[i][j] > 0) { String[] list = renderer.getAlterList(); // create edge and note where it came from, so we can point out if it's a dupe Edge edge = new Edge(list[i], list[j]); edge.setNotes("i="+i+",j="+j); List<Vertex> verts = Arrays.asList(new Vertex(list[i]), new Vertex(list[j])); if(graph.containsEdge(edge)) { Edge oldEdge = null; for(Edge e : graph.getEdges()) { if(e.equals(edge)) oldEdge = e; } // help by printing out the problem String oldEdgeStr = "unknown"; if(oldEdge != null) { oldEdgeStr = edge.toString() + " from position " + edge.getNotes(); } String err = "Graph already contained connected vertices " + verts + " (adjacency matrix position [i="+i+",j="+j+"] was already in the adjacency matrix from "+oldEdgeStr+")"; logger.error(err); throw new RuntimeException(err); } graph.addEdge(edge, verts); String label = ((Integer) egoClient.getInterview().getStats().proximityMatrix[i][j]).toString(); EdgeProperty edgeProperty = new EdgeProperty(label, Color.BLACK, EdgeShape.Line, 1); edgeProperty.setVisible(true); edgeSettingsMap.put(edge, edgeProperty); } } } } public void saveSettingsFile(File file) { try { DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element studyElement = doc.createElement("GraphSettings"); String studyID = egoClient.getStudy().getStudyId(); studyElement.setAttribute("StudyId", studyID); doc.appendChild(studyElement); Element graphElement = doc.createElement("GraphElement"); // layoutElement Element layoutElement = doc.createElement("Layout"); VisualizationModel model = renderer.getVisualizationModel(); Layout graphLayout = model.getGraphLayout(); if(graphLayout instanceof LayoutDecorator) { LayoutDecorator decor = (LayoutDecorator)graphLayout; graphLayout = decor.getDelegate(); } layoutElement.setAttribute("layout", graphLayout.getClass().getName()); // zoomElement Element zoomElement = doc.createElement("Zoom"); zoomElement.setAttribute("zoom", GraphRenderer.getVv().getLayout() .getClass().toString()); // backGroundElement Element backGroundElement = doc.createElement("Background"); String background = ((Integer) GraphRenderer.getVisualizationViewer() .getBackground().getRGB()).toString(); backGroundElement.setAttribute("background", background); // showNodeLabelElement Element showNodeLabelElement = doc.createElement("ShowNodeLabel"); showNodeLabelElement.setAttribute("shownodelabel", renderer .getShowNodeLabels() ? "true" : "false"); graphElement.appendChild(layoutElement); graphElement.appendChild(backGroundElement); graphElement.appendChild(zoomElement); graphElement.appendChild(showNodeLabelElement); studyElement.appendChild(graphElement); for (GraphSettingsEntry entry : QAsettings) entry.writeEntryElement(doc, studyElement); TransformerFactory tranFactory = TransformerFactory.newInstance(); Transformer aTransformer = tranFactory.newTransformer(); aTransformer.setOutputProperty("indent", "yes"); aTransformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "4"); Source src = new DOMSource(doc); Result dest = new StreamResult(file); aTransformer.transform(src, dest); } catch (Throwable ex) { throw new RuntimeException(ex); } } public void loadSettingsFile(File file) throws ParserConfigurationException, SAXException, IOException, Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(file); NodeList nodeList = document.getDocumentElement().getChildNodes(); Study study = egoClient.getInterview().getStudy(); QuestionList questionList = study.getQuestions(); for (int i = 1; i < nodeList.getLength(); i++) { Node entryNode = nodeList.item(i); if (entryNode.getNodeType() == Node.ELEMENT_NODE && ((Element) entryNode).getTagName() .equals("GraphElement")) { Element graphElement = (Element) entryNode; Element layoutElement = (Element) graphElement .getElementsByTagName("Layout").item(0); //Element zoomElement = (Element) graphElement.getElementsByTagName("Zoom").item(0); Element backgroundElement = (Element) graphElement .getElementsByTagName("Background").item(0); Element showNodeLabelElement = (Element) graphElement .getElementsByTagName("ShowNodeLabel").item(0); try { renderer.changeLayout(Class.forName(layoutElement .getAttribute("layout"))); } catch (ClassNotFoundException ex) { logger.info("Specified class is not a Layout class"); logger.error(ex.toString()); } catch (Exception ex) { logger.info("Unable to change layout"); logger.error(ex.toString()); ex.printStackTrace(); } GraphRenderer.getVv().setBackground( Color.decode(backgroundElement .getAttribute("background"))); if (showNodeLabelElement.getAttribute("shownodelabel").equals( "true")) renderer.drawNodeLabels(); } if (entryNode.getNodeType() == Node.ELEMENT_NODE && ((Element) entryNode).getTagName().equals("Entry")) { Element entryElement = (Element) entryNode; Element graphQuestionSelectionElement = (Element) entryElement .getElementsByTagName("GraphQuestionSelectionPair") .item(0); Element questionElement = (Element) graphQuestionSelectionElement .getElementsByTagName("Question").item(0); Element selectionElement = (Element) graphQuestionSelectionElement .getElementsByTagName("Selection").item(0); //Element categoryElement = (Element) graphQuestionSelectionElement.getElementsByTagName("Category").item(0); Element propertyElement = (Element) entryElement .getElementsByTagName("Property").item(0); Element visibleElement = (Element) propertyElement .getElementsByTagName("Visible").item(0); Question question = questionList.get(Long.parseLong(questionElement.getAttribute("id"))); for (int j = 0; j < question.getSelections().size(); j++) { Selection selection = question.getSelections().get(j); if (selection.getString().equals( selectionElement.getAttribute("text"))) { GraphQuestionSelectionPair graphQuestion = new GraphQuestionSelectionPair(question, selection); if (propertyElement.getAttribute("type").equals("Edge")) { logger.info(propertyElement .getAttribute("color")); if (!propertyElement.getAttribute("color").equals( "")) { EdgeProperty epColor = new EdgeProperty(); epColor.setColor(Color.decode(propertyElement .getAttribute("color"))); epColor.setProperty(EdgePropertyType.Color); epColor.setVisible(visibleElement.getAttribute( "visible").equals("true")); renderer.addQAsettings(graphQuestion, epColor); } if (!propertyElement.getAttribute("size") .equals("")) { EdgeProperty epSize = new EdgeProperty(); epSize.setSize(Integer.parseInt(propertyElement .getAttribute("size"))); epSize.setProperty(EdgePropertyType.Size); epSize.setVisible(visibleElement.getAttribute( "visible").equals("true")); renderer.addQAsettings(graphQuestion, epSize); } if (!propertyElement.getAttribute("shape").equals( "")) { EdgeProperty epShape = new EdgeProperty(); epShape.setShapeFromString(propertyElement .getAttribute("shape")); epShape.setProperty(EdgePropertyType.Shape); epShape.setVisible(visibleElement.getAttribute( "visible").equals("true")); renderer.addQAsettings(graphQuestion, epShape); } } else { // not edge? must be node. if (!propertyElement.getAttribute("color").equals("")) { NodeProperty npColor = new NodeProperty(); npColor.setColor(Color.decode(propertyElement.getAttribute("color"))); npColor.setProperty(NodePropertyType.Color); renderer.addQAsettings(graphQuestion, npColor); } else if (!propertyElement.getAttribute("size").equals("")) { NodeProperty npSize = new NodeProperty(); npSize.setSize(Integer.parseInt(propertyElement.getAttribute("size"))); npSize.setProperty(NodePropertyType.Size); renderer.addQAsettings(graphQuestion, npSize); } else if (!propertyElement.getAttribute("shape").equals("")) { NodeProperty npShape = new NodeProperty(); npShape.setShapeFromString(propertyElement.getAttribute("shape")); npShape.setProperty(NodePropertyType.Shape); renderer.addQAsettings(graphQuestion, npShape); } else { // If none of those, then label NodeProperty npLabel = new NodeProperty(); npLabel.setProperty(NodePropertyType.Label); npLabel.setLabel(graphQuestion.getSelection().getString()); renderer.addQAsettings(graphQuestion, npLabel); } } } } } } renderer.updateGraphSettings(); } public int getNodeSize(Vertex node) { NodeProperty nodeProperty = nodeSettingsMap.get(node); return nodeProperty.getSize(); } public void setNodeSize(Vertex node, int nodeSize) { nodeSettingsMap.get(node).setSize(nodeSize); } public NodeShape getNodeShape(Vertex node) { NodeProperty nodeProperty = nodeSettingsMap.get(node); return nodeProperty.getShape(); } public void setNodeShape(Vertex node, NodeShape nodeShape) { nodeSettingsMap.get(node).setShape(nodeShape); } public Color getNodeColor(Vertex node) { NodeProperty nodeProperty = nodeSettingsMap.get(node); return nodeProperty.getColor(); } public void setNodeColor(Vertex node, Color nodeColor) { nodeSettingsMap.get(node).setColor(nodeColor); } public String getNodeLabel(Vertex node) { NodeProperty nodeProperty = nodeSettingsMap.get(node); return nodeProperty.getLabel(); } public void setNodeLabel(Vertex node, String nodeLabel) { nodeSettingsMap.get(node).setLabel(nodeLabel); } public String getNodeToolTipText(Vertex node) { NodeProperty nodeProperty = nodeSettingsMap.get(node); if(isDetailedTooltips()) return nodeProperty.getDetailedToolTipText(); return nodeProperty.getToolTipText(); } public int getEdgeSize(Edge edge) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); return edgeProperty.getSize(); } public void setEdgeSize(Edge edge, int edgeSize) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); if (edgeProperty != null) { edgeProperty.setSize(edgeSize); } else { edgeProperty = new EdgeProperty(Color.BLACK, EdgeShape.Line, edgeSize); } edgeSettingsMap.put(edge, edgeProperty); } public EdgeShape getEdgeShape(Edge edge) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); return edgeProperty.getShape(); } public void setEdgeShape(Edge edge, EdgeShape edgeShape) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); if (edgeProperty != null) { edgeProperty.setShape(edgeShape); } else { edgeProperty = new EdgeProperty(Color.BLACK, edgeShape, 1); } edgeSettingsMap.put(edge, edgeProperty); } public Color getEdgeColor(Edge edge) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); return edgeProperty.getColor(); } public void setEdgeColor(Edge edge, Color edgeColor) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); if (edgeProperty != null) { edgeProperty.setColor(edgeColor); } else { edgeProperty = new EdgeProperty(edgeColor, EdgeShape.Line, 1); } edgeSettingsMap.put(edge, edgeProperty); } public String getEdgeLabel(Edge edge) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); return edgeProperty.getLabel(); } public void setEdgeLabel(Edge edge, String edgeLabel) { edgeSettingsMap.get(edge).setLabel(edgeLabel); } public void addQAsetting(GraphQuestionSelectionPair graphQuestion, NodeProperty nodeProperty) { GraphSettingsEntry entry = new GraphSettingsEntry(graphQuestion, nodeProperty, GraphSettingType.Node); QAsettings.add(entry); displaySettings(); } public void addQAsetting(GraphQuestionSelectionPair graphQuestion, EdgeProperty edgeProperty) { GraphSettingsEntry entry = new GraphSettingsEntry(graphQuestion, edgeProperty, GraphSettingType.Edge); QAsettings.add(entry); displaySettings(); } private void displaySettings() { boolean debug = false; if(!debug) return; int size = QAsettings.size(); logger.info("Graph settings (" + size + " entries):"); for (int i = 0; i < size; i++) { GraphSettingsEntry entry = QAsettings.get(i); logger.info("Entry " + i + ": " + entry.toString()); } } public Iterator<GraphSettingsEntry> getQAsettingsIterator() { return QAsettings.iterator(); } private String getAlterInfo(int alterIndex, boolean detail) { String[] alterToolTip = new String[egoClient.getInterview().getNumberAlters()]; for (int i = 0; i < alterToolTip.length; i++) { alterToolTip[i] = "<html>" + egoClient.getInterview().getAlterList()[i] + "<br>"; } Answer[] answers = egoClient.getInterview().get_answers(); for (Answer answer : answers) { String questionTitle = ""; String answerString = ""; Question question = egoClient.getStudy().getQuestion(answer.getQuestionId()); if (question instanceof AlterQuestion) { questionTitle = question.title; answerString = answer.string + " " + (detail ? "(index="+answer.getIndex()+",value="+answer.getValue()+")" : ""); for (int alter : answer.getAlters()) { alterToolTip[alter] += questionTitle + " : " + answerString + "<br>"; } } } return alterToolTip[alterIndex]; } public Iterator<Edge> getEdgeIterator() { return edgeSettingsMap.keySet().iterator(); } public static void writeSettings() { // Iterator iterator = getQAsettingsIterator(); } public void emptyEdgeSettingsMap() { edgeSettingsMap.clear(); } public boolean isEdgeVisible(Edge edge) { EdgeProperty edgeProperty = edgeSettingsMap.get(edge); return edgeProperty.isVisible(); } public void setEdgeVisible(Edge edge, boolean b) { edgeSettingsMap.get(edge).setVisible(b); } public Map<Edge, EdgeProperty> getEdgeSettingsMap() { return edgeSettingsMap; } public void setEdgeSettingsMap(Map<Edge, EdgeProperty> edgeSettingsMap) { this.edgeSettingsMap = edgeSettingsMap; } public Map<Vertex, NodeProperty> getNodeSettingsMap() { return nodeSettingsMap; } public void setNodeSettingsMap( Map<Vertex, NodeProperty> nodeSettingsMap) { this.nodeSettingsMap = nodeSettingsMap; } public java.util.List<GraphSettingsEntry> getQAsettings() { return this.QAsettings; } public void setQAsettings(java.util.List<GraphSettingsEntry> asettings) { this.QAsettings = asettings; } }