Sandboxie/SandboxiePlus/SandMan/Models/TraceModel.cpp

341 lines
8.5 KiB
C++
Raw Normal View History

2021-10-15 16:39:43 +01:00
#include "stdafx.h"
#include "TraceModel.h"
#include "../MiscHelpers/Common/Common.h"
#include "../SbiePlusAPI.h"
2023-01-07 15:57:55 +00:00
#define FIRST_COLUMN 0
2021-10-15 16:39:43 +01:00
2023-01-07 15:57:55 +00:00
#define PROCESS_MARK 0x10000000
#define THREAD_MARK 0x20000000
2021-10-15 16:39:43 +01:00
CTraceModel::CTraceModel(QObject* parent)
2023-01-07 15:57:55 +00:00
:QAbstractItemModelEx(parent)
2021-10-15 16:39:43 +01:00
{
2022-09-29 17:28:48 +01:00
m_bTree = false;
2023-01-07 15:57:55 +00:00
m_Root = MkNode(0);
2021-10-15 16:39:43 +01:00
m_LastCount = 0;
}
CTraceModel::~CTraceModel()
{
2023-01-07 15:57:55 +00:00
FreeNode(m_Root);
m_Root = NULL;
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
QList<QModelIndex> CTraceModel::Sync(const QVector<CTraceEntryPtr>& EntryList)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
QList<QModelIndex> NewBranches;
2021-10-15 16:39:43 +01:00
// 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++;
else
i = 0;
}
2023-01-07 15:57:55 +00:00
emit layoutAboutToBeChanged();
2021-10-15 16:39:43 +01:00
for (; i < EntryList.count(); i++)
{
2023-01-07 15:57:55 +00:00
const CTraceEntryPtr& pEntry = EntryList.at(i);
2021-10-15 16:39:43 +01:00
quint64 ID = pEntry->GetUID();
2023-01-07 15:57:55 +00:00
STreeNode* pNode = MkNode(ID);
pNode->pEntry = pEntry;
if (m_bTree)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
quint64 Path = PROCESS_MARK | pEntry->GetProcessId();
Path |= quint64(THREAD_MARK | pEntry->GetThreadId()) << 32;
2021-10-15 16:39:43 +01:00
2023-01-07 15:57:55 +00:00
pNode->Parent = FindParentNode(m_Root, Path, 0, &NewBranches);
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
else
pNode->Parent = m_Root;
2021-10-15 16:39:43 +01:00
2023-01-07 15:57:55 +00:00
//pNode->Row = pNode->Parent->Children.size();
pNode->Parent->Children.append(pNode);
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
emit layoutChanged();
2021-10-15 16:39:43 +01:00
m_LastCount = EntryList.count();
if(m_LastCount)
m_LastID = EntryList.last()->GetUID();
2023-01-07 15:57:55 +00:00
return NewBranches;
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
//__inline uint qHash(const CTraceModel::STracePath& var)
//{
// unsigned int hash = 5381;
// for (quint32* ptr = var.path; ptr < var.path + var.count; ptr++)
// hash = ((hash << 15) + hash) ^ *ptr;
// return hash;
//}
//
//bool operator == (const CTraceModel::STracePath& l, const CTraceModel::STracePath& r)
//{
// if (l.count != r.count)
// return false;
// return memcmp(l.path, r.path, l.count) == 0;
//}
CTraceModel::STreeNode* CTraceModel::FindParentNode(STreeNode* pParent, quint64 Path, int PathsIndex, QList<QModelIndex>* pNewBranches)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
if (2 <= PathsIndex)
return pParent;
quint64 CurPath = PathsIndex == 0 ? Path & 0x00000000FFFFFFFF : Path;
STreeNode* &pNode = m_Branches[CurPath];
if(!pNode)
{
pNode = MkNode(PathsIndex == 0 ? Path & 0x00000000FFFFFFFF : (Path >> 32));
pNode->Parent = pParent;
pNewBranches->append(createIndex(pParent->Children.size(), FIRST_COLUMN, pNode));
2021-10-15 16:39:43 +01:00
2023-01-07 15:57:55 +00:00
//pNode->Row = pParent->Children.size();
pParent->Children.append(pNode);
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
return FindParentNode(pNode, Path, PathsIndex + 1, pNewBranches);
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
void CTraceModel::Clear(bool bMem)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
m_LastCount = 0;
m_LastID.clear();
2021-10-15 16:39:43 +01:00
2023-01-07 15:57:55 +00:00
beginResetModel();
m_Branches.clear();
FreeNode(m_Root);
if (bMem)
m_NodeAllocator.dispose();
m_Root = MkNode(0);
endResetModel();
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
PoolAllocator<sizeof(CTraceModel::STreeNode)> CTraceModel::m_NodeAllocator;
CTraceModel::STreeNode* CTraceModel::MkNode(quint64 Id)
{
STreeNode* pNode = (STreeNode*)m_NodeAllocator.allocate(sizeof(STreeNode));
new (pNode) STreeNode(Id);
return pNode;
//return new STreeNode(Id);
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
void CTraceModel::FreeNode(STreeNode* pNode)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
foreach(STreeNode* pSubNode, pNode->Children)
FreeNode(pSubNode);
pNode->~STreeNode();
m_NodeAllocator.free(pNode);
//delete pNode;
}
2021-10-15 16:39:43 +01:00
2023-01-12 22:10:50 +00:00
bool CTraceModel::TestHighLight(STreeNode* pNode) const
{
if (m_HighLightExp.isEmpty())
return false;
for (int i = 0; i < eCount; i++) {
if (NodeData(pNode, Qt::DisplayRole, i).toString().contains(m_HighLightExp))
return true;
}
return false;
}
2023-01-07 15:57:55 +00:00
QVariant CTraceModel::NodeData(STreeNode* pNode, int role, int section) const
{
const CTraceEntryPtr& pEntry = pNode->pEntry;
if(!pEntry.constData())
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
if (section != FIRST_COLUMN || (role != Qt::DisplayRole && role != Qt::EditRole))
return QVariant();
quint32 id = pNode->ID;
if (id & PROCESS_MARK) {
CTraceEntryPtr pProcEntry; // pick first log entry of first thread to query the process name
if (!pNode->Children.isEmpty()) {
STreeNode* pSubNode = pNode->Children.first();
if (!pSubNode->Children.isEmpty())
pProcEntry = pSubNode->Children.first()->pEntry;
}
if (pProcEntry && !pProcEntry->GetProcessName().isEmpty())
return tr("%1 (%2)").arg(pProcEntry->GetProcessName()).arg(pProcEntry->GetProcessId());
return tr("Process %1").arg(id & 0x0FFFFFFF);
}
else if (id & THREAD_MARK)
return tr("Thread %1").arg(id & 0x0FFFFFFF);
2021-10-15 16:39:43 +01:00
else
2023-01-07 15:57:55 +00:00
return QString::number(id, 16).rightJustified(8, '0');
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
switch(role)
2021-10-15 16:39:43 +01:00
{
2023-01-07 15:57:55 +00:00
case Qt::DisplayRole:
case Qt::EditRole: // sort role
{
switch (section)
{
//case eProcess: return pEntry->GetProcessId();
//case eTimeStamp: return pEntry->GetUID();
case eProcess: {
if(!m_bTree) {
QString Name = pEntry->GetProcessName();
return QString("%1 (%2, %3) - %4").arg(Name.isEmpty() ? tr("Unknown") : Name)
2023-01-12 22:10:50 +00:00
.arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId())
.arg(QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz"));
2023-01-07 15:57:55 +00:00
} else
2023-01-12 22:10:50 +00:00
return QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz");
2023-01-07 15:57:55 +00:00
}
case eType: return pEntry->GetTypeStr();
case eStatus: return pEntry->GetStautsStr();
case eValue: {
QString sValue = pEntry->GetName();
if (!sValue.isEmpty() && !pEntry->GetMessage().isEmpty())
sValue += " ";
sValue += pEntry->GetMessage();
return sValue;
}
}
}
2023-01-12 22:10:50 +00:00
case Qt::BackgroundRole:
{
if(!CTreeItemModel::GetDarkMode())
return TestHighLight(pNode) ? QColor(Qt::yellow) : QVariant();
break;
}
case Qt::ForegroundRole:
{
if(CTreeItemModel::GetDarkMode())
return TestHighLight(pNode) ? QColor(Qt::yellow) : QVariant();
break;
}
2021-10-15 16:39:43 +01:00
}
2023-01-07 15:57:55 +00:00
return QVariant();
2021-10-15 16:39:43 +01:00
}
CTraceEntryPtr CTraceModel::GetEntry(const QModelIndex& index) const
{
if (!index.isValid())
return CTraceEntryPtr();
2023-01-07 15:57:55 +00:00
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
2021-10-15 16:39:43 +01:00
ASSERT(pNode);
return pNode->pEntry;
}
2023-01-07 15:57:55 +00:00
QVariant CTraceModel::data(const QModelIndex &index, int role) const
{
return Data(index, role, index.column());
}
QVariant CTraceModel::GetItemID(const QModelIndex& index) const
{
if (!index.isValid())
return QVariant();
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
return pNode->ID;
}
QVariant CTraceModel::Data(const QModelIndex &index, int role, int section) const
{
if (!index.isValid())
return QVariant();
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
ASSERT(pNode);
return NodeData(pNode, role, section);
}
Qt::ItemFlags CTraceModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
if(index.column() == 0)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QModelIndex CTraceModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
STreeNode* pParent;
if (!parent.isValid())
pParent = m_Root;
else
pParent = static_cast<STreeNode*>(parent.internalPointer());
if(STreeNode* pNode = pParent->Children.count() > row ? pParent->Children[row] : NULL)
return createIndex(row, column, pNode);
return QModelIndex();
}
QModelIndex CTraceModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
ASSERT(pNode->Parent);
STreeNode* pParent = pNode->Parent;
if (pParent == m_Root)
return QModelIndex();
int row = 0;
if(pParent->Parent)
row = pParent->Parent->Children.indexOf(pParent);
return createIndex(row, 0, pParent);
}
int CTraceModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
STreeNode* pNode;
if (!parent.isValid())
pNode = m_Root;
else
pNode = static_cast<STreeNode*>(parent.internalPointer());
return pNode->Children.count();
}
2021-10-15 16:39:43 +01:00
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();
2021-03-04 20:13:45 +00:00
}