/* * 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 analyser.gui; import gui.graph.DefaultGraphPainter; import gui.graph.GraphNode; import gui.graph.GraphPanel; import java.awt.Color; import java.awt.Font; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import analyser.gui.actions.ShowBytecodeAction; import analyser.gui.actions.bytecodemod.GraphMarkAction; import analyser.gui.actions.lookup.AbstractCallGraphAction; import analyser.logic.InvSnooper; import mereflect.MEMethod; public class MAGraphPanel extends GraphPanel { private static final long serialVersionUID = -4262422603167294033L; static final Color COL_NODE = new Color(238, 238, 255); MainFrame mainFrame; AbstractCallGraphAction gAction; RefNode selectedNode; List<InvSnooper.Invokation> callChain; MANodePainter defaultNodePainter; MANodePainter markedNodePainter; JPopupMenu nodePopup = new JPopupMenu(); JPopupMenu defaultPopup = new JPopupMenu(); JPopupMenu popup; boolean mirrored; public MAGraphPanel(MainFrame mf, DefaultGraphPainter dga, boolean isMirrored, AbstractCallGraphAction gAction) { super(dga); this.gAction = gAction; mainFrame = mf; mirrored = isMirrored; defaultNodePainter = new MANodePainter(); markedNodePainter = new MANodePainter(); defaultNodePainter.setSpacers(4, 16, 16, 4); defaultNodePainter.setBackground(COL_NODE); defaultNodePainter.setBorderColor(Color.gray); defaultNodePainter.setForeground(Color.blue); defaultNodePainter.setLineColor(Color.lightGray); defaultNodePainter.setFont(Font.decode("verdana")); markedNodePainter.setSpacers(4, 16, 16, 4); markedNodePainter.setBackground(Color.blue); markedNodePainter.setBorderColor(Color.gray); markedNodePainter.setForeground(Color.white); markedNodePainter.setLineColor(Color.gray); markedNodePainter.setFont(Font.decode("verdana")); dga.setMirrored(isMirrored); dga.setDefaultNodePainter(defaultNodePainter); dga.setBackground(Color.white); dga.setSpacers(8, 16, 16, 8); addMouseListener(new GraphPanelMouseListener()); nodePopup.add(ShowBytecodeAction.getInstance(getMainFrame())); nodePopup.add(GraphMarkAction.getInstance(getMainFrame())); } public MainFrame getMainFrame() { return mainFrame; } public MEMethod getSelectedMethod() { if (selectedNode == null) { return null; } else { return ((InvSnooper.Invokation) selectedNode.getUserObject()).toMethod; } } public List<InvSnooper.Invokation> getCallChain() { if (callChain != null && !mirrored) { List<InvSnooper.Invokation> reverseCallChain = new ArrayList<InvSnooper.Invokation>(); for (int i = callChain.size() - 1; i >= 0; i--) { reverseCallChain.add(callChain.get(i)); } return reverseCallChain; } return callChain; } class GraphPanelMouseListener extends MouseAdapter { GraphNode markedNode; @Override public void mouseClicked(MouseEvent me) { RefNode node = (RefNode) getPainter().getNodeAtPosition(me.getX(), me.getY()); if (node != null) { Selection.setSelectedObject(MAGraphPanel.this, node.getUserObject()); } if (SwingUtilities.isLeftMouseButton(me)) { if (node != null) { toggleNodeOpened(node); } } else { if (popup != null) { popup.setVisible(false); popup = null; } if (node != null) { selectedNode = node; nodePopup.show(me.getComponent(), me.getX(), me.getY()); popup = nodePopup; } unmarkPath(); markPath(node); } revalidate(); repaint(); } void unmarkPath() { if (markedNode != null) { GraphNode curNode = markedNode; while (curNode != null) { curNode.setPainter(defaultNodePainter); if (curNode instanceof RefNode) { ((RefNode) curNode).setSelected(false); } curNode = curNode.getParent(); } markedNode = null; } callChain = null; } void markPath(RefNode node) { if (node != null) { callChain = new ArrayList<InvSnooper.Invokation>(); GraphNode curNode = node; markedNode = node; while (curNode != null && curNode.getUserObject() instanceof InvSnooper.Invokation) { callChain.add((InvSnooper.Invokation) curNode.getUserObject()); curNode.setPainter(markedNodePainter); if (curNode instanceof RefNode) { ((RefNode) curNode).setSelected(true); } curNode = curNode.getParent(); } } } void toggleNodeOpened(RefNode node) { List<GraphNode> children = node.getChildren(); for (int cIx = 0; cIx < children.size(); cIx++) { RefNode refNode = (RefNode) children.get(cIx); if (!refNode.isPopuplated()) { List<InvSnooper.Invokation> calls = null; try { InvSnooper.Invokation inv = ((InvSnooper.Invokation) refNode.getUserObject()); calls = gAction.getReferences(inv.toMethod, (inv.flags & InvSnooper.ABSTRACT) != 0 || (inv.flags & InvSnooper.OVERRIDDEN) != 0); } catch (Throwable e1) { e1.printStackTrace(); } for (int i = 0; calls != null && i < calls.size(); i++) { InvSnooper.Invokation inv = calls.get(i); refNode.add(new RefNode(inv, inv.flags)); } refNode.setPopuplated(true); } } if (getPainter().isNodeOpened(node)) { getPainter().closeNode(node); } else { getPainter().openNode(node); } revalidate(); repaint(); } } }