/* * Copyright (C) 2012 Sony Mobile Communications AB * * This file is part of ApkAnalyser. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gui.graph; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.util.ArrayList; import java.util.List; public class DefaultGraphPainter { Graph graph; List<GraphNode> openNodes; DefaultNodePainter defaultNodePainter; Color background; Dimension dimension; int topSpacer; int leftSpacer; int rightSpacer; int bottomSpacer; List<GraphNode> preRootList; List<Integer> columnHeights; List<Integer> columnWidths; List<List<GraphNode>> rowNodes; // List(GraphNode) boolean mirrored = false; public static final String DUMMY_NODE = ""; public DefaultGraphPainter(Graph graph) { this.graph = graph; GraphNode preRoot = new GraphNode(DUMMY_NODE); preRoot.add(graph.getRoot()); preRootList = new ArrayList<GraphNode>(); preRootList.add(preRoot); openNodes = new ArrayList<GraphNode>(); openNodes.add(preRoot); defaultNodePainter = new DefaultNodePainter(); } public void openNode(GraphNode node) { if (!openNodes.contains(node)) { openNodes.add(node); } } public void closeNode(GraphNode node) { openNodes.remove(node); } public boolean isNodeOpened(GraphNode node) { return openNodes.contains(node); } static final boolean DBG = false; public void paint(Graphics g) { GraphNode root = graph.getRoot(); dimension = getDimension(g, root); g.setColor(background); g.fillRect(0, 0, dimension.width, dimension.height); Point p; if (isMirrored()) { p = new Point(dimension.width - rightSpacer, dimension.height >> 1); } else { p = new Point(leftSpacer, dimension.height >> 1); } rowNodes = new ArrayList<List<GraphNode>>(); paintNodes(preRootList, p, g, 0); if (DBG) { int curX = 0; if (isMirrored()) { curX = getDimension().width - rightSpacer - (columnWidths.get(0)).intValue(); } int curW = 0; int ix = 0; curW = (columnWidths.get(ix)).intValue(); while (ix < columnWidths.size()) { g.drawRect(curX, 0, curW, getHeight()); g.drawLine(curX, 0, curX + curW, getHeight()); g.drawLine(curX + curW, 0, curX, getHeight()); ix++; if (!isMirrored()) { curX += curW; } if (ix < columnWidths.size()) { curW = (columnWidths.get(ix)).intValue(); } if (isMirrored()) { curX -= curW; } } } } void paintNodes(List<GraphNode> nodes, Point p, Graphics g, int column) { List<GraphNode> allChildren = new ArrayList<GraphNode>(); for (int i = 0; i < nodes.size(); i++) { GraphNode node = nodes.get(i); if (openNodes.contains(node)) { allChildren.addAll((nodes.get(i)).getChildren()); } } if (!allChildren.isEmpty()) { if (isMirrored()) { p.x -= (columnWidths.get(column)).intValue(); } int y = (dimension.height - (((columnHeights.get(column)).intValue()))) >> 1; for (int i = 0; i < allChildren.size(); i++) { GraphNode n = allChildren.get(i); // visit node if (isMirrored()) { paintNode(g, n, p.x + (columnWidths.get(column)).intValue() - n.width, y); } else { paintNode(g, n, p.x, y); } int h = topSpacer + getHeight(g, n) + bottomSpacer; y += h; } rowNodes.add(allChildren); if (!isMirrored()) { p.x += (columnWidths.get(column)).intValue(); } paintNodes(allChildren, p, g, column + 1); } } public int getWidth() { dimension = getDimension(graph.getRoot()); return dimension.width; } public int getHeight() { dimension = getDimension(graph.getRoot()); return dimension.height; } /** * @return */ public Dimension getDimension() { Dimension d = getDimension(graph.getRoot()); return d; } Dimension getDimension(GraphNode node) { return getDimension(null, node); } Dimension getDimension(Graphics g, GraphNode node) { columnWidths = new ArrayList<Integer>(); columnHeights = new ArrayList<Integer>(); if (openNodes.contains(node)) { Dimension d = new Dimension(); findTotalDimension(g, preRootList, d); d.height += topSpacer + bottomSpacer; d.width += leftSpacer + rightSpacer; return d; } else { int nw = getWidth(g, node); int nh = getHeight(g, node); int w = leftSpacer + nw + rightSpacer; int h = topSpacer + nh + bottomSpacer; node.width = nw; node.height = nh; columnWidths.add(new Integer(w)); columnHeights.add(new Integer(h)); return new Dimension(w, h); } } void findTotalDimension(Graphics g, List<GraphNode> nodes, Dimension d) { List<GraphNode> allChildren = new ArrayList<GraphNode>(); for (int i = 0; i < nodes.size(); i++) { GraphNode node = nodes.get(i); if (openNodes.contains(node)) { allChildren.addAll((nodes.get(i)).getChildren()); } } int maxW = leftSpacer + rightSpacer; int totH = 0; for (int i = 0; i < allChildren.size(); i++) { GraphNode n = allChildren.get(i); int nw = getWidth(g, n); int nh = getHeight(g, n); n.width = nw; n.height = nh; // visit node int w = leftSpacer + nw + rightSpacer; int h = topSpacer + nh + bottomSpacer; maxW = Math.max(maxW, w); totH += h; } if (!allChildren.isEmpty()) { d.width += maxW; columnWidths.add(new Integer(maxW)); columnHeights.add(new Integer(totH)); d.height = Math.max(d.height, totH); findTotalDimension(g, allChildren, d); } } int getWidth(Graphics g, GraphNode node) { if (node.getPainter() == null) { return defaultNodePainter.getWidth(g, node); } else { return node.getPainter().getWidth(g, node); } } int getHeight(Graphics g, GraphNode node) { if (node.getPainter() == null) { return defaultNodePainter.getHeight(g, node); } else { return node.getPainter().getHeight(g, node); } } void paintNode(Graphics g, GraphNode node, int x, int y) { DefaultNodePainter dnp = node.getPainter(); g.translate(x, y); node.x = x; node.y = y; if (dnp == null) { defaultNodePainter.paint(g, node, isMirrored()); } else { dnp.paint(g, node, isMirrored()); } g.translate(-x, -y); } public GraphNode getNodeAtPosition(int x, int y) { GraphNode res = null; int curX = 0; if (isMirrored()) { curX = getDimension().width - rightSpacer - (columnWidths.get(0)).intValue(); } int curW = 0; int ix = 0; curW = (columnWidths.get(ix)).intValue(); while (!(x >= curX && x <= curX + curW) && ix < columnWidths.size() - 1) { ix++; if (!isMirrored()) { curX += curW; } curW = (columnWidths.get(ix)).intValue(); if (isMirrored()) { curX -= curW; } } if (ix < rowNodes.size()) { List<GraphNode> children = rowNodes.get(ix); for (int cix = 0; res == null && cix < children.size(); cix++) { GraphNode cand = children.get(cix); if (cand.y <= y && cand.y + cand.height >= y) { res = cand; } } } return res; } /** * @return */ public DefaultNodePainter getDefaultNodePainter() { return defaultNodePainter; } /** * @param defaultNodePainter */ public void setDefaultNodePainter(DefaultNodePainter defaultNodePainter) { this.defaultNodePainter = defaultNodePainter; } /** * @return */ public Color getBackground() { return background; } /** * @param background */ public void setBackground(Color background) { this.background = background; } public void setSpacers(int top, int left, int right, int bottom) { topSpacer = top; leftSpacer = left; rightSpacer = right; bottomSpacer = bottom; } /** * @return */ public boolean isMirrored() { return mirrored; } /** * @param mirrored */ public void setMirrored(boolean mirrored) { this.mirrored = mirrored; } }