/**
* erlyberly, erlang trace debugger
* Copyright (C) 2016 Andy Till
*
* This program 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.
*
* This program 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 erlyberly;
import java.util.Arrays;
import java.util.List;
import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangRangeException;
import com.ericsson.otp.erlang.OtpErlangTuple;
import erlyberly.node.OtpUtil;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
public class CallGraphView extends TreeView<ModFunc> {
/**
* A list of module names that will not be expanded in the call graph tree, since
* they have lots of sub-calls, cluttering up the tree and it is assumed most usage
* will be for application calls, not for the standard libs.
*/
private static final List<String> UNEXPANDED_MODULES = Arrays.asList(
"erlang", "gen_server", "io", "io_lib", "lists", "rpc", "unicode");
private ModFuncContextMenu modFuncContextMenu;
public CallGraphView(DbgController aDbgController) {
assert aDbgController != null;
modFuncContextMenu = new ModFuncContextMenu(aDbgController);
getSelectionModel()
.selectedItemProperty()
.addListener((o, old, newItem) -> {
modFuncContextMenu.selectedTreeItemProperty().set(newItem);
if(newItem != null)
modFuncContextMenu.selectedItemProperty().set(newItem.getValue());
});
ModFuncTreeCellFactory modFuncTreeCellFactory;
modFuncTreeCellFactory = new ModFuncTreeCellFactory(aDbgController);
modFuncTreeCellFactory.setShowModuleName(true);
setRoot(new TreeItem<>());
setShowRoot(false);
setContextMenu(modFuncContextMenu);
setCellFactory(modFuncTreeCellFactory);
}
public void callGraph(OtpErlangTuple callStack) {
assert callStack != null;
populateCallGraph(getRoot(), callStack);
}
/**
* Parses erlang terms in the format, into a JavaFX tree.
* <code>
* {{M::atom(), F::atom(), A::integer()}, [{M,F,A}]}
* </code>
*/
private void populateCallGraph(TreeItem<ModFunc> parentModFuncItem, OtpErlangTuple callGraph) {
assert callGraph != null;
OtpErlangTuple mfaTuple = (OtpErlangTuple) OtpUtil.tupleElement(0, callGraph);
OtpErlangList calls = (OtpErlangList) OtpUtil.tupleElement(1, callGraph);
OtpErlangAtom module = (OtpErlangAtom) OtpUtil.tupleElement(0, mfaTuple);
OtpErlangAtom function = (OtpErlangAtom) OtpUtil.tupleElement(1, mfaTuple);
OtpErlangLong arity = (OtpErlangLong) OtpUtil.tupleElement(2, mfaTuple);
try {
// just put something in, this isn't used
boolean exported = false;
boolean synthetic = false;
ModFunc modFunc = new ModFunc(module.atomValue(), function.atomValue(), arity.intValue(), exported, synthetic);
TreeItem<ModFunc> modFuncItem;
modFuncItem = new TreeItem<>(modFunc);
String atomString = module.atomValue();
boolean value = !UNEXPANDED_MODULES.contains(atomString);
modFuncItem.setExpanded(value);
parentModFuncItem.getChildren().add(modFuncItem);
for (OtpErlangObject e : OtpUtil.iterableElements(calls)) {
populateCallGraph(modFuncItem, (OtpErlangTuple) e);
}
}
catch (OtpErlangRangeException e) {
e.printStackTrace();
}
}
}