0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 00:21:11 +08:00

(GUI) Added search box into Hierarchy window;

(GUI) Added new option for building hierarchy for selected thread only (for memory economy)
This commit is contained in:
Victor Zarubkin 2016-11-20 21:01:33 +03:00
parent a08b986418
commit 92b2b27a3b
10 changed files with 392 additions and 18 deletions

View File

@ -857,7 +857,8 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
for (auto item : m_items)
{
item->getBlocks(m_chronometerItem->left(), m_chronometerItem->right(), m_selectedBlocks);
if (!EASY_GLOBALS.only_current_thread_hierarchy || item->threadId() == EASY_GLOBALS.selected_thread)
item->getBlocks(m_chronometerItem->left(), m_chronometerItem->right(), m_selectedBlocks);
}
if (!m_selectedBlocks.empty())
@ -1183,9 +1184,10 @@ void EasyGraphicsView::initMode()
connect(&m_idleTimer, &QTimer::timeout, this, &This::onIdleTimeout);
auto globalSignals = &EASY_GLOBALS.events;
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::hierarchyFlagChanged, this, &This::onHierarchyFlagChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsExpandStateChange);
}
//////////////////////////////////////////////////////////////////////////
@ -1373,6 +1375,36 @@ void EasyGraphicsView::onIdleTimeout()
//////////////////////////////////////////////////////////////////////////
void EasyGraphicsView::onHierarchyFlagChange(bool)
{
bool changedSelection = false;
if (!m_selectedBlocks.empty())
{
changedSelection = true;
m_selectedBlocks.clear();
}
if (m_chronometerItem->isVisible())
{
for (auto item : m_items)
{
if (!EASY_GLOBALS.only_current_thread_hierarchy || item->threadId() == EASY_GLOBALS.selected_thread)
item->getBlocks(m_chronometerItem->left(), m_chronometerItem->right(), m_selectedBlocks);
}
if (!m_selectedBlocks.empty())
{
changedSelection = true;
}
}
if (changedSelection)
{
emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_chronometerItem->reverse());
}
}
void EasyGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id)
{
if (m_pScrollbar == nullptr || m_pScrollbar->minimapThread() == _id)
@ -1391,6 +1423,29 @@ void EasyGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id)
if (item->threadId() == _id)
{
m_pScrollbar->setMinimapFrom(_id, item->items(0));
bool changedSelection = false;
if (EASY_GLOBALS.only_current_thread_hierarchy)
{
if (!m_selectedBlocks.empty())
{
changedSelection = true;
m_selectedBlocks.clear();
}
if (m_chronometerItem->isVisible())
{
item->getBlocks(m_chronometerItem->left(), m_chronometerItem->right(), m_selectedBlocks);
if (!m_selectedBlocks.empty())
changedSelection = true;
}
}
if (changedSelection)
{
emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_chronometerItem->reverse());
}
repaintScene();
return;
}
@ -1429,7 +1484,7 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index)
//////////////////////////////////////////////////////////////////////////
void EasyGraphicsView::onItemsEspandStateChange()
void EasyGraphicsView::onItemsExpandStateChange()
{
if (!m_bUpdatingRect)
{

View File

@ -196,9 +196,10 @@ private slots:
void onGraphicsScrollbarValueChange(qreal);
void onFlickerTimeout();
void onIdleTimeout();
void onHierarchyFlagChange(bool _value);
void onSelectedThreadChange(::profiler::thread_id_t _id);
void onSelectedBlockChange(unsigned int _block_index);
void onItemsEspandStateChange();
void onItemsExpandStateChange();
public:

View File

@ -60,6 +60,11 @@
#include <QProgressDialog>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QLineEdit>
#include <QLabel>
#include <QToolBar>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDebug>
#include "blocks_tree_widget.h"
#include "tree_widget_item.h"
@ -86,6 +91,7 @@ const int HIERARCHY_BUILDER_TIMER_INTERVAL = 40;
EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
: Parent(_parent)
, m_beginTime(::std::numeric_limits<decltype(m_beginTime)>::max())
, m_lastFound(nullptr)
, m_progress(nullptr)
, m_bColorRows(true)
, m_bLocked(false)
@ -324,6 +330,8 @@ void EasyTreeWidget::clearSilent(bool _global)
disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand);
disconnect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
disconnect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
m_lastFound = nullptr;
m_lastSearch.clear();
if (!_global)
{
@ -366,6 +374,104 @@ void EasyTreeWidget::clearSilent(bool _global)
//////////////////////////////////////////////////////////////////////////
int EasyTreeWidget::findNext(const QString& _str)
{
if (m_bLocked || _str.isEmpty())
return 0;
const bool isNewSearch = (m_lastSearch != _str);
auto itemsList = findItems(_str, Qt::MatchContains | Qt::MatchRecursive, COL_NAME);
if (!isNewSearch)
{
if (!itemsList.empty())
{
bool stop = false;
decltype(m_lastFound) next = nullptr;
for (auto item : itemsList)
{
if (item->parent() == nullptr)
continue;
if (stop)
{
next = item;
break;
}
stop = item == m_lastFound;
}
m_lastFound = next == nullptr ? itemsList.front() : next;
}
else
{
m_lastFound = nullptr;
}
}
else
{
m_lastSearch = _str;
m_lastFound = !itemsList.empty() ? itemsList.front() : nullptr;
}
if (m_lastFound != nullptr)
{
scrollToItem(m_lastFound, QAbstractItemView::PositionAtCenter);
setCurrentItem(m_lastFound);
}
return itemsList.size();
}
int EasyTreeWidget::findPrev(const QString& _str)
{
if (m_bLocked || _str.isEmpty())
return 0;
const bool isNewSearch = (m_lastSearch != _str);
auto itemsList = findItems(_str, Qt::MatchContains | Qt::MatchRecursive, COL_NAME);
if (!isNewSearch)
{
if (!itemsList.empty())
{
decltype(m_lastFound) prev = nullptr;
for (auto item : itemsList)
{
if (item->parent() == nullptr)
continue;
if (item == m_lastFound)
break;
prev = item;
}
m_lastFound = prev == nullptr ? itemsList.back() : prev;
}
else
{
m_lastFound = nullptr;
}
}
else
{
m_lastSearch = _str;
m_lastFound = !itemsList.empty() ? itemsList.front() : nullptr;
}
if (m_lastFound != nullptr)
{
scrollToItem(m_lastFound, QAbstractItemView::PositionAtCenter);
setCurrentItem(m_lastFound);
}
return itemsList.size();
}
//////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
{
if (m_bLocked)
@ -813,3 +919,147 @@ void EasyTreeWidget::saveSettings()
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
EasyHierarchyWidget::EasyHierarchyWidget(QWidget* _parent) : Parent(_parent)
, m_tree(new EasyTreeWidget(this))
, m_searchBox(new QLineEdit(this))
, m_foundNumber(new QLabel("Found 0 matches", this))
, m_searchButton(nullptr)
{
m_searchBox->setFixedWidth(200);
m_searchBox->setContentsMargins(5, 0, 0, 0);
QMenu* menu = new QMenu(this);
m_searchButton = menu->menuAction();
m_searchButton->setText("Find next");
m_searchButton->setIcon(QIcon(":/Search-next"));
m_searchButton->setData(true);
connect(m_searchButton, &QAction::triggered, this, &This::findNext);
auto actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true);
auto a = new QAction(tr("Find next"), actionGroup);
a->setCheckable(true);
a->setChecked(true);
connect(a, &QAction::triggered, this, &This::findNextFromMenu);
menu->addAction(a);
a = new QAction(tr("Find previous"), actionGroup);
a->setCheckable(true);
connect(a, &QAction::triggered, this, &This::findPrevFromMenu);
menu->addAction(a);
auto tb = new QToolBar(this);
tb->addAction(m_searchButton);
tb->addWidget(m_searchBox);
auto searchbox = new QHBoxLayout();
searchbox->setContentsMargins(0, 0, 5, 0);
searchbox->addWidget(tb);
searchbox->addStretch(100);
searchbox->addWidget(m_foundNumber, Qt::AlignRight);
auto lay = new QVBoxLayout(this);
lay->setContentsMargins(1, 1, 1, 1);
lay->addLayout(searchbox);
lay->addWidget(m_tree);
connect(m_searchBox, &QLineEdit::returnPressed, this, &This::onSeachBoxReturnPressed);
}
EasyHierarchyWidget::~EasyHierarchyWidget()
{
}
void EasyHierarchyWidget::keyPressEvent(QKeyEvent* _event)
{
if (_event->key() == Qt::Key_F3)
{
if (_event->modifiers() & Qt::ShiftModifier)
findPrev(true);
else
findNext(true);
}
_event->accept();
}
EasyTreeWidget* EasyHierarchyWidget::tree()
{
return m_tree;
}
void EasyHierarchyWidget::clear(bool _global)
{
m_tree->clearSilent(_global);
m_foundNumber->setText(QString("Found 0 matches"));
}
void EasyHierarchyWidget::onSeachBoxReturnPressed()
{
auto matches = m_tree->findNext(m_searchBox->text());
if (matches == 1)
m_foundNumber->setText(QString("Found 1 match"));
else
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
}
void EasyHierarchyWidget::findNext(bool)
{
auto matches = m_tree->findNext(m_searchBox->text());
if (matches == 1)
m_foundNumber->setText(QString("Found 1 match"));
else
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
}
void EasyHierarchyWidget::findPrev(bool)
{
auto matches = m_tree->findPrev(m_searchBox->text());
if (matches == 1)
m_foundNumber->setText(QString("Found 1 match"));
else
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
}
void EasyHierarchyWidget::findNextFromMenu(bool _checked)
{
if (!_checked)
return;
if (m_searchButton->data().toBool() == false)
{
m_searchButton->setData(true);
m_searchButton->setText(tr("Find next"));
m_searchButton->setIcon(QIcon(":/Search-next"));
disconnect(m_searchButton, &QAction::triggered, this, &This::findPrev);
connect(m_searchButton, &QAction::triggered, this, &This::findNext);
}
findNext(true);
}
void EasyHierarchyWidget::findPrevFromMenu(bool _checked)
{
if (!_checked)
return;
if (m_searchButton->data().toBool() == true)
{
m_searchButton->setData(false);
m_searchButton->setText(tr("Find prev"));
m_searchButton->setIcon(QIcon(":/Search-prev"));
disconnect(m_searchButton, &QAction::triggered, this, &This::findNext);
connect(m_searchButton, &QAction::triggered, this, &This::findPrev);
}
findPrev(true);
}
//////////////////////////////////////////////////////////////////////////

View File

@ -74,6 +74,8 @@ protected:
RootsMap m_roots;
::profiler_gui::TreeBlocks m_inputBlocks;
QTimer m_fillTimer;
QString m_lastSearch;
QTreeWidgetItem* m_lastFound;
::profiler::timestamp_t m_beginTime;
class QProgressDialog* m_progress;
bool m_bColorRows;
@ -86,6 +88,8 @@ public:
virtual ~EasyTreeWidget();
void clearSilent(bool _global = false);
int findNext(const QString& _str);
int findPrev(const QString& _str);
public slots:
@ -137,6 +141,48 @@ protected:
}; // END of class EasyTreeWidget.
//////////////////////////////////////////////////////////////////////////
class EasyHierarchyWidget : public QWidget
{
Q_OBJECT
typedef QWidget Parent;
typedef EasyHierarchyWidget This;
private:
EasyTreeWidget* m_tree;
class QLineEdit* m_searchBox;
class QLabel* m_foundNumber;
class QAction* m_searchButton;
public:
// Public virtual methods
explicit EasyHierarchyWidget(QWidget* _parent = nullptr);
virtual ~EasyHierarchyWidget();
void keyPressEvent(QKeyEvent* _event) override;
public:
// Public non-virtual methods
EasyTreeWidget* tree();
void clear(bool _global = false);
private slots:
void onSeachBoxReturnPressed();
void findNext(bool);
void findPrev(bool);
void findNextFromMenu(bool);
void findPrevFromMenu(bool);
}; // END of class EasyHierarchyWidget.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET__H_

View File

@ -713,15 +713,15 @@ int EasyDescTreeWidget::findPrev(const QString& _str)
//////////////////////////////////////////////////////////////////////////
EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
, m_tree(new EasyDescTreeWidget())
, m_searchBox(new QLineEdit())
, m_foundNumber(new QLabel("Found 0 matches"))
, m_tree(new EasyDescTreeWidget(this))
, m_searchBox(new QLineEdit(this))
, m_foundNumber(new QLabel("Found 0 matches", this))
, m_searchButton(nullptr)
{
m_searchBox->setFixedWidth(200);
m_searchBox->setContentsMargins(5, 0, 0, 0);
auto tb = new QToolBar();
auto tb = new QToolBar(this);
auto refreshButton = tb->addAction(QIcon(":/Reload"), tr("Refresh blocks list"));
refreshButton->setEnabled(EASY_GLOBALS.connected);
refreshButton->setToolTip(tr("Refresh blocks list.\nConnection needed."));
@ -755,7 +755,7 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
tb->addWidget(m_searchBox);
auto searchbox = new QHBoxLayout();
searchbox->setContentsMargins(0, 0, 0, 0);
searchbox->setContentsMargins(0, 0, 5, 0);
searchbox->addWidget(tb);
searchbox->addStretch(100);
searchbox->addWidget(m_foundNumber, Qt::AlignRight);

View File

@ -73,6 +73,7 @@ namespace profiler_gui {
, display_only_relevant_stats(true)
, collapse_items_on_tree_close(false)
, all_items_expanded_by_default(true)
, only_current_thread_hierarchy(false)
, bind_scene_and_tree_expand_status(true)
{

View File

@ -123,6 +123,7 @@ namespace profiler_gui {
bool display_only_relevant_stats; ///< Display only relevant information in ProfTreeWidget (excludes min, max, average times if there are only 1 calls number)
bool collapse_items_on_tree_close; ///< Collapse all items which were displayed in the hierarchy tree after tree close/reset
bool all_items_expanded_by_default; ///< Expand all items after file is opened
bool only_current_thread_hierarchy; ///< Build hierarchy tree for current thread only
bool bind_scene_and_tree_expand_status; /** \brief If true then items on graphics scene and in the tree (blocks hierarchy) are binded on each other
so expanding/collapsing items on scene also expands/collapse items in the tree. */

View File

@ -54,6 +54,7 @@ namespace profiler_gui {
void connectionChanged(bool _connected);
void blocksRefreshRequired(bool);
void timelineMarkerChanged();
void hierarchyFlagChanged(bool);
}; // END of class EasyGlobalSignals.

View File

@ -129,18 +129,20 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastP
setStatusBar(new QStatusBar());
auto graphicsView = new EasyGraphicsViewWidget();
m_graphicsView = new QDockWidget("Diagram");
m_graphicsView = new QDockWidget("Diagram", this);
m_graphicsView->setObjectName("ProfilerGUI_Diagram");
m_graphicsView->setMinimumHeight(50);
m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas);
auto graphicsView = new EasyGraphicsViewWidget(this);
m_graphicsView->setWidget(graphicsView);
auto treeWidget = new EasyTreeWidget();
m_treeWidget = new QDockWidget("Hierarchy");
m_treeWidget = new QDockWidget("Hierarchy", this);
m_treeWidget->setObjectName("ProfilerGUI_Hierarchy");
m_treeWidget->setMinimumHeight(50);
m_treeWidget->setAllowedAreas(Qt::AllDockWidgetAreas);
auto treeWidget = new EasyHierarchyWidget(this);
m_treeWidget->setWidget(treeWidget);
addDockWidget(Qt::TopDockWidgetArea, m_graphicsView);
@ -254,6 +256,11 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastP
action->setChecked(EASY_GLOBALS.hide_narrow_children);
connect(action, &QAction::triggered, this, &This::onHideNarrowChildrenChanged);
action = submenu->addAction("Build hierarchy only for current thread");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.only_current_thread_hierarchy);
connect(action, &QAction::triggered, this, &This::onHierarchyFlagChange);
action = submenu->addAction("Collapse items on tree reset");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.collapse_items_on_tree_close);
@ -405,7 +412,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastP
toolbar->addWidget(lbl);
connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget, &EasyTreeWidget::setTreeBlocks);
connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget->tree(), &EasyTreeWidget::setTreeBlocks);
connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout);
connect(&m_listenerTimer, &QTimer::timeout, this, &This::onListenerTimerTimeout);
@ -577,7 +584,7 @@ void EasyMainWindow::onSaveFileClicked(bool)
void EasyMainWindow::clear()
{
static_cast<EasyTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
static_cast<EasyHierarchyWidget*>(m_treeWidget->widget())->clear(true);
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->clear();
#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
@ -689,6 +696,12 @@ void EasyMainWindow::onBindExpandStatusChange(bool _checked)
EASY_GLOBALS.bind_scene_and_tree_expand_status = _checked;
}
void EasyMainWindow::onHierarchyFlagChange(bool _checked)
{
EASY_GLOBALS.only_current_thread_hierarchy = _checked;
emit EASY_GLOBALS.events.hierarchyFlagChanged(_checked);
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::onExpandAllClicked(bool)
@ -698,7 +711,7 @@ void EasyMainWindow::onExpandAllClicked(bool)
emit EASY_GLOBALS.events.itemsExpandStateChanged();
auto tree = static_cast<EasyTreeWidget*>(m_treeWidget->widget());
auto tree = static_cast<EasyHierarchyWidget*>(m_treeWidget->widget())->tree();
const QSignalBlocker b(tree);
tree->expandAll();
}
@ -710,7 +723,7 @@ void EasyMainWindow::onCollapseAllClicked(bool)
emit EASY_GLOBALS.events.itemsExpandStateChanged();
auto tree = static_cast<EasyTreeWidget*>(m_treeWidget->widget());
auto tree = static_cast<EasyHierarchyWidget*>(m_treeWidget->widget())->tree();
const QSignalBlocker b(tree);
tree->collapseAll();
}
@ -841,6 +854,10 @@ void EasyMainWindow::loadSettings()
if (!flag.isNull())
EASY_GLOBALS.all_items_expanded_by_default = flag.toBool();
flag = settings.value("only_current_thread_hierarchy");
if (!flag.isNull())
EASY_GLOBALS.only_current_thread_hierarchy = flag.toBool();
flag = settings.value("bind_scene_and_tree_expand_status");
if (!flag.isNull())
EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool();
@ -896,6 +913,7 @@ void EasyMainWindow::saveSettingsAndGeometry()
settings.setValue("hide_narrow_children", EASY_GLOBALS.hide_narrow_children);
settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close);
settings.setValue("all_items_expanded_by_default", EASY_GLOBALS.all_items_expanded_by_default);
settings.setValue("only_current_thread_hierarchy", EASY_GLOBALS.only_current_thread_hierarchy);
settings.setValue("bind_scene_and_tree_expand_status", EASY_GLOBALS.bind_scene_and_tree_expand_status);
settings.setValue("enable_event_indicators", EASY_GLOBALS.enable_event_indicators);
settings.setValue("enable_statistics", EASY_GLOBALS.enable_statistics);
@ -979,7 +997,7 @@ void EasyMainWindow::onFileReaderTimeout()
auto nblocks = m_reader.size();
if (nblocks != 0)
{
static_cast<EasyTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
static_cast<EasyHierarchyWidget*>(m_treeWidget->widget())->clear(true);
::profiler::SerializedData serialized_blocks;
::profiler::SerializedData serialized_descriptors;

View File

@ -237,6 +237,7 @@ protected slots:
void onCollapseItemsAfterCloseChanged(bool);
void onAllItemsExpandedByDefaultChange(bool);
void onBindExpandStatusChange(bool);
void onHierarchyFlagChange(bool);
void onExpandAllClicked(bool);
void onCollapseAllClicked(bool);
void onSpacingChange(int _value);