/*
* 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.actions.lookup;
import gui.actions.AbstractCanceableAction;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.Icon;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import analyser.gui.ClassTree;
import analyser.gui.MainFrame;
import analyser.gui.Selection;
import analyser.logic.Reference;
import analyser.logic.ReferredReference;
import analyser.logic.ReverseReference;
public class LookUpAction extends AbstractCanceableAction {
private static final long serialVersionUID = -9068479725468233223L;
protected static LookUpAction m_inst = null;
protected static LookUpAction m_instInternal = null;
protected int m_refs;
protected int m_curRefs;
protected boolean m_isExternal;
public static LookUpAction getInstance(MainFrame mainFrame) {
if (m_inst == null) {
m_inst = new LookUpAction("Look up external", null);
m_inst.setMainFrame(mainFrame);
m_inst.m_isExternal = true;
}
return m_inst;
}
public static LookUpAction getInstanceInternal(MainFrame mainFrame) {
if (m_instInternal == null) {
m_instInternal = new LookUpAction("Look up internal", null);
m_instInternal.setMainFrame(mainFrame);
m_instInternal.m_isExternal = false;
}
return m_instInternal;
}
protected LookUpAction(String arg0, Icon arg1) {
super(arg0, arg1);
}
@Override
@SuppressWarnings("unchecked")
public void run(ActionEvent e) throws Throwable {
Object oRef = Selection.getSelectedObject();
if (oRef == null /* || !(oRef instanceof RefMethod) */) {
return;
}
Reference mRef = (Reference) oRef;
//boolean thisTree = (oRef instanceof RefInvokation && ((RefInvokation) oRef).isLocal());
ClassTree tree = (m_isExternal == false) ? ((MainFrame) getMainFrame()).getSelectedTree() : ((MainFrame) getMainFrame()).getOppositeSelectedTree();
m_refs = mRef.getCount() * 2;
m_curRefs = 0;
Reference[] invs = getInvokations(mRef, tree == ((MainFrame) getMainFrame()).getMidletTree());
if (isRunning()) {
selectPathsInTree(tree, invs, Reference.class);
}
getMainFrame().setBottomInfo(invs.length + " reference(s) found");
}
public Reference[] getInvokations(Reference ref, boolean isMidletTree) {
List<Reference> res = new ArrayList<Reference>();
if (ref instanceof ReferredReference) {
appendOneReferredReference(res, (ReferredReference) ref, isMidletTree);
} else {
if (ref instanceof ReverseReference) {
ReverseReference reverse = (ReverseReference) ref;
for (ReferredReference referred : reverse.getReferredReference(isMidletTree)) {
res.add(referred);
}
}
Iterator<Reference> i = (ref).getChildren().iterator();
addInvokations(res, i, isMidletTree);
}
return res.toArray(new Reference[res.size()]);
}
public void selectPathsInTree(ClassTree tree, Reference[] invs, Class<? extends Reference>... levels) {
List<TreePath> paths = new ArrayList<TreePath>();
tree.clearSelection();
if (m_isExternal) {
tree.collapseWholeTree();
}
for (int i = 0; i < invs.length; i++) {
TreePath path = tree.getPath(invs[i], levels);
//System.out.println("name " + invs[i].getName() + " treemidlet "+ (tree == ((MainFrame) getMainFrame()).getMidletTree()) + " treeref "+ (tree == ((MainFrame) getMainFrame()).getResourceTree()) );
//System.out.println("path " + path.toString());
if (path != null) {
if (((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject() instanceof ReferredReference) {
path = path.getParentPath();
}
if (!paths.contains(path)) {
paths.add(path);
}
} else {
System.err.println("No path found for " + invs[i]);
}
getMainFrame().actionReportWork(this, 50 + ((45 * i) / (invs.length)));
}
if (isRunning()) {
TreePath[] treePaths = paths.toArray(new TreePath[paths.size()]);
synchronized (tree.getTreeLock()) {
tree.markPaths(treePaths, true);
tree.setSelectionPaths(treePaths);
}
}
}
private void appendOneReferredReference(List<Reference> res, ReferredReference referred, boolean isMidletTree) {
Reference ref;
if (isMidletTree) {
ref = referred.getLocalReferredReference();
} else {
ref = referred.getExternalReferredReference();
}
if (ref != null) {
res.add(ref);
}
}
private void addInvokations(List<Reference> res, Iterator<Reference> refs, boolean isMidletTree) {
while (isRunning() && refs.hasNext()) {
Reference ref = refs.next();
if (ref instanceof ReferredReference) {
appendOneReferredReference(res, (ReferredReference) ref, isMidletTree);
} else {
if (ref instanceof ReverseReference) {
ReverseReference reverse = (ReverseReference) ref;
for (ReferredReference referred : reverse.getReferredReference(isMidletTree)) {
res.add(referred);
}
}
addInvokations(res, ref.getChildren().iterator(), isMidletTree);
}
}
}
@Override
public void handleThrowable(Throwable t) {
getMainFrame().showError("Error during reference look up", t);
t.printStackTrace();
}
@Override
public String getWorkDescription() {
return "Looking up references";
}
}