diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 90c6023..a173483 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -897,11 +897,11 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (!m_items.empty()) { - action = menu.addAction("Expand all"); + action = menu.addAction("Expand All"); connect(action, &QAction::triggered, this, &This::onExpandAllClicked); action->setIcon(QIcon(imagePath("expand"))); - action = menu.addAction("Collapse all"); + action = menu.addAction("Collapse All"); connect(action, &QAction::triggered, this, &This::onCollapseAllClicked); action->setIcon(QIcon(imagePath("collapse"))); @@ -909,11 +909,11 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) { menu.addSeparator(); - action = menu.addAction("Expand all children"); + action = menu.addAction("Expand All Children"); connect(action, &QAction::triggered, this, &This::onExpandAllChildrenClicked); action->setIcon(QIcon(imagePath("expand"))); - action = menu.addAction("Collapse all children"); + action = menu.addAction("Collapse All Children"); connect(action, &QAction::triggered, this, &This::onCollapseAllChildrenClicked); action->setIcon(QIcon(imagePath("collapse"))); } @@ -924,21 +924,21 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) auto actionGroup = new QActionGroup(&menu); actionGroup->setExclusive(true); - auto actionHierarchy = new QAction("Call-stack", actionGroup); + auto actionHierarchy = new QAction("Call-Stack", actionGroup); actionHierarchy->setCheckable(true); actionHierarchy->setChecked(m_mode == TreeMode::Full); - actionHierarchy->setToolTip("Display full call stack"); + actionHierarchy->setToolTip("Display Full Call Stack"); actionHierarchy->setData((quint32)TreeMode::Full); menu.addAction(actionHierarchy); - auto actionPlain = new QAction("Per-frame stats", actionGroup); + auto actionPlain = new QAction("Per-Frame Stats", actionGroup); actionPlain->setCheckable(true); actionPlain->setChecked(m_mode == TreeMode::Plain); actionPlain->setToolTip("Display plain list of blocks per frame.\nSome columns are disabled with this mode."); actionPlain->setData((quint32)TreeMode::Plain); menu.addAction(actionPlain); - auto actionSelectedArea = new QAction("Aggregate stats", actionGroup); + auto actionSelectedArea = new QAction("Aggregate Stats", actionGroup); actionSelectedArea->setCheckable(true); actionSelectedArea->setChecked(m_mode == TreeMode::SelectedArea); actionSelectedArea->setToolTip("Display aggregate stats for selected area.\nSome columns are disabled with this mode."); @@ -968,17 +968,19 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) { auto& block = item->block(); auto i = profiler_gui::numeric_max(); + QString name; switch (col) { - case COL_MIN_PER_THREAD: i = block.per_thread_stats->min_duration_block; break; - case COL_MIN_PER_PARENT: i = block.per_parent_stats->min_duration_block; break; - case COL_MIN_PER_FRAME: i = block.per_frame_stats->min_duration_block; break; - case COL_MAX_PER_THREAD: i = block.per_thread_stats->max_duration_block; break; - case COL_MAX_PER_PARENT: i = block.per_parent_stats->max_duration_block; break; - case COL_MAX_PER_FRAME: i = block.per_frame_stats->max_duration_block; break; + case COL_MIN_PER_THREAD: name = QStringLiteral("Min"); i = block.per_thread_stats->min_duration_block; break; + case COL_MIN_PER_PARENT: name = QStringLiteral("Min"); i = block.per_parent_stats->min_duration_block; break; + case COL_MIN_PER_FRAME: name = QStringLiteral("Min"); i = block.per_frame_stats->min_duration_block; break; + case COL_MAX_PER_THREAD: name = QStringLiteral("Max"); i = block.per_thread_stats->max_duration_block; break; + case COL_MAX_PER_PARENT: name = QStringLiteral("Max"); i = block.per_parent_stats->max_duration_block; break; + case COL_MAX_PER_FRAME: name = QStringLiteral("Max"); i = block.per_frame_stats->max_duration_block; break; case COL_MIN_PER_AREA: { + name = QStringLiteral("Min"); auto data = item->data(COL_MIN_PER_AREA, MinMaxBlockIndexRole); if (!data.isNull()) i = data.toUInt(); @@ -987,6 +989,7 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) case COL_MAX_PER_AREA: { + name = QStringLiteral("Max"); auto data = item->data(COL_MAX_PER_AREA, MinMaxBlockIndexRole); if (!data.isNull()) i = data.toUInt(); @@ -997,9 +1000,9 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (i != profiler_gui::numeric_max(i)) { menu.addSeparator(); - auto itemAction = new QAction("Jump to such item", nullptr); + auto itemAction = new QAction(QString("Jump To %1 Item").arg(name), nullptr); itemAction->setData(i); - itemAction->setToolTip("Jump to item with min/max duration (depending on clicked column)"); + itemAction->setToolTip(QString("Jump to item with %1 duration").arg(name.toLower())); connect(itemAction, &QAction::triggered, this, &This::onJumpToItemClicked); menu.addAction(itemAction); } @@ -1013,7 +1016,7 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) } const auto& desc = easyDescriptor(item->block().node->id()); - auto submenu = menu.addMenu("Block status"); + auto submenu = menu.addMenu("Block Status"); submenu->setToolTipsVisible(true); #define ADD_STATUS_ACTION(NameValue, StatusValue, ToolTipValue)\ @@ -1037,7 +1040,7 @@ void BlocksTreeWidget::contextMenuEvent(QContextMenuEvent* _event) submenu->setTitle(QString("%1 (connection needed)").arg(submenu->title())); } - auto hidemenu = menu.addMenu("Select columns"); + auto hidemenu = menu.addMenu("Select Columns"); auto hdr = headerItem(); #define ADD_COLUMN_ACTION(i) \ diff --git a/profiler_gui/descriptors_tree_widget.cpp b/profiler_gui/descriptors_tree_widget.cpp index 4343cb1..e918d40 100644 --- a/profiler_gui/descriptors_tree_widget.cpp +++ b/profiler_gui/descriptors_tree_widget.cpp @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include #include #include @@ -201,31 +203,63 @@ bool DescriptorsTreeItem::operator < (const Parent& _other) const QVariant DescriptorsTreeItem::data(int _column, int _role) const { - if (_column == DESC_COL_TYPE) + switch (_column) { - if (_role == Qt::ToolTipRole) + case DESC_COL_TYPE: { - switch (m_type) + if (_role == Qt::ToolTipRole) { - case Type::File: return QStringLiteral("File"); - case Type::Event: return QStringLiteral("Event"); - case Type::Block: return QStringLiteral("Block"); - case Type::Value: return QStringLiteral("Arbitrary Value"); + switch (m_type) + { + case Type::File: return QStringLiteral("File"); + case Type::Event: return QStringLiteral("Event"); + case Type::Block: return QStringLiteral("Block"); + case Type::Value: return QStringLiteral("Arbitrary Value"); + } } + else if (_role == Qt::DisplayRole) + { + switch (m_type) + { + case Type::File: return QStringLiteral("F"); + case Type::Event: return QStringLiteral("E"); + case Type::Block: return QStringLiteral("B"); + case Type::Value: return QStringLiteral("V"); + } + } + + break; } - else if (_role == Qt::DisplayRole) + + case DESC_COL_FILE_LINE: { - switch (m_type) + if (parent() != nullptr) { - case Type::File: return QStringLiteral("F"); - case Type::Event: return QStringLiteral("E"); - case Type::Block: return QStringLiteral("B"); - case Type::Value: return QStringLiteral("V"); + if (_role == Qt::ToolTipRole) + { + const int row = data(_column, Qt::UserRole).toInt(); + return QString("%1:%2").arg(parent()->data(_column, Qt::UserRole).toString()).arg(row); + } + else if (_role == Qt::DisplayRole) + { + const int row = data(_column, Qt::UserRole).toInt(); + return QString("%1:%2").arg(parent()->text(_column)).arg(row); + } } + else if (_role == Qt::ToolTipRole) + { + return data(_column, Qt::UserRole).toString(); + } + break; + } + + default: + { + break; } } - return QTreeWidgetItem::data(_column, _role); + return Parent::data(_column, _role); } ////////////////////////////////////////////////////////////////////////// @@ -393,11 +427,11 @@ void DescriptorsTreeWidget::contextMenuEvent(QContextMenuEvent* _event) QMenu menu; menu.setToolTipsVisible(true); - auto action = menu.addAction("Expand all"); + auto action = menu.addAction("Expand All"); action->setIcon(QIcon(imagePath("expand"))); connect(action, &QAction::triggered, this, &This::expandAll); - action = menu.addAction("Collapse all"); + action = menu.addAction("Collapse All"); action->setIcon(QIcon(imagePath("collapse"))); connect(action, &QAction::triggered, this, &This::collapseAll); @@ -407,7 +441,7 @@ void DescriptorsTreeWidget::contextMenuEvent(QContextMenuEvent* _event) const auto& desc = easyDescriptor(static_cast(item)->desc()); menu.addSeparator(); - auto submenu = menu.addMenu("Change status"); + auto submenu = menu.addMenu("Change Status"); submenu->setToolTipsVisible(true); #define ADD_STATUS_ACTION(NameValue, StatusValue, ToolTipValue)\ @@ -431,6 +465,17 @@ void DescriptorsTreeWidget::contextMenuEvent(QContextMenuEvent* _event) submenu->setTitle(QString("%1 (connection needed)").arg(submenu->title())); } + if (item != nullptr) + { + menu.addSeparator(); + action = menu.addAction(QStringLiteral("Copy Full Path")); + connect(action, &QAction::triggered, [this, item] (bool) { + auto fileItem = item->parent() == nullptr ? item : item->parent(); + auto fullName = fileItem->data(DESC_COL_FILE_LINE, Qt::UserRole).toString(); + qApp->clipboard()->setText(fullName); + }); + } + menu.exec(QCursor::pos()); } @@ -494,16 +539,47 @@ void DescriptorsTreeWidget::build() memset(m_items.data(), 0, sizeof(void*) * m_items.size()); const QSignalBlocker b(this); - ::profiler::block_id_t id = 0; + profiler::block_id_t id = 0, count = 0; + + QString commonDir; for (auto desc : EASY_GLOBALS.descriptors) { if (desc != nullptr) { + ++count; + auto& p = fileItems[desc->file()]; if (p.item == nullptr) { auto item = new DescriptorsTreeItem(0); - item->setText(DESC_COL_FILE_LINE, QString(desc->file()).remove(QRegExp("^(\\.{2}\\\\+|\\/+)+"))); + auto fullName = QString(desc->file()).remove(QRegExp("^(\\.{2}\\\\+)+")); // without leading "..\" + auto fileName = QString(desc->file()).remove(QRegExp("^(.+(\\\\|\\/)+)+")); + auto dir = fullName.left(fullName.length() - fileName.length()); + + if (count == 1) + { + commonDir = dir; + } + else if (!commonDir.isEmpty()) + { + if (dir.length() < commonDir.length()) + { + commonDir.truncate(dir.length()); + } + + int i = 0; + for (; i < commonDir.length(); ++i) + { + if (commonDir[i] != dir[i]) + { + break; + } + } + + commonDir.truncate(i); + } + + item->setData(DESC_COL_FILE_LINE, Qt::UserRole, fullName); item->setType(DescriptorsTreeItem::Type::File); p.item = item; } @@ -512,7 +588,6 @@ void DescriptorsTreeWidget::build() if (it == p.children.end()) { auto item = new DescriptorsTreeItem(desc->id(), p.item); - item->setText(DESC_COL_FILE_LINE, QString::number(desc->line())); item->setData(DESC_COL_FILE_LINE, Qt::UserRole, desc->line()); item->setText(DESC_COL_NAME, desc->name()); @@ -551,6 +626,8 @@ void DescriptorsTreeWidget::build() for (auto& p : fileItems) { + auto fullName = p.second.item->data(DESC_COL_FILE_LINE, Qt::UserRole).toString(); + p.second.item->setText(DESC_COL_FILE_LINE, fullName.right(fullName.length() - commonDir.length())); addTopLevelItem(p.second.item); if (m_expandedFilesTemp.find(p.first) != m_expandedFilesTemp.end()) p.second.item->setExpanded(true); @@ -1256,9 +1333,14 @@ void DescWidgetItemDelegate::highlightMatchingText( QTextDocument doc; doc.setDefaultFont(painter->font()); + + auto textOption = doc.defaultTextOption(); + textOption.setWrapMode(QTextOption::NoWrap); + doc.setDefaultTextOption(textOption); + doc.setTextWidth(option.rect.width()); - const auto elidedText = painter->fontMetrics().elidedText(text, Qt::ElideRight, std::max(option.rect.width(), 0)); + const auto elidedText = painter->fontMetrics().elidedText(text, Qt::ElideRight, option.rect.width()); doc.setHtml(elidedText); TextHighlighter highlighter( diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp index 02cf606..d78b980 100644 --- a/profiler_gui/tree_widget_item.cpp +++ b/profiler_gui/tree_widget_item.cpp @@ -561,6 +561,11 @@ void TreeWidgetItemDelegate::highlightMatchingText( QTextDocument doc; doc.setDefaultFont(painter->font()); + + auto textOption = doc.defaultTextOption(); + textOption.setWrapMode(QTextOption::NoWrap); + doc.setDefaultTextOption(textOption); + doc.setTextWidth(option.rect.width() - padding); const auto elidedText = painter->fontMetrics().elidedText(text, Qt::ElideRight, std::max(option.rect.width() - padding, 0));