#include "TStructViewer.h"
#include "TStructNodeProperty.h"
#include "TStructViewerGUI.h"
#include "TStructNode.h"
#include <TDataMember.h>
#include <TVirtualCollectionProxy.h>
#include <TClassEdit.h>
#include <vector>
ClassImp(TStructViewer);
class TA {
public:
virtual ~TA() {}
};
// <p> In this picture we can see TStructViewer with pointer to TList which contains
// other collections and objects of various classes</p>
// <img src="gif/TStructViewer1.jpg">
// End_Html
// <p> Other screenshot presents opened TStructNodeEditor</p>
// <img src="gif/TStructViewer2.jpg">
// End_Html
TStructViewer::TStructViewer(void* ptr, const char * clname)
{
fPointer = NULL;
fPointerClass = NULL;
fTopNode = NULL;
fColors.Add(new TStructNodeProperty("+", 17));
fGUI = new TStructViewerGUI(this, NULL, &fColors);
SetPointer(ptr, clname);
}
TStructViewer::~TStructViewer()
{
Reset();
fColors.SetOwner();
fColors.Clear();
}
void TStructViewer::AddNode(TStructNode* node, ULong_t size)
{
TList* list = (TList*)fLevelArray[node->GetLevel()];
if(!list) {
fLevelArray[node->GetLevel()] = list = new TList();
}
list->Add(node);
fLevelMembersCount(node->GetLevel())++;
fLevelSize(node->GetLevel()) += size;
}
void TStructViewer::CountMembers(TClass* cl, TStructNode* parent, void* pointer)
{
if(!cl) {
return;
}
if (cl->InheritsFrom("TClass")) {
return;
}
cl->BuildRealData(parent->GetPointer());
TIter it(cl->GetListOfDataMembers());
TDataMember* dm;
while ((dm = (TDataMember*) it() ))
{
parent->SetAllMembersCount(parent->GetAllMembersCount() + 1);
parent->SetMembersCount(parent->GetMembersCount() + 1);
if (dm->Property() & kIsStatic) {
continue;
}
void* ptr = NULL;
if(dm->IsaPointer()) {
TString trueTypeName = dm->GetTrueTypeName();
if(trueTypeName.EndsWith("**")) {
continue;
}
if (!pointer) {
continue;
}
void** pptr = (void**)((ULong_t)pointer + dm->GetOffset());
ptr = *pptr;
if (!ptr) {
continue;
}
if(fPointers.GetValue((ULong_t)ptr)) {
continue;
} else {
fPointers.Add((ULong_t)ptr, (ULong_t)ptr);
}
ULong_t size = 0;
if (TClass* cl2 = TClass::GetClass(dm->GetTypeName())) {
size = cl2->Size();
}
if(size == 0) {
size = dm->GetUnitSize();
}
ENodeType type;
if(dm->GetDataType()) {
type = kBasic;
} else {
type = kClass;
}
TStructNode* node = new TStructNode(dm->GetName(), dm->GetTypeName(), ptr, parent, size, type);
AddNode(node, size);
CountMembers(TClass::GetClass(dm->GetTypeName()), node, ptr);
parent->SetTotalSize(parent->GetTotalSize() + node->GetTotalSize() - size);
parent->SetAllMembersCount(parent->GetAllMembersCount() + node->GetAllMembersCount() - 1);
} else {
ptr = (void*)((ULong_t)pointer + dm->GetOffset());
if (!ptr) {
continue;
}
CountMembers(TClass::GetClass(dm->GetTypeName()), parent, ptr);
}
if (dm->IsSTLContainer()) {
parent->SetNodeType(kSTLCollection);
TClass* stlClass = TClass::GetClass(dm->GetTypeName());
if (!stlClass) {
continue;
}
TVirtualCollectionProxy* proxy = stlClass->GetCollectionProxy();
if (!proxy) {
continue;
}
TVirtualCollectionProxy::TPushPop helper(proxy, ptr);
UInt_t count = proxy->Size();
parent->SetMembersCount(parent->GetMembersCount() + count);
if(!proxy->HasPointers() || proxy->GetType()) {
parent->SetTotalSize(parent->GetTotalSize() + count * proxy->Sizeof());
parent->SetAllMembersCount(parent->GetAllMembersCount() + count);
} else {
TClass* clProxy = proxy->GetValueClass();
TString name;
TString typeName;
ULong_t size = 0;
if (clProxy) {
name = clProxy->GetName();
typeName = clProxy->GetName();
size = clProxy->Size();
} else {
continue;
}
if (size == 0) {
size = proxy->Sizeof();
}
Bool_t ptp = kFALSE;
std::vector<std::string> parts;
int loc;
TClassEdit::GetSplit(dm->GetTypeName(), parts, loc);
std::vector<std::string>::const_iterator iPart = parts.begin();
while (iPart != parts.end() && *iPart == "")
++iPart;
if (iPart != parts.end() && *iPart != dm->GetTypeName()) {
for (std::vector<std::string>::const_iterator iP = iPart,
iPE = parts.end(); iP != iPE; ++iP) {
if (TString(TClassEdit::ResolveTypedef(iP->c_str(), true).c_str()).EndsWith("**")){
ptp = kTRUE;
break;
}
}
}
if (ptp) {
continue;
}
void* element;
for (UInt_t i = 0; i < count ; i++) {
element = *(void**)proxy->At(i);
if (!element) {
continue;
}
if (clProxy->InheritsFrom("TObject")) {
name = ((TObject*) element)->GetName();
}
TStructNode* node = new TStructNode(name, typeName, element, parent, size, kClass);
AddNode(node, size);
parent->SetMembersCount(parent->GetMembersCount() + 1);
CountMembers(clProxy, node, element);
parent->SetTotalSize(parent->GetTotalSize() + node->GetTotalSize());
parent->SetAllMembersCount(parent->GetAllMembersCount() + node->GetAllMembersCount());
}
}
}
}
if(cl->InheritsFrom("TCollection")) {
parent->SetNodeType(kCollection);
if (!pointer) {
return;
}
TIter it2((TCollection*)pointer);
TObject* item;
while((item = it2())) {
ULong_t size = 0;
if (TClass* cl3 = item->IsA()){
size = cl3->Size();
}
if (size == 0) {
size = sizeof(item);
}
TStructNode* node = new TStructNode(item->GetName(), item->ClassName(), item, parent, size, kClass);
AddNode(node, size);
parent->SetMembersCount(parent->GetMembersCount() + 1);
CountMembers(item->IsA(), node, item);
parent->SetTotalSize(parent->GetTotalSize() + node->GetTotalSize());
parent->SetAllMembersCount(parent->GetAllMembersCount() + node->GetAllMembersCount());
}
}
}
void TStructViewer::Draw(Option_t *option)
{
TString opt(option);
if(opt == "count") {
} else if (opt == "size") {
}
if (fTopNode) {
fGUI->SetNodePtr(fTopNode);
} else {
}
}
TCanvas* TStructViewer::GetCanvas()
{
return fGUI->GetCanvas();
}
TGMainFrame* TStructViewer::GetFrame()
{
return fGUI;
}
void* TStructViewer::GetPointer() const
{
return fPointer;
}
TExMap TStructViewer::GetLevelMembersCount() const
{
return fLevelMembersCount;
}
TExMap TStructViewer::GetLevelSize() const
{
return fLevelSize;
}
Bool_t TStructViewer::GetLinksVisibility() const
{
return fGUI->GetLinksVisibility();
}
void TStructViewer::Prepare()
{
if (fTopNode) {
Reset();
}
ULong_t size = fPointerClass->Size();
TString name = "Main pointer";
if (fPointerClass->InheritsFrom("TObject")) {
name = ((TObject*) fPointer)->GetName();
}
fTopNode = new TStructNode(name, fPointerClass->GetName(), fPointer, NULL, size, kClass);
AddNode(fTopNode, size);
CountMembers(fPointerClass, fTopNode, fPointer);
}
void TStructViewer::Reset()
{
TList* lst;
TIter it(&fLevelArray);
while ((lst = (TList*) it() )) {
lst->SetOwner();
lst->Clear();
}
fLevelMembersCount.Clear();
fLevelSize.Clear();
fPointers.Clear();
fLevelArray.Clear();
fTopNode = NULL;
}
void TStructViewer::SetColor(TString name, Int_t color)
{
TIter it(&fColors);
TStructNodeProperty* prop;
while ((prop = (TStructNodeProperty*) it() )) {
if (name == prop->GetName()) {
prop->SetColor(TColor::GetColor(color));
fGUI->Update();
return;
}
}
prop = new TStructNodeProperty(name.Data(), color);
fColors.Add(prop);
fColors.Sort();
}
void TStructViewer::SetLinksVisibility(Bool_t val)
{
fGUI->SetLinksVisibility(val);
}
void TStructViewer::SetPointer(void* ptr, const char* clname)
{
if (ptr) {
TA* a = (TA*) ptr;
if (clname) {
fPointerClass = TClass::GetClass(clname);
} else {
fPointerClass = TClass::GetClass(typeid(*a));
}
if (!fPointerClass) {
return;
}
fPointer = ptr;
Prepare();
fGUI->SetNodePtr(fTopNode);
}
}
TColor TStructViewer::GetColor(const char* typeName)
{
TIter it(&fColors);
TStructNodeProperty* prop;
while((prop = (TStructNodeProperty*) it())) {
if (!strcmp(prop->GetName(), typeName)) {
return prop->GetColor();
}
}
return TColor();
}