321 lines
8.4 KiB
C++
321 lines
8.4 KiB
C++
#include "stdafx.h"
|
|
#include "TraceModel.h"
|
|
#include "../MiscHelpers/Common/Common.h"
|
|
#include "../SbiePlusAPI.h"
|
|
|
|
|
|
|
|
CTraceModel::CTraceModel(QObject* parent)
|
|
:CTreeItemModel(parent)
|
|
{
|
|
m_bTree = false;
|
|
m_bObjTree = false;
|
|
|
|
m_Root = MkNode(QVariant());
|
|
|
|
m_LastCount = 0;
|
|
}
|
|
|
|
CTraceModel::~CTraceModel()
|
|
{
|
|
}
|
|
|
|
/*QList<QVariant> CTraceModel::MakePath(const CTraceEntryPtr& pEntry, const QList<CTraceEntryPtr>& EntryList)
|
|
{
|
|
quint64 ParentID = pEntry->GetParentWnd();
|
|
CTraceEntryPtr pParent = EntryList.value(ParentID);
|
|
|
|
QList<QVariant> Path;
|
|
if (!pParent.isNull() && ParentID != pEntry->GetHWnd())
|
|
{
|
|
Path = MakeWndPath(pParent, EntryList);
|
|
Path.append(ParentID);
|
|
}
|
|
return Path;
|
|
}
|
|
|
|
bool CTraceModel::TestPath(const QList<QVariant>& Path, const CTraceEntryPtr& pEntry, const QList<CTraceEntryPtr>& EntryList, int Index)
|
|
{
|
|
quint64 ParentID = pEntry->GetParentWnd();
|
|
CTraceEntryPtr pParent = EntryList.value(ParentID);
|
|
|
|
if (!pParent.isNull() && ParentID != pEntry->GetHWnd())
|
|
{
|
|
if (Index >= Path.size() || Path[Path.size() - Index - 1] != ParentID)
|
|
return false;
|
|
|
|
return TestWndPath(Path, pParent, EntryList, Index + 1);
|
|
}
|
|
|
|
return Path.size() == Index;
|
|
}*/
|
|
|
|
QList<QVariant> CTraceModel::Sync(const QVector<CTraceEntryPtr>& EntryList, int (*Filter)(const CTraceEntryPtr&, void*), void* params)
|
|
{
|
|
QList<QVariant> Added;
|
|
QMap<QList<QVariant>, QList<STreeNode*> > New;
|
|
QHash<QVariant, STreeNode*> Old = m_Map;
|
|
|
|
// Note: since this is a log and we ever always only add entries we save cpu time by always skipping the already know portion of the list
|
|
|
|
int i = 0;
|
|
if (EntryList.count() >= m_LastCount && m_LastCount > 0)
|
|
{
|
|
i = m_LastCount - 1;
|
|
if (m_LastID == EntryList.at(i)->GetUID())
|
|
{
|
|
i++;
|
|
Old.clear();
|
|
}
|
|
else
|
|
i = 0;
|
|
}
|
|
|
|
for (; i < EntryList.count(); i++)
|
|
{
|
|
CTraceEntryPtr pEntry = EntryList.at(i);
|
|
|
|
int iFilter = Filter(pEntry, params);
|
|
if (!iFilter)
|
|
continue;
|
|
|
|
quint64 ID = pEntry->GetUID();
|
|
|
|
QStringList NtPath;
|
|
if (m_bObjTree) {
|
|
QString Name = pEntry->GetName();
|
|
if (Name.left(1) != "\\")
|
|
continue;
|
|
NtPath = Name.split("\\");
|
|
}
|
|
|
|
QModelIndex Index;
|
|
|
|
QHash<QVariant, STreeNode*>::iterator I = Old.find(ID);
|
|
STraceNode* pNode = I != Old.end() ? static_cast<STraceNode*>(I.value()) : NULL;
|
|
if (!pNode /*|| (m_bTree ? !TestPath(pNode->Path, pEntry, EntryList) : !pNode->Path.isEmpty())*/)
|
|
{
|
|
pNode = static_cast<STraceNode*>(MkNode(ID));
|
|
pNode->Values.resize(columnCount());
|
|
if (m_bTree)
|
|
{
|
|
//pNode->Path.append(QString("pid_%1").arg(pEntry->GetProcessId()));
|
|
//pNode->Path.append(QString("tid_%1").arg(pEntry->GetThreadId()));
|
|
if (pEntry->GetProcessName().isEmpty())
|
|
pNode->Path.append(tr("Process %1").arg(pEntry->GetProcessId()));
|
|
else
|
|
pNode->Path.append(tr("%1 (%2)").arg(pEntry->GetProcessName()).arg(pEntry->GetProcessId()));
|
|
pNode->Path.append(QString("Thread %1").arg(pEntry->GetThreadId()));
|
|
//pNode->Path = MakePath(pEntry, EntryList);
|
|
}
|
|
if (m_bObjTree) {
|
|
foreach(const QString & Part, NtPath) {
|
|
if(!Part.isEmpty())
|
|
pNode->Path.append(Part);
|
|
}
|
|
}
|
|
pNode->pEntry = pEntry;
|
|
New[pNode->Path].append(pNode);
|
|
//SetProcessName(pEntry->GetProcessName(), pEntry->GetProcessId(), pEntry->GetThreadId());
|
|
}
|
|
else
|
|
{
|
|
I.value() = NULL;
|
|
Index = Find(m_Root, pNode);
|
|
}
|
|
|
|
//if(Index.isValid()) // this is to slow, be more precise
|
|
// emit dataChanged(createIndex(Index.row(), 0, pNode), createIndex(Index.row(), columnCount()-1, pNode));
|
|
|
|
int Col = 0;
|
|
bool State = false;
|
|
int Changed = 0;
|
|
|
|
if (pNode->bHighLight != (iFilter == 2)) {
|
|
pNode->bHighLight = (iFilter == 2);
|
|
pNode->Color = pNode->bHighLight ? Qt::yellow : QColor();
|
|
Changed = -1;
|
|
}
|
|
|
|
for (int section = 0; section < columnCount(); section++)
|
|
{
|
|
if (!m_Columns.contains(section))
|
|
continue; // ignore columns which are hidden
|
|
|
|
QVariant Value;
|
|
switch (section)
|
|
{
|
|
//case eProcess: Value = pEntry->GetProcessId(); break;
|
|
//case eTimeStamp: Value = pEntry->GetUID(); break;
|
|
case eProcess: Value = pEntry->GetUID(); break;
|
|
case eType: Value = pEntry->GetTypeStr(); break;
|
|
case eStatus: Value = pEntry->GetStautsStr(); break;
|
|
case eValue: {
|
|
QString sValue = pEntry->GetName();
|
|
if (!sValue.isEmpty() && !pEntry->GetMessage().isEmpty())
|
|
sValue += " ";
|
|
sValue += pEntry->GetMessage();
|
|
Value = sValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
STraceNode::SValue& ColValue = pNode->Values[section];
|
|
|
|
if (ColValue.Raw != Value)
|
|
{
|
|
if (Changed == 0)
|
|
Changed = 1;
|
|
ColValue.Raw = Value;
|
|
|
|
switch (section)
|
|
{
|
|
/*case eProcess:
|
|
{
|
|
CBoxedProcessPtr pProcess = theAPI->GetProcessById(pEntry->GetProcessId());
|
|
ColValue.Formatted = QString("%1 (%2, %3)").arg(pProcess.isNull() ? tr("Unknown") : pProcess->GetProcessName()).arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId());
|
|
break;
|
|
}
|
|
case eTimeStamp: ColValue.Formatted = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"); break;*/
|
|
case eProcess:
|
|
if(!m_bTree) {
|
|
QString Name = pEntry->GetProcessName();
|
|
ColValue.Formatted = QString("%1 (%2, %3) - %4").arg(Name.isEmpty() ? tr("Unknown") : Name)
|
|
.arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId()).arg(pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"));
|
|
} else
|
|
ColValue.Formatted = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz");
|
|
break;
|
|
//case eType: ColValue.Formatted = ; break;
|
|
//case eValue: ColValue.Formatted = ; break;
|
|
}
|
|
}
|
|
|
|
if (State != (Changed != 0))
|
|
{
|
|
if (State && Index.isValid())
|
|
emit dataChanged(createIndex(Index.row(), Col, pNode), createIndex(Index.row(), section - 1, pNode));
|
|
State = (Changed != 0);
|
|
Col = section;
|
|
}
|
|
if (Changed == 1)
|
|
Changed = 0;
|
|
}
|
|
if (State && Index.isValid())
|
|
emit dataChanged(createIndex(Index.row(), Col, pNode), createIndex(Index.row(), columnCount() - 1, pNode));
|
|
|
|
}
|
|
|
|
m_LastCount = EntryList.count();
|
|
if(m_LastCount)
|
|
m_LastID = EntryList.last()->GetUID();
|
|
|
|
CTreeItemModel::Sync(New, Old, &Added);
|
|
|
|
return Added;
|
|
}
|
|
|
|
void CTraceModel::Clear()
|
|
{
|
|
m_LastCount = 0;
|
|
m_LastID.clear();
|
|
|
|
/*foreach(quint32 pid, m_PidMap.keys()) {
|
|
SProgInfo& Info = m_PidMap[pid];
|
|
Info.Dirty = true;
|
|
Info.Threads.clear();
|
|
}
|
|
m_PidMap.clear();*/
|
|
CTreeItemModel::Clear();
|
|
}
|
|
|
|
/*
|
|
void CTraceModel::SetProcessName(const QString& Name, quint32 pid, quint32 tid)
|
|
{
|
|
SProgInfo& Info = m_PidMap[pid];
|
|
Info.Name = Name;
|
|
if (!Info.Threads.contains(tid)) {
|
|
Info.Threads.insert(tid);
|
|
Info.Dirty = true;
|
|
}
|
|
if (Info.Dirty) {
|
|
Info.Dirty = false;
|
|
emit NewBranche();
|
|
}
|
|
}
|
|
|
|
QString CTraceModel::GetProcessName(quint32 pid)
|
|
{
|
|
SProgInfo& Info = m_PidMap[pid];
|
|
return Info.Name;
|
|
}
|
|
|
|
void CTraceModel::LogThreadId(quint32 pid, quint32 tid)
|
|
{
|
|
SProgInfo& Info = m_PidMap[pid];
|
|
if (!Info.Threads.contains(tid)) {
|
|
Info.Threads.insert(tid);
|
|
emit NewBranche();
|
|
}
|
|
}
|
|
*/
|
|
|
|
CTraceModel::STreeNode* CTraceModel::MkVirtualNode(const QVariant& Id, STreeNode* pParent)
|
|
{
|
|
STreeNode* pNode = CTreeItemModel::MkVirtualNode(Id, pParent);
|
|
|
|
/*StrPair typeId = Split2(Id.toString(), "_");
|
|
if (typeId.first == "pid")
|
|
{
|
|
quint32 pid = typeId.second.toUInt();
|
|
QString Name = GetProcessName(pid);
|
|
pNode->Values[0].Raw = pid;
|
|
if(!Name.isEmpty())
|
|
pNode->Values[0].Formatted = tr("%1 (%2)").arg(Name).arg(pid);
|
|
else
|
|
pNode->Values[0].Formatted = tr("Process %1").arg(pid);
|
|
}
|
|
else if (typeId.first == "tid")
|
|
{
|
|
quint32 tid = typeId.second.toUInt();
|
|
quint32 pid = Split2(pParent->ID.toString(), "_").second.toUInt();
|
|
LogThreadId(pid, tid);
|
|
pNode->Values[0].Raw = tid;
|
|
pNode->Values[0].Formatted = tr("Thread %1").arg(tid);
|
|
}
|
|
else*/
|
|
pNode->Values[0].Raw = pNode->Values[0].Formatted = Id;
|
|
|
|
return pNode;
|
|
}
|
|
|
|
CTraceEntryPtr CTraceModel::GetEntry(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return CTraceEntryPtr();
|
|
|
|
STraceNode* pNode = static_cast<STraceNode*>(index.internalPointer());
|
|
ASSERT(pNode);
|
|
|
|
return pNode->pEntry;
|
|
}
|
|
|
|
int CTraceModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
return eCount;
|
|
}
|
|
|
|
QVariant CTraceModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
|
{
|
|
switch (section)
|
|
{
|
|
case eProcess: return tr("Process");
|
|
//case eTimeStamp: return tr("Time Stamp");
|
|
case eType: return tr("Type");
|
|
case eStatus: return tr("Status");
|
|
case eValue: return tr("Value");
|
|
}
|
|
}
|
|
return QVariant();
|
|
} |