1.6.6
This commit is contained in:
parent
e5f40dd9d8
commit
7ce252fb36
|
@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
## Changed
|
||||
- improved trace log retrival greately improving performance
|
||||
- improved list/tree finder
|
||||
- improved trace logging
|
||||
|
||||
### Fixed
|
||||
- fixed potential BSOD issue in the driver
|
||||
|
|
|
@ -553,6 +553,8 @@ _FX void Session_MonitorPutEx(ULONG type, const WCHAR** strings, ULONG* lengths,
|
|||
|
||||
if (session->monitor_log) {
|
||||
|
||||
LARGE_INTEGER timestamp = Util_GetTimestamp();
|
||||
|
||||
ULONG pid = (ULONG)hpid;
|
||||
ULONG tid = (ULONG)htid;
|
||||
|
||||
|
@ -561,12 +563,13 @@ _FX void Session_MonitorPutEx(ULONG type, const WCHAR** strings, ULONG* lengths,
|
|||
data_len += ((lengths ? lengths [i] : wcslen(strings[i])) + 1) * sizeof(WCHAR);
|
||||
|
||||
|
||||
//[Type 4][PID 4][TID 4][Data n*2]
|
||||
SIZE_T entry_size = 4 + 4 + 4 + data_len;
|
||||
//[Time 8][Type 4][PID 4][TID 4][Data n*2]
|
||||
SIZE_T entry_size = 8 + 4 + 4 + 4 + data_len;
|
||||
|
||||
CHAR* write_ptr = log_buffer_push_entry((LOG_BUFFER_SIZE_T)entry_size, session->monitor_log, FALSE);
|
||||
if (write_ptr) {
|
||||
WCHAR null_char = L'\0';
|
||||
log_buffer_push_bytes((CHAR*)×tamp.QuadPart, 8, &write_ptr, session->monitor_log);
|
||||
log_buffer_push_bytes((CHAR*)&type, 4, &write_ptr, session->monitor_log);
|
||||
log_buffer_push_bytes((CHAR*)&pid, 4, &write_ptr, session->monitor_log);
|
||||
log_buffer_push_bytes((CHAR*)&tid, 4, &write_ptr, session->monitor_log);
|
||||
|
@ -925,6 +928,7 @@ _FX NTSTATUS Session_Api_MonitorGetEx(PROCESS* proc, ULONG64* parms)
|
|||
API_MONITOR_GET_EX_ARGS* args = (API_MONITOR_GET_EX_ARGS*)parms;
|
||||
NTSTATUS status;
|
||||
//ULONG* seq_num;
|
||||
LARGE_INTEGER timestamp;
|
||||
ULONG* log_type;
|
||||
ULONG* log_pid;
|
||||
ULONG* log_tid;
|
||||
|
@ -1007,7 +1011,9 @@ _FX NTSTATUS Session_Api_MonitorGetEx(PROCESS* proc, ULONG64* parms)
|
|||
// __leave;
|
||||
//}
|
||||
|
||||
//[Type 4][PID 4][TID 4][Data n*2]
|
||||
//[Time 8][Type 4][PID 4][TID 4][Data n*2]
|
||||
|
||||
log_buffer_get_bytes((CHAR*)×tamp.QuadPart, 8, &read_ptr, session->monitor_log);
|
||||
|
||||
log_buffer_get_bytes((CHAR*)log_type, 4, &read_ptr, session->monitor_log);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 2004-2020 Sandboxie Holdings, LLC
|
||||
* Copyright 2020-2021 David Xanatos, xanasoft.com
|
||||
* Copyright 2020-2023 David Xanatos, xanasoft.com
|
||||
*
|
||||
* 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
|
||||
|
@ -443,3 +443,30 @@ retry:
|
|||
return pid;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Util_GetTime
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX LARGE_INTEGER Util_GetTimestamp(void)
|
||||
{
|
||||
static LARGE_INTEGER gMonitorStartCounter;
|
||||
static LARGE_INTEGER gPerformanceFrequency;
|
||||
static LARGE_INTEGER gMonitorStartTime = { 0 };
|
||||
|
||||
if (gMonitorStartTime.QuadPart == 0) {
|
||||
KeQuerySystemTime(&gMonitorStartTime);
|
||||
gMonitorStartCounter = KeQueryPerformanceCounter(&gPerformanceFrequency);
|
||||
}
|
||||
|
||||
LARGE_INTEGER Time;
|
||||
LARGE_INTEGER CounterNow = KeQueryPerformanceCounter(NULL);
|
||||
LONGLONG CounterOff = CounterNow.QuadPart - gMonitorStartCounter.QuadPart;
|
||||
|
||||
Time.QuadPart = gMonitorStartTime.QuadPart +
|
||||
(10000000 * (CounterOff / gPerformanceFrequency.QuadPart)) +
|
||||
((10000000 * (CounterOff % gPerformanceFrequency.QuadPart)) / gPerformanceFrequency.QuadPart);
|
||||
|
||||
return Time;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 2004-2020 Sandboxie Holdings, LLC
|
||||
* Copyright 2020 David Xanatos, xanasoft.com
|
||||
* Copyright 2020-2023 David Xanatos, xanasoft.com
|
||||
*
|
||||
* 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
|
||||
|
@ -110,6 +110,8 @@ NTSTATUS MyValidateCertificate(void);
|
|||
HANDLE Util_GetProcessPidByName(const WCHAR* name);
|
||||
|
||||
|
||||
LARGE_INTEGER Util_GetTimestamp(void);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
|
||||
bool CFinder::m_DarkMode = false;
|
||||
|
||||
QWidget* CFinder::AddFinder(QWidget* pList, QObject* pFilterTarget, int iOptions, CFinder** ppFinder)
|
||||
QWidget* CFinder::AddFinder(QTreeView* pTree, QObject* pFilterTarget, int iOptions, CFinder** ppFinder)
|
||||
{
|
||||
QWidget* pWidget = new QWidget();
|
||||
QVBoxLayout* pLayout = new QVBoxLayout();
|
||||
pLayout->setContentsMargins(0,0,0,0);
|
||||
pWidget->setLayout(pLayout);
|
||||
|
||||
pLayout->addWidget(pList);
|
||||
pLayout->addWidget(pTree);
|
||||
CFinder* pFinder = new CFinder(pFilterTarget, pWidget, iOptions);
|
||||
pFinder->SetTree(pTree);
|
||||
pLayout->addWidget(pFinder);
|
||||
|
||||
if (ppFinder)
|
||||
|
@ -52,9 +53,10 @@ CFinder::CFinder(QObject* pFilterTarget, QWidget *parent, int iOptions)
|
|||
else
|
||||
m_pRegExp = NULL;
|
||||
|
||||
m_pSortProxy = qobject_cast<QSortFilterProxyModel*>(pFilterTarget);
|
||||
m_pTree = NULL;
|
||||
m_pModel = qobject_cast<QAbstractProxyModel*>(pFilterTarget);
|
||||
|
||||
if (m_pSortProxy) {
|
||||
if (m_pModel) {
|
||||
m_pColumn = new QComboBox();
|
||||
m_pSearchLayout->addWidget(m_pColumn);
|
||||
connect(m_pColumn, SIGNAL(currentIndexChanged(int)), this, SLOT(OnUpdate()));
|
||||
|
@ -66,7 +68,8 @@ CFinder::CFinder(QObject* pFilterTarget, QWidget *parent, int iOptions)
|
|||
if ((iOptions & eHighLight) != 0)
|
||||
{
|
||||
m_pHighLight = new QCheckBox(tr("Highlight"));
|
||||
//m_pHighLight->setChecked(true);
|
||||
if ((iOptions & eHighLightDefault) == eHighLightDefault)
|
||||
m_pHighLight->setChecked(true);
|
||||
m_pSearchLayout->addWidget(m_pHighLight);
|
||||
connect(m_pHighLight, SIGNAL(stateChanged(int)), this, SLOT(OnUpdate()));
|
||||
}
|
||||
|
@ -103,7 +106,7 @@ CFinder::CFinder(QObject* pFilterTarget, QWidget *parent, int iOptions)
|
|||
|
||||
if (pFilterTarget) {
|
||||
QObject::connect(this, SIGNAL(SetFilter(const QString&, int, int)), pFilterTarget, SLOT(SetFilter(const QString&, int, int)));
|
||||
QObject::connect(this, SIGNAL(SelectNext()), pFilterTarget, SLOT(SelectNext()));
|
||||
//QObject::connect(this, SIGNAL(SelectNext()), pFilterTarget, SLOT(SelectNext()));
|
||||
}
|
||||
|
||||
m_pTimer = new QTimer(this);
|
||||
|
@ -118,6 +121,12 @@ CFinder::~CFinder()
|
|||
{
|
||||
}
|
||||
|
||||
void CFinder::SetTree(QTreeView* pTree)
|
||||
{
|
||||
m_pTree = pTree;
|
||||
QObject::connect(this, SIGNAL(SelectNext()), this, SLOT(OnSelectNext()));
|
||||
}
|
||||
|
||||
bool CFinder::eventFilter(QObject* source, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress && ((QKeyEvent*)event)->key() == Qt::Key_Escape
|
||||
|
@ -132,11 +141,11 @@ bool CFinder::eventFilter(QObject* source, QEvent* event)
|
|||
|
||||
void CFinder::Open()
|
||||
{
|
||||
if (m_pSortProxy && m_pColumn->count() == 0)
|
||||
if (m_pModel && m_pColumn->count() == 0)
|
||||
{
|
||||
m_pColumn->addItem(tr("All columns"), -1);
|
||||
for (int i = 0; i < m_pSortProxy->columnCount(); i++)
|
||||
m_pColumn->addItem(m_pSortProxy->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(), i);
|
||||
for (int i = 0; i < m_pModel->columnCount(); i++)
|
||||
m_pColumn->addItem(m_pModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(), i);
|
||||
m_pColumn->setVisible(true);
|
||||
}
|
||||
|
||||
|
@ -158,7 +167,12 @@ void CFinder::OnUpdate()
|
|||
iOptions |= eCaseSens;
|
||||
if (GetHighLight())
|
||||
iOptions |= eHighLight;
|
||||
SetFilter(m_pSearch->text(), iOptions, GetColumn());
|
||||
QString Exp = m_pSearch->text();
|
||||
|
||||
QString ExpStr = ((iOptions & CFinder::eRegExp) == 0) ? Exp : (".*" + QRegularExpression::escape(Exp) + ".*");
|
||||
m_RegExp = QRegularExpression(ExpStr, (iOptions & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
SetFilter(Exp, iOptions, GetColumn());
|
||||
}
|
||||
|
||||
void CFinder::OnText()
|
||||
|
@ -178,4 +192,126 @@ void CFinder::Close()
|
|||
{
|
||||
emit SetFilter(QString());
|
||||
hide();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
bool CFinder::MatchString(const QString& value)
|
||||
{
|
||||
return value.contains(m_RegExp);
|
||||
}
|
||||
|
||||
bool CFinder::MatchCell(QModelIndex idx, int column)
|
||||
{
|
||||
QModelIndex tmp = idx.sibling(idx.row(), column);
|
||||
|
||||
QString str = m_pModel->data(tmp, Qt::DisplayRole).toString();
|
||||
return MatchString(str);
|
||||
}
|
||||
|
||||
bool CFinder::MatchRow(QModelIndex idx)
|
||||
{
|
||||
int iColumn = GetColumn();
|
||||
if (iColumn != -1)
|
||||
return MatchCell(idx, iColumn);
|
||||
|
||||
for(int col = 0; col < m_pModel->columnCount(idx); col++) {
|
||||
if (MatchCell(idx, col))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex CFinder::FindNext(QModelIndex idx, bool next, int depth)
|
||||
{
|
||||
if (MatchRow(idx) && !next)
|
||||
return idx;
|
||||
//Q_ASSERT(depth < 100);
|
||||
|
||||
if (m_pModel->hasChildren(idx))
|
||||
{
|
||||
int numRows = m_pModel->rowCount(idx);
|
||||
for (int count = 0; count < numRows; count++) {
|
||||
QModelIndex tmp = FindNext(m_pModel->index(count, 0, idx), false, depth + 1);
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
QModelIndex par = m_pModel->parent(idx);
|
||||
if (!par.isValid() && depth > 0)
|
||||
break;
|
||||
|
||||
int numRows = m_pModel->rowCount(par);
|
||||
for (int count = idx.row() + 1; count < numRows; count++) {
|
||||
QModelIndex tmp = FindNext(m_pModel->index(count, 0, par), false, depth + 1);
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (!par.isValid())
|
||||
break;
|
||||
idx = par;
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CFinder::FindPrev(QModelIndex idx, bool next, int depth)
|
||||
{
|
||||
if (MatchRow(idx) && !next)
|
||||
return idx;
|
||||
//Q_ASSERT(depth < 100);
|
||||
|
||||
if (m_pModel->hasChildren(idx))
|
||||
{
|
||||
int numRows = m_pModel->rowCount(idx);
|
||||
for (int count = numRows-1; count >= 0; count++) {
|
||||
QModelIndex tmp = FindNext(m_pModel->index(count, 0, idx), false, depth + 1);
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
QModelIndex par = m_pModel->parent(idx);
|
||||
if (!par.isValid() && depth > 0)
|
||||
break;
|
||||
|
||||
int numRows = m_pModel->rowCount(par);
|
||||
for (int count = idx.row() - 1; count >= 0; count--) {
|
||||
QModelIndex tmp = FindNext(m_pModel->index(count, 0, par), false, depth + 1);
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (!par.isValid())
|
||||
break;
|
||||
idx = par;
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void CFinder::OnSelectNext()
|
||||
{
|
||||
bool next = true;
|
||||
QModelIndex idx = m_pTree->currentIndex();
|
||||
if (!(next = idx.isValid()))
|
||||
idx = m_pModel->index(0, 0);
|
||||
|
||||
//if (QApplication::keyboardModifiers() & Qt::ControlModifier)
|
||||
if (QApplication::keyboardModifiers() & Qt::ShiftModifier)
|
||||
idx = FindPrev(idx, next);
|
||||
else
|
||||
idx = FindNext(idx, next);
|
||||
|
||||
if (idx.isValid())
|
||||
m_pTree->setCurrentIndex(idx);
|
||||
else
|
||||
QApplication::beep();
|
||||
}
|
|
@ -10,21 +10,21 @@ public:
|
|||
CFinder(QObject* pFilterTarget, QWidget *parent = NULL, int iOptions = eRegExp | eCaseSens | eHighLight);
|
||||
~CFinder();
|
||||
|
||||
void SetTree(QTreeView* pTree);
|
||||
|
||||
static void SetDarkMode(bool bDarkMode) { m_DarkMode = bDarkMode; }
|
||||
static bool GetDarkMode() { return m_DarkMode; }
|
||||
|
||||
static QWidget* AddFinder(QWidget* pList, QObject* pFilterTarget, int iOptions = eRegExp | eCaseSens | eHighLight, CFinder** ppFinder = NULL);
|
||||
static QWidget* AddFinder(QTreeView* pTree, QObject* pFilterTarget, int iOptions = eRegExp | eCaseSens | eHighLight, CFinder** ppFinder = NULL);
|
||||
|
||||
bool GetCaseSensitive() const { return m_pCaseSensitive ? m_pCaseSensitive->isChecked() : false; }
|
||||
bool GetRegExp() const { return m_pRegExp ? m_pRegExp->isChecked() : false; }
|
||||
bool GetHighLight() const { return m_pHighLight ? m_pHighLight->isChecked() : false; }
|
||||
int GetColumn() const { return m_pColumn ? m_pColumn->currentData().toInt() : -1; }
|
||||
QRegularExpression GetSearchExp() const { return m_RegExp; }
|
||||
|
||||
enum EOptions
|
||||
{
|
||||
eRegExp = 0x01,
|
||||
eCaseSens = 0x02,
|
||||
eHighLight = 0x04,
|
||||
eHighLightDefault = eHighLight | 0x08,
|
||||
};
|
||||
|
||||
signals:
|
||||
|
@ -40,9 +40,22 @@ private slots:
|
|||
void OnText();
|
||||
void OnReturn();
|
||||
|
||||
void OnSelectNext();
|
||||
|
||||
protected:
|
||||
bool GetCaseSensitive() const { return m_pCaseSensitive ? m_pCaseSensitive->isChecked() : false; }
|
||||
bool GetRegExp() const { return m_pRegExp ? m_pRegExp->isChecked() : false; }
|
||||
bool GetHighLight() const { return m_pHighLight ? m_pHighLight->isChecked() : false; }
|
||||
int GetColumn() const { return m_pColumn ? m_pColumn->currentData().toInt() : -1; }
|
||||
|
||||
bool eventFilter(QObject* source, QEvent* event);
|
||||
|
||||
virtual bool MatchString(const QString& value);
|
||||
bool MatchCell(QModelIndex idx, int column);
|
||||
bool MatchRow(QModelIndex idx);
|
||||
QModelIndex FindNext(QModelIndex idx, bool next = false, int depth = 0);
|
||||
QModelIndex FindPrev(QModelIndex idx, bool next = false, int depth = 0);
|
||||
|
||||
private:
|
||||
|
||||
QHBoxLayout* m_pSearchLayout;
|
||||
|
@ -53,7 +66,10 @@ private:
|
|||
QComboBox* m_pColumn;
|
||||
QCheckBox* m_pHighLight;
|
||||
|
||||
QSortFilterProxyModel* m_pSortProxy;
|
||||
QRegularExpression m_RegExp;
|
||||
|
||||
QTreeView* m_pTree;
|
||||
QAbstractProxyModel*m_pModel;
|
||||
|
||||
QTimer* m_pTimer;
|
||||
|
||||
|
|
|
@ -136,10 +136,10 @@ public:
|
|||
}
|
||||
|
||||
private slots:
|
||||
void SetFilter(const QString& Exp, int iFormat, int Col = -1) // -1 = any
|
||||
void SetFilter(const QString& Exp, int iOptions, int Col = -1) // -1 = any
|
||||
{
|
||||
QString ExpStr = ((iFormat & CFinder::eRegExp) == 0) ? Exp : (".*" + QRegularExpression::escape(Exp) + ".*");
|
||||
QRegularExpression RegExp(ExpStr, (iFormat & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
QString ExpStr = ((iOptions & CFinder::eRegExp) == 0) ? Exp : (".*" + QRegularExpression::escape(Exp) + ".*");
|
||||
QRegularExpression RegExp(ExpStr, (iOptions & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
ApplyFilter(m_pTreeList, RegExp);
|
||||
}
|
||||
|
||||
|
@ -164,8 +164,6 @@ public:
|
|||
m_pSortProxy->setDynamicSortFilter(true);
|
||||
|
||||
m_pTreeList->setModel(m_pSortProxy);
|
||||
((CSortFilterProxyModel*)m_pSortProxy)->setView(m_pTreeList);
|
||||
|
||||
|
||||
m_pTreeList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -14,16 +14,10 @@ public:
|
|||
{
|
||||
m_bHighLight = false;
|
||||
m_iColumn = 0;
|
||||
m_pView = NULL;
|
||||
|
||||
this->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void setView(QTreeView* pView)
|
||||
{
|
||||
m_pView = pView;
|
||||
}
|
||||
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
|
||||
{
|
||||
if (m_bHighLight)
|
||||
|
@ -86,124 +80,16 @@ public slots:
|
|||
QRegularExpression RegExp(ExpStr, (iOptions & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
QModelIndex idx;
|
||||
//if (m_pView) idx = m_pView->currentIndex();
|
||||
m_iColumn = Col;
|
||||
m_bHighLight = (iOptions & CFinder::eHighLight) != 0;
|
||||
setFilterKeyColumn(Col);
|
||||
setFilterRegularExpression(RegExp);
|
||||
//if (m_pView) m_pView->setCurrentIndex(idx);
|
||||
if (m_bHighLight)
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void SelectNext()
|
||||
{
|
||||
if (!m_pView)
|
||||
return;
|
||||
|
||||
bool next = true;
|
||||
QModelIndex idx = m_pView->currentIndex();
|
||||
if (!(next = idx.isValid()))
|
||||
idx = index(0, 0);
|
||||
|
||||
//if (QApplication::keyboardModifiers() & Qt::ControlModifier)
|
||||
if (QApplication::keyboardModifiers() & Qt::ShiftModifier)
|
||||
idx = FindPrev(idx, next);
|
||||
else
|
||||
idx = FindNext(idx, next);
|
||||
|
||||
if (idx.isValid())
|
||||
m_pView->setCurrentIndex(idx);
|
||||
else
|
||||
QApplication::beep();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_bHighLight;
|
||||
int m_iColumn;
|
||||
QTreeView* m_pView;
|
||||
|
||||
bool MatchCell(QModelIndex idx, int column)
|
||||
{
|
||||
QModelIndex tmp = idx.sibling(idx.row(), column);
|
||||
|
||||
QString str = data(tmp, filterRole()).toString();
|
||||
if (str.contains(filterRegularExpression()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MatchRow(QModelIndex idx)
|
||||
{
|
||||
if (m_iColumn != -1)
|
||||
return MatchCell(idx, m_iColumn);
|
||||
|
||||
for(int col = 0; col < columnCount(idx); col++) {
|
||||
if (MatchCell(idx, col))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex FindNext(QModelIndex idx, bool next = false)
|
||||
{
|
||||
if (MatchRow(idx) && !next)
|
||||
return idx;
|
||||
|
||||
if (hasChildren(idx))
|
||||
{
|
||||
int numRows = rowCount(idx);
|
||||
for (int count = 0; count < numRows; count++) {
|
||||
QModelIndex tmp = FindNext(index(count, 0, idx));
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
QModelIndex par = parent(idx);
|
||||
|
||||
int numRows = rowCount(par);
|
||||
for (int count = idx.row() + 1; count < numRows; count++) {
|
||||
QModelIndex tmp = FindNext(index(count, 0, par));
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
|
||||
idx = par;
|
||||
} while (idx.isValid());
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex FindPrev(QModelIndex idx, bool next = false)
|
||||
{
|
||||
if (MatchRow(idx) && !next)
|
||||
return idx;
|
||||
|
||||
if (hasChildren(idx))
|
||||
{
|
||||
int numRows = rowCount(idx);
|
||||
for (int count = numRows-1; count >= 0; count++) {
|
||||
QModelIndex tmp = FindNext(index(count, 0, idx));
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
QModelIndex par = parent(idx);
|
||||
|
||||
int numRows = rowCount(par);
|
||||
for (int count = idx.row() - 1; count >= 0; count--) {
|
||||
QModelIndex tmp = FindNext(index(count, 0, par));
|
||||
if (tmp.isValid())
|
||||
return tmp;
|
||||
}
|
||||
|
||||
idx = par;
|
||||
} while (idx.isValid());
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2533,7 +2533,7 @@ bool CSbieAPI::GetMonitor()
|
|||
pos += (len + 1) * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(pid, tid, type, LogData));
|
||||
CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(0, pid, tid, type, LogData));
|
||||
|
||||
QMutexLocker Lock(&m_TraceMutex);
|
||||
m_TraceCache.append(LogEntry);
|
||||
|
@ -2570,6 +2570,10 @@ bool CSbieAPI::GetMonitor()
|
|||
ULONG uSize = *(ULONG*)ptr;
|
||||
ptr += sizeof(ULONG);
|
||||
|
||||
LONGLONG uTimestamp = *(LONGLONG*)ptr;
|
||||
ptr += sizeof(LONGLONG);
|
||||
uSize -= sizeof(LONGLONG);
|
||||
|
||||
ULONG uType = *(ULONG*)ptr;
|
||||
ptr += sizeof(ULONG);
|
||||
uSize -= sizeof(ULONG);
|
||||
|
@ -2590,7 +2594,7 @@ bool CSbieAPI::GetMonitor()
|
|||
}
|
||||
ptr += uSize;
|
||||
|
||||
CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(uPid, uTid, uType, LogData));
|
||||
CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(FILETIME2ms(uTimestamp), uPid, uTid, uType, LogData));
|
||||
|
||||
QMutexLocker Lock(&m_TraceMutex);
|
||||
m_TraceCache.append(LogEntry);
|
||||
|
|
|
@ -60,7 +60,7 @@ QString ErrorString(qint32 err)
|
|||
return Error;
|
||||
}
|
||||
|
||||
CTraceEntry::CTraceEntry(quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData)
|
||||
CTraceEntry::CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData)
|
||||
{
|
||||
m_ProcessId = ProcessId;
|
||||
m_ThreadId = ThreadId;
|
||||
|
@ -69,7 +69,7 @@ CTraceEntry::CTraceEntry(quint32 ProcessId, quint32 ThreadId, quint32 Type, cons
|
|||
m_SubType = LogData.length() > 2 ? LogData.at(2) : QString();
|
||||
m_Type.Flags = Type;
|
||||
|
||||
m_TimeStamp = QDateTime::currentDateTime(); // ms resolution
|
||||
m_TimeStamp = Timestamp ? Timestamp : QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
|
||||
m_BoxPtr = 0;
|
||||
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
class QSBIEAPI_EXPORT CTraceEntry : public QSharedData
|
||||
{
|
||||
public:
|
||||
CTraceEntry(quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData);
|
||||
CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData);
|
||||
|
||||
virtual QString GetName() const { return m_Name; }
|
||||
virtual QString GetMessage() const { return m_Message; }
|
||||
virtual quint32 GetProcessId() const { return m_ProcessId; }
|
||||
virtual quint32 GetThreadId() const { return m_ThreadId; }
|
||||
virtual QDateTime GetTimeStamp() const { return m_TimeStamp; }
|
||||
virtual quint64 GetTimeStamp() const { return m_TimeStamp; }
|
||||
|
||||
virtual quint8 GetType() const { return m_Type.Type; }
|
||||
static QList<quint32>AllTypes();
|
||||
|
@ -72,7 +72,7 @@ protected:
|
|||
QString m_SubType;
|
||||
quint32 m_ProcessId;
|
||||
quint32 m_ThreadId;
|
||||
QDateTime m_TimeStamp;
|
||||
quint64 m_TimeStamp;
|
||||
QString m_ProcessName;
|
||||
void* m_BoxPtr;
|
||||
|
||||
|
|
|
@ -144,6 +144,17 @@ void CTraceModel::FreeNode(STreeNode* pNode)
|
|||
//delete pNode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
QVariant CTraceModel::NodeData(STreeNode* pNode, int role, int section) const
|
||||
{
|
||||
const CTraceEntryPtr& pEntry = pNode->pEntry;
|
||||
|
@ -183,9 +194,10 @@ QVariant CTraceModel::NodeData(STreeNode* pNode, int role, int section) const
|
|||
if(!m_bTree) {
|
||||
QString Name = pEntry->GetProcessName();
|
||||
return 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"));
|
||||
.arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId())
|
||||
.arg(QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz"));
|
||||
} else
|
||||
return pEntry->GetTimeStamp().toString("hh:mm:ss.zzz");
|
||||
return QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz");
|
||||
}
|
||||
case eType: return pEntry->GetTypeStr();
|
||||
case eStatus: return pEntry->GetStautsStr();
|
||||
|
@ -198,6 +210,18 @@ QVariant CTraceModel::NodeData(STreeNode* pNode, int role, int section) const
|
|||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
|
|
@ -15,6 +15,8 @@ public:
|
|||
void SetTree(bool bTree) { m_bTree = bTree; }
|
||||
bool IsTree() const { return m_bTree; }
|
||||
|
||||
void SetHighLight(const QString& Exp) { m_HighLightExp = Exp; }
|
||||
|
||||
QList<QModelIndex> Sync(const QVector<CTraceEntryPtr>& EntryList);
|
||||
|
||||
CTraceEntryPtr GetEntry(const QModelIndex& index) const;
|
||||
|
@ -96,5 +98,9 @@ protected:
|
|||
STreeNode* m_Root;
|
||||
QHash<quint64, STreeNode*> m_Branches;
|
||||
|
||||
QString m_HighLightExp;
|
||||
|
||||
bool TestHighLight(STreeNode* pNode) const;
|
||||
|
||||
static PoolAllocator<sizeof(STreeNode)> m_NodeAllocator;
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
|
|||
|
||||
//m_UserConfigChanged = false;
|
||||
|
||||
m_pSbieModel = new CSbieModel();
|
||||
m_pSbieModel = new CSbieModel(this);
|
||||
m_pSbieModel->SetTree(true);
|
||||
m_pSbieModel->SetUseIcons(true);
|
||||
|
||||
|
@ -50,7 +50,6 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
|
|||
m_pSbieModel->SetLargeIcons();
|
||||
m_pSbieTree->setIconSize(QSize(32, 32));
|
||||
}
|
||||
((CSortFilterProxyModel*)m_pSortProxy)->setView(m_pSbieTree);
|
||||
|
||||
m_pSbieTree->setDragDropMode(QAbstractItemView::InternalMove);
|
||||
|
||||
|
@ -82,7 +81,9 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
|
|||
m_pMainLayout->addWidget(m_pSbieTree);
|
||||
//
|
||||
|
||||
m_pMainLayout->addWidget(new CFinder(m_pSortProxy, this));
|
||||
CFinder* pFinder = new CFinder(m_pSortProxy, this);
|
||||
m_pMainLayout->addWidget(pFinder);
|
||||
pFinder->SetTree(m_pSbieTree);
|
||||
|
||||
|
||||
connect(m_pSbieModel, SIGNAL(ToolTipCallback(const QVariant&, QString&)), this, SLOT(OnToolTipCallback(const QVariant&, QString&)), Qt::DirectConnection);
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
CTraceTree::CTraceTree(QWidget* parent)
|
||||
: CPanelWidget<QTreeViewEx>(parent)
|
||||
{
|
||||
m_bHighLight = false;
|
||||
//m_FilterCol = -1;
|
||||
|
||||
m_pTreeList->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false));
|
||||
|
||||
m_pTreeList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
|
@ -83,7 +86,8 @@ CTraceTree::CTraceTree(QWidget* parent)
|
|||
//connect(m_pBoxTree, SIGNAL(ColumnChanged(int, bool)), this, SLOT(OnColumnsChanged()));
|
||||
|
||||
//m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, m_pSortProxy));
|
||||
m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, this, CFinder::eHighLight));
|
||||
m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, this, CFinder::eHighLightDefault));
|
||||
//QObject::connect(pFinder, SIGNAL(SelectNext()), this, SLOT(SelectNext()));
|
||||
|
||||
|
||||
QByteArray Columns = theConf->GetBlob("MainWindow/TraceLog_Columns");
|
||||
|
@ -98,6 +102,23 @@ CTraceTree::~CTraceTree()
|
|||
theConf->SetBlob("MainWindow/TraceLog_Columns", GetView()->header()->saveState());
|
||||
}
|
||||
|
||||
void CTraceTree::SetFilter(const QString& Exp, int iOptions, int Column)
|
||||
{
|
||||
bool bReset = m_FilterExp != Exp || m_bHighLight != ((iOptions & CFinder::eHighLight) != 0);
|
||||
|
||||
//QString ExpStr = ((iOptions & CFinder::eRegExp) == 0) ? Exp : (".*" + QRegularExpression::escape(Exp) + ".*");
|
||||
//QRegularExpression RegExp(ExpStr, (iOptions & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
//m_FilterExp = RegExp;
|
||||
m_FilterExp = Exp;
|
||||
m_bHighLight = (iOptions & CFinder::eHighLight) != 0;
|
||||
//m_FilterCol = Col;
|
||||
|
||||
if(bReset)
|
||||
emit FilterChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CMonitorList
|
||||
|
||||
|
@ -117,8 +138,6 @@ CMonitorList::CMonitorList(QWidget* parent)
|
|||
m_pSortProxy->setDynamicSortFilter(true);
|
||||
|
||||
m_pTreeList->setModel(m_pSortProxy);
|
||||
m_pSortProxy->setView(m_pTreeList);
|
||||
|
||||
|
||||
QStyle* pStyle = QStyleFactory::create("windows");
|
||||
m_pTreeList->setStyle(pStyle);
|
||||
|
@ -163,8 +182,6 @@ CTraceView::CTraceView(bool bStandAlone, QWidget* parent) : QWidget(parent)
|
|||
m_LastCount = 0;
|
||||
m_bUpdatePending = false;
|
||||
|
||||
m_bHighLight = false;
|
||||
//m_FilterCol = -1;
|
||||
m_FilterPid = 0;
|
||||
m_FilterTid = 0;
|
||||
m_FilterStatus = 0;
|
||||
|
@ -177,7 +194,7 @@ CTraceView::CTraceView(bool bStandAlone, QWidget* parent) : QWidget(parent)
|
|||
|
||||
m_pMonitorMode = m_pTraceToolBar->addAction(CSandMan::GetIcon("Monitor"), tr("Monitor mode"), this, SLOT(OnSetMode()));
|
||||
m_pMonitorMode->setCheckable(true);
|
||||
m_pMonitorMode->setChecked(theConf->GetBool("Options/UseMonitorMode"));
|
||||
m_pMonitorMode->setChecked(theConf->GetBool("Options/UseMonitorMode", true));
|
||||
|
||||
m_pTraceTree = m_pTraceToolBar->addAction(CSandMan::GetIcon("Tree"), tr("Show as task tree"), this, SLOT(OnSetTree()));
|
||||
m_pTraceTree->setCheckable(true);
|
||||
|
@ -258,7 +275,7 @@ CTraceView::CTraceView(bool bStandAlone, QWidget* parent) : QWidget(parent)
|
|||
|
||||
m_pLayout->addWidget(m_pTrace);
|
||||
|
||||
QObject::connect(m_pTrace, SIGNAL(FilterSet(const QString&, int, int)), this, SLOT(SetFilter(const QString&, int, int)));
|
||||
QObject::connect(m_pTrace, SIGNAL(FilterChanged()), this, SLOT(OnFilterChanged()));
|
||||
|
||||
m_pMonitor = new CMonitorList(this);
|
||||
m_pMonitor->m_pMonitorModel->SetObjTree(m_pObjectTree->isChecked());
|
||||
|
@ -335,8 +352,8 @@ void CTraceView::Refresh()
|
|||
if (m_LastCount == ResourceLog.count())
|
||||
return;
|
||||
|
||||
//bool bHasFilter = !m_FilterExp.pattern().isEmpty();
|
||||
bool bHasFilter = !m_FilterExp.isEmpty();
|
||||
//bool bHasFilter = !m_pTrace->m_FilterExp.pattern().isEmpty();
|
||||
bool bHasFilter = !m_pTrace->m_FilterExp.isEmpty();
|
||||
|
||||
quint64 start = GetCurCycle();
|
||||
for (; i < ResourceLog.count(); i++)
|
||||
|
@ -381,12 +398,12 @@ void CTraceView::Refresh()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (bHasFilter && !m_bHighLight) {
|
||||
if (!pEntry->GetName().contains(m_FilterExp)
|
||||
&& !pEntry->GetMessage().contains(m_FilterExp)
|
||||
//&& !pEntry->GetTypeStr().contains(m_FilterExp) // dont filter on non static strings !!!
|
||||
//&& !pEntry->GetStautsStr().contains(m_FilterExp) // dont filter on non static strings !!!
|
||||
&& !pEntry->GetProcessName().contains(m_FilterExp))
|
||||
if (bHasFilter && !m_pTrace->m_bHighLight) {
|
||||
if (!pEntry->GetName().contains(m_pTrace->m_FilterExp)
|
||||
&& !pEntry->GetMessage().contains(m_pTrace->m_FilterExp)
|
||||
//&& !pEntry->GetTypeStr().contains(m_pTrace->m_FilterExp) // dont filter on non static strings !!!
|
||||
//&& !pEntry->GetStautsStr().contains(m_pTrace->m_FilterExp) // dont filter on non static strings !!!
|
||||
&& !pEntry->GetProcessName().contains(m_pTrace->m_FilterExp))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -434,6 +451,11 @@ void CTraceView::Refresh()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (m_pTrace->m_bHighLight)
|
||||
m_pTrace->m_pTraceModel->SetHighLight(m_pTrace->m_FilterExp);
|
||||
else
|
||||
m_pTrace->m_pTraceModel->SetHighLight(QString());
|
||||
|
||||
quint64 start = GetCurCycle();
|
||||
QList<QModelIndex> NewBranches = m_pTrace->m_pTraceModel->Sync(m_TraceList);
|
||||
qDebug() << "Sync took" << (GetCurCycle() - start) / 1000000.0 << "s";
|
||||
|
@ -538,15 +560,8 @@ void CTraceView::UpdateFilters()
|
|||
}
|
||||
}
|
||||
|
||||
void CTraceView::SetFilter(const QString& Exp, int iOptions, int Col)
|
||||
void CTraceView::OnFilterChanged()
|
||||
{
|
||||
//QString ExpStr = ((iOptions & CFinder::eRegExp) == 0) ? Exp : (".*" + QRegularExpression::escape(Exp) + ".*");
|
||||
//QRegularExpression RegExp(ExpStr, (iOptions & CFinder::eCaseSens) != 0 ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
|
||||
//m_FilterExp = RegExp;
|
||||
m_FilterExp = Exp;
|
||||
m_bHighLight = (iOptions & CFinder::eHighLight) != 0;
|
||||
//m_FilterCol = Col;
|
||||
|
||||
m_FullRefresh = true;
|
||||
}
|
||||
|
||||
|
@ -626,7 +641,7 @@ void CTraceView::SaveToFile()
|
|||
const CTraceEntryPtr& pEntry = ResourceLog.at(i);
|
||||
|
||||
QStringList Line;
|
||||
Line.append(pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"));
|
||||
Line.append(QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz"));
|
||||
QString Name = pEntry->GetProcessName();
|
||||
Line.append(Name.isEmpty() ? tr("Unknown") : Name);
|
||||
Line.append(QString("%1").arg(pEntry->GetProcessId()));
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "../Models/SbieModel.h"
|
||||
#include "../Models/TraceModel.h"
|
||||
#include "../Models/MonitorModel.h"
|
||||
#include "../../MiscHelpers/Common/SortFilterProxyModel.h"
|
||||
|
||||
class CTraceFilterProxyModel;
|
||||
|
||||
class CTraceTree : public CPanelWidget<QTreeViewEx>
|
||||
{
|
||||
|
@ -19,13 +19,20 @@ public:
|
|||
CTraceModel* m_pTraceModel;
|
||||
|
||||
public slots:
|
||||
void SetFilter(const QString& Exp, int iOptions = 0, int Column = -1) {
|
||||
emit FilterSet(Exp, iOptions, Column);
|
||||
}
|
||||
void SelectNext() {}
|
||||
void SetFilter(const QString& Exp, int iOptions = 0, int Column = -1);
|
||||
|
||||
signals:
|
||||
void FilterSet(const QString& Exp, int iOptions = 0, int Column = -1);
|
||||
void FilterChanged();
|
||||
|
||||
protected:
|
||||
friend class CTraceView;
|
||||
|
||||
QString GetFilterExp() const { return m_FilterExp; }
|
||||
|
||||
//QRegularExpression m_FilterExp;
|
||||
QString m_FilterExp;
|
||||
bool m_bHighLight;
|
||||
//int m_FilterCol;
|
||||
};
|
||||
|
||||
class CMonitorList : public CPanelWidget<QTreeViewEx>
|
||||
|
@ -61,7 +68,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void UpdateFilters();
|
||||
void SetFilter(const QString& Exp, int iOptions = 0, int Col = -1); // -1 = any
|
||||
void OnFilterChanged();
|
||||
|
||||
void SaveToFile();
|
||||
|
||||
|
@ -85,10 +92,6 @@ protected:
|
|||
protected:
|
||||
bool m_FullRefresh;
|
||||
|
||||
//QRegularExpression m_FilterExp;
|
||||
QString m_FilterExp;
|
||||
bool m_bHighLight;
|
||||
//int m_FilterCol;
|
||||
quint32 m_FilterPid;
|
||||
quint32 m_FilterTid;
|
||||
QList<quint32> m_FilterTypes;
|
||||
|
|
|
@ -65,7 +65,7 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, bool bImmediate, QWidg
|
|||
|
||||
ui.btnDeleteAll->setVisible(false);
|
||||
|
||||
m_pFileModel = new CSimpleTreeModel();
|
||||
m_pFileModel = new CSimpleTreeModel(this);
|
||||
m_pFileModel->SetUseIcons(true);
|
||||
m_pFileModel->AddColumn(tr("File Name"), "FileName");
|
||||
m_pFileModel->AddColumn(tr("File Size"), "FileSize");
|
||||
|
@ -79,13 +79,14 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, bool bImmediate, QWidg
|
|||
//ui.treeFiles->setItemDelegate(theGUI->GetItemDelegate());
|
||||
|
||||
ui.treeFiles->setModel(m_pSortProxy);
|
||||
((CSortFilterProxyModel*)m_pSortProxy)->setView(ui.treeFiles);
|
||||
|
||||
ui.treeFiles->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
ui.treeFiles->setSortingEnabled(true);
|
||||
//ui.treeFiles->setUniformRowHeights(true);
|
||||
|
||||
ui.gridLayout->addWidget(new CFinder(m_pSortProxy, this, true), 3, 0, 1, 5);
|
||||
CFinder* pFinder = new CFinder(m_pSortProxy, this);
|
||||
ui.gridLayout->addWidget(pFinder, 3, 0, 1, 5);
|
||||
pFinder->SetTree(ui.treeFiles);
|
||||
ui.finder->deleteLater(); // remove place holder
|
||||
|
||||
//connect(ui.treeFiles, SIGNAL(clicked(const QModelIndex&)), this, SLOT(UpdateSnapshot(const QModelIndex&)));
|
||||
|
|
|
@ -34,7 +34,7 @@ CSnapshotsWindow::CSnapshotsWindow(const CSandBoxPtr& pBox, QWidget *parent)
|
|||
ui.treeSnapshots->setItemDelegate(new CTreeItemDelegate());
|
||||
ui.treeSnapshots->setExpandsOnDoubleClick(false);
|
||||
|
||||
m_pSnapshotModel = new CSimpleTreeModel();
|
||||
m_pSnapshotModel = new CSimpleTreeModel(this);
|
||||
m_pSnapshotModel->AddColumn(tr("Snapshot"), "Name");
|
||||
|
||||
/*m_pSortProxy = new CSortFilterProxyModel(this);
|
||||
|
|
Loading…
Reference in New Issue