diff --git a/include/profiler/serialized_block.h b/include/profiler/serialized_block.h index 01f45a3..9e6f592 100644 --- a/include/profiler/serialized_block.h +++ b/include/profiler/serialized_block.h @@ -69,6 +69,11 @@ namespace profiler { return name() + m_nameLength; } + inline void setEnabled(bool _enabled) + { + m_enabled = _enabled; + } + private: SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete; diff --git a/profiler_gui/CMakeLists.txt b/profiler_gui/CMakeLists.txt index 279a02b..e236347 100644 --- a/profiler_gui/CMakeLists.txt +++ b/profiler_gui/CMakeLists.txt @@ -16,6 +16,8 @@ add_executable(${PROJECT_NAME} blocks_graphics_view.cpp blocks_tree_widget.h blocks_tree_widget.cpp + descriptors_tree_widget.h + descriptors_tree_widget.cpp easy_chronometer_item.h easy_chronometer_item.cpp easy_graphics_item.h diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index cb93ea2..89c9313 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -50,12 +50,16 @@ #include "tree_widget_item.h" #include "globals.h" -#ifdef max -#undef max -#endif - -#ifdef min -#undef min +#ifdef _WIN32 +#include +#endif + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min #endif ////////////////////////////////////////////////////////////////////////// @@ -332,6 +336,11 @@ void EasyTreeWidget::clearSilent(bool _global) for (auto item : _items) delete item; }, ::std::move(topLevelItems)); + +#ifdef _WIN32 + SetThreadPriority(deleter_thread.native_handle(), THREAD_PRIORITY_LOWEST); +#endif + deleter_thread.detach(); //clear(); @@ -395,11 +404,6 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (item != nullptr && item->parent() != nullptr) { - //auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index); - //itemAction->setToolTip("Scroll graphics scene to current item in the tree"); - //connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked); - //menu.addAction(itemAction); - if (col >= 0) { switch (col) @@ -437,6 +441,19 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) } } } + + auto id = item->block().node->id(); + action = menu.addAction("Block enabled"); + action->setCheckable(true); + action->setChecked(easyDescriptor(id).enabled()); + action->setData(id); + connect(action, &QAction::triggered, this, &This::onBlockEnableDisable); + + if (action->isChecked()) { + auto f = action->font(); + f.setBold(true); + action->setFont(f); + } } menu.addSeparator(); @@ -562,6 +579,19 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool) ////////////////////////////////////////////////////////////////////////// +void EasyTreeWidget::onBlockEnableDisable(bool _checked) +{ + auto action = qobject_cast(sender()); + if (action != nullptr) + { + auto id = action->data().toUInt(); + easyDescriptor(id).setEnabled(_checked); + emit EASY_GLOBALS.events.enableStatusChanged(id, _checked); + } +} + +////////////////////////////////////////////////////////////////////////// + void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item) { if (!EASY_GLOBALS.bind_scene_and_tree_expand_status) @@ -640,7 +670,7 @@ void EasyTreeWidget::onSelectedThreadChange(::profiler::thread_id_t _id) } } -void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index) +void EasyTreeWidget::onSelectedBlockChange(uint32_t _block_index) { disconnect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange); diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index dd2ba85..187a436 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -106,7 +106,9 @@ private slots: void onSelectedThreadChange(::profiler::thread_id_t _id); - void onSelectedBlockChange(unsigned int _block_index); + void onSelectedBlockChange(uint32_t _block_index); + + void onBlockEnableDisable(bool _checked); void resizeColumnsToContents(); diff --git a/profiler_gui/descriptors_tree_widget.cpp b/profiler_gui/descriptors_tree_widget.cpp new file mode 100644 index 0000000..0559926 --- /dev/null +++ b/profiler_gui/descriptors_tree_widget.cpp @@ -0,0 +1,309 @@ +/************************************************************************ +* file name : descriptors_tree_widget.cpp +* ----------------- : +* creation time : 2016/09/17 +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of EasyDescWidget and it's auxiliary classes +* : for displyaing EasyProfiler blocks descriptors tree. +* ----------------- : +* change log : * 2016/09/17 Victor Zarubkin: initial commit. +* : +* : * +* ----------------- : +* license : Lightweight profiler library for c++ +* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin +* : +* : 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 +* : the Free Software Foundation, either version 3 of the License, or +* : (at your option) any later version. +* : +* : This program is distributed in the hope that it will be useful, +* : but WITHOUT ANY WARRANTY; without even the implied warranty of +* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +* : GNU General Public License for more details. +* : +* : You should have received a copy of the GNU General Public License +* : along with this program.If not, see . +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "descriptors_tree_widget.h" +#include "globals.h" +#include "../src/hashed_cstr.h" + +#ifdef _WIN32 +#include +#endif + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +////////////////////////////////////////////////////////////////////////// + +enum DescColumns +{ + DESC_COL_FILE_LINE = 0, + DESC_COL_NAME, + DESC_COL_STATUS, + + DESC_COL_COLUMNS_NUMBER +}; + +const auto ENABLED_COLOR = ::profiler::colors::LightGreen900; +const auto DISABLED_COLOR = ::profiler::colors::DarkRed; + +////////////////////////////////////////////////////////////////////////// + +EasyDescWidgetItem::EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent) : Parent(_parent), m_desc(_desc) +{ + +} + +EasyDescWidgetItem::~EasyDescWidgetItem() +{ + +} + +bool EasyDescWidgetItem::operator < (const Parent& _other) const +{ + const auto col = treeWidget()->sortColumn(); + + switch (col) + { + case DESC_COL_FILE_LINE: + { + if (parent() != nullptr) + return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt(); + } + } + + return Parent::operator < (_other); +} + +////////////////////////////////////////////////////////////////////////// + +EasyDescWidget::EasyDescWidget(QWidget* _parent) + : Parent(_parent) +{ + setAutoFillBackground(false); + setAlternatingRowColors(true); + setItemsExpandable(true); + setAnimated(true); + setSortingEnabled(false); + setColumnCount(DESC_COL_COLUMNS_NUMBER); + + auto header_item = new QTreeWidgetItem(); + header_item->setText(DESC_COL_FILE_LINE, "File/Line"); + header_item->setText(DESC_COL_NAME, "Name"); + header_item->setText(DESC_COL_STATUS, "Status"); + setHeaderItem(header_item); + + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + connect(this, &Parent::itemDoubleClicked, this, &This::onDoubleClick); + + loadSettings(); +} + +EasyDescWidget::~EasyDescWidget() +{ + saveSettings(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::clearSilent(bool) +{ + const QSignalBlocker b(this); + + setSortingEnabled(false); + + ::std::vector topLevelItems; + topLevelItems.reserve(topLevelItemCount()); + for (int i = topLevelItemCount() - 1; i >= 0; --i) + topLevelItems.push_back(takeTopLevelItem(i)); + + auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) { + for (auto item : _items) + delete item; + }, ::std::move(topLevelItems)); + +#ifdef _WIN32 + SetThreadPriority(deleter_thread.native_handle(), THREAD_PRIORITY_LOWEST); +#endif + + deleter_thread.detach(); + + //clear(); +} + +////////////////////////////////////////////////////////////////////////// + +struct FileItems +{ + typedef ::std::unordered_map::hasher_t> Items; + Items children; + QTreeWidgetItem* item = nullptr; +}; + +void EasyDescWidget::build() +{ + clearSilent(false); + + auto f = header()->font(); + f.setBold(true); + + typedef ::std::unordered_map<::std::string, FileItems> Files; + Files m_files; + + const QSignalBlocker b(this); + ::profiler::block_id_t id = 0; + for (auto desc : EASY_GLOBALS.descriptors) + { + if (desc != nullptr) + { + auto& p = m_files[desc->file()]; + if (p.item == nullptr) + { + p.item = new QTreeWidgetItem(); + p.item->setText(DESC_COL_FILE_LINE, desc->file()); + } + + auto it = p.children.find(desc->line()); + if (it == p.children.end()) + { + auto item = new EasyDescWidgetItem(id, p.item); + item->setText(DESC_COL_FILE_LINE, QString::number(desc->line())); + item->setData(DESC_COL_FILE_LINE, Qt::UserRole, desc->line()); + if (*desc->name() != 0) + item->setText(DESC_COL_NAME, desc->name()); + + item->setFont(DESC_COL_STATUS, f); + + QBrush brush; + if (desc->enabled()) + { + item->setText(DESC_COL_STATUS, "ON"); + brush.setColor(QColor::fromRgba(ENABLED_COLOR)); + } + else + { + item->setText(DESC_COL_STATUS, "OFF"); + brush.setColor(QColor::fromRgba(DISABLED_COLOR)); + } + + item->setForeground(DESC_COL_STATUS, brush); + } + } + + ++id; + } + + for (auto& p : m_files) + { + addTopLevelItem(p.second.item); + } + + setSortingEnabled(true); + sortByColumn(DESC_COL_FILE_LINE, Qt::AscendingOrder); + resizeColumnsToContents(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::onItemExpand(QTreeWidgetItem*) +{ + resizeColumnsToContents(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::onDoubleClick(QTreeWidgetItem* _item, int _column) +{ + if (_column >= DESC_COL_NAME && _item->parent() != nullptr) + { + auto item = static_cast(_item); + auto& desc = easyDescriptor(item->desc()); + + QBrush brush; + if (desc.enabled()) + { + desc.setEnabled(false); + item->setText(DESC_COL_STATUS, "OFF"); + brush.setColor(QColor::fromRgba(DISABLED_COLOR)); + } + else + { + desc.setEnabled(true); + item->setText(DESC_COL_STATUS, "ON"); + brush.setColor(QColor::fromRgba(ENABLED_COLOR)); + } + + item->setForeground(DESC_COL_STATUS, brush); + emit EASY_GLOBALS.events.enableStatusChanged(item->desc(), desc.enabled()); + } +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::resizeColumnsToContents() +{ + for (int i = 0; i < DESC_COL_COLUMNS_NUMBER; ++i) + { + resizeColumnToContents(i); + } +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::contextMenuEvent(QContextMenuEvent* _event) +{ + _event->accept(); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::onSelectedBlockChange(uint32_t _block_index) +{ + +} + +////////////////////////////////////////////////////////////////////////// + +void EasyDescWidget::loadSettings() +{ + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("desc_tree_widget"); + + // ... + + settings.endGroup(); +} + +void EasyDescWidget::saveSettings() +{ + QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); + settings.beginGroup("desc_tree_widget"); + + // ... + + settings.endGroup(); +} + +////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/descriptors_tree_widget.h b/profiler_gui/descriptors_tree_widget.h new file mode 100644 index 0000000..dab0290 --- /dev/null +++ b/profiler_gui/descriptors_tree_widget.h @@ -0,0 +1,108 @@ +/************************************************************************ +* file name : descriptors_tree_widget.h +* ----------------- : +* creation time : 2016/09/17 +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains declaration of EasyDescWidget and it's auxiliary classes +* : for displyaing EasyProfiler blocks descriptors tree. +* ----------------- : +* change log : * 2016/09/17 Victor Zarubkin: initial commit. +* : +* : * +* ----------------- : +* license : Lightweight profiler library for c++ +* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin +* : +* : 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 +* : the Free Software Foundation, either version 3 of the License, or +* : (at your option) any later version. +* : +* : This program is distributed in the hope that it will be useful, +* : but WITHOUT ANY WARRANTY; without even the implied warranty of +* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +* : GNU General Public License for more details. +* : +* : You should have received a copy of the GNU General Public License +* : along with this program.If not, see . +************************************************************************/ + +#ifndef EASY__DESCRIPTORS__WIDGET__H_ +#define EASY__DESCRIPTORS__WIDGET__H_ + +#include +#include "profiler/reader.h" + +////////////////////////////////////////////////////////////////////////// + +class EasyDescWidgetItem : public QTreeWidgetItem +{ + typedef QTreeWidgetItem Parent; + typedef EasyDescWidgetItem This; + + ::profiler::block_id_t m_desc; + +public: + + explicit EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent = nullptr); + virtual ~EasyDescWidgetItem(); + + bool operator < (const Parent& _other) const override; + +public: + + // Public inline methods + + inline ::profiler::block_id_t desc() const + { + return m_desc; + } + +}; // END of class EasyDescWidgetItem. + +////////////////////////////////////////////////////////////////////////// + +class EasyDescWidget : public QTreeWidget +{ + Q_OBJECT + + typedef QTreeWidget Parent; + typedef EasyDescWidget This; + +protected: + + + +public: + + explicit EasyDescWidget(QWidget* _parent = nullptr); + virtual ~EasyDescWidget(); + +public slots: + + void clearSilent(bool _global = false); + void build(); + +protected: + + void contextMenuEvent(QContextMenuEvent* _event) override; + +private slots: + + void onItemExpand(QTreeWidgetItem* _item); + void onDoubleClick(QTreeWidgetItem* _item, int _column); + void onSelectedBlockChange(uint32_t _block_index); + void resizeColumnsToContents(); + +protected: + + void loadSettings(); + void saveSettings(); + +}; // END of class EasyDescWidget. + +////////////////////////////////////////////////////////////////////////// + +#endif // EASY__DESCRIPTORS__WIDGET__H_ diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index ccf2010..fd4fc72 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -48,10 +48,11 @@ namespace profiler_gui { signals: void selectedThreadChanged(::profiler::thread_id_t _id); - void selectedBlockChanged(unsigned int _block_index); + void selectedBlockChanged(uint32_t _block_index); void itemsExpandStateChanged(); void drawBordersChanged(); void chronoPositionChanged(); + void enableStatusChanged(::profiler::block_id_t _id, bool _enabled); }; // END of class EasyGlobalSignals. diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 5e08488..81d22e2 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -49,9 +49,12 @@ #include #include #include +#include +#include #include "main_window.h" #include "blocks_tree_widget.h" #include "blocks_graphics_view.h" +#include "descriptors_tree_widget.h" #include "globals.h" ////////////////////////////////////////////////////////////////////////// @@ -60,7 +63,7 @@ const int LOADER_TIMER_INTERVAL = 40; ////////////////////////////////////////////////////////////////////////// -EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr) +EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr), m_editBlocksAction(nullptr) { { QIcon icon(":/logo"); if (!icon.isNull()) QApplication::setWindowIcon(icon); } @@ -173,8 +176,17 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsVi + menu = new QMenu("&Edit"); + action = menu->addAction("Edit blocks"); + action->setEnabled(false); + connect(action, &QAction::triggered, this, &This::onEditBlocksClicked); + m_editBlocksAction = action; + menuBar()->addMenu(menu); + + + menu = new QMenu("&Settings"); - action = new QAction("Statistics enabled", nullptr); + action = menu->addAction("Statistics enabled"); action->setCheckable(true); action->setChecked(EASY_GLOBALS.enable_statistics); connect(action, &QAction::triggered, this, &This::onEnableDisableStatistics); @@ -368,6 +380,24 @@ void EasyMainWindow::onCollapseAllClicked(bool) ////////////////////////////////////////////////////////////////////////// +void EasyMainWindow::onEditBlocksClicked(bool) +{ + QDialog d(this); + d.setWindowTitle("EasyProfiler"); + d.resize(800, 600); + + auto descTree = new EasyDescWidget(); + descTree->build(); + + auto l = new QVBoxLayout(&d); + l->addWidget(descTree); + + d.setLayout(l); + d.exec(); +} + +////////////////////////////////////////////////////////////////////////// + void EasyMainWindow::closeEvent(QCloseEvent* close_event) { saveSettingsAndGeometry(); @@ -503,6 +533,8 @@ void EasyMainWindow::onFileReaderTimeout() } static_cast(m_graphicsView->widget())->view()->setTree(EASY_GLOBALS.profiler_blocks); + + m_editBlocksAction->setEnabled(true); } else { diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 6ad19bf..25197c9 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -89,6 +89,7 @@ protected: QDockWidget* m_treeWidget; QDockWidget* m_graphicsView; class QProgressDialog* m_progress; + class QAction* m_editBlocksAction; QTimer m_readerTimer; ::profiler::SerializedData m_serializedBlocks; ::profiler::SerializedData m_serializedDescriptors; @@ -96,7 +97,7 @@ protected: public: - EasyMainWindow(); + explicit EasyMainWindow(); virtual ~EasyMainWindow(); // Public virtual methods @@ -119,6 +120,7 @@ protected slots: void onCollapseAllClicked(bool); void onFileReaderTimeout(); void onFileReaderCancel(); + void onEditBlocksClicked(bool); private: