1 /*
2   This file is part of GammaRay, the Qt application inspection and
3   manipulation tool.
4 
5   Copyright (C) 2012-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
6   Author: Volker Krause <volker.krause@kdab.com>
7 
8   Licensees holding valid commercial KDAB GammaRay licenses may use this file in
9   accordance with GammaRay Commercial License Agreement provided with the Software.
10 
11   Contact info@kdab.com if any conditions of this licensing are not clear to you.
12 
13   This program is free software; you can redistribute it and/or modify
14   it under the terms of the GNU General Public License as published by
15   the Free Software Foundation, either version 2 of the License, or
16   (at your option) any later version.
17 
18   This program is distributed in the hope that it will be useful,
19   but WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21   GNU General Public License for more details.
22 
23   You should have received a copy of the GNU General Public License
24   along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 */
26 
27 #include "paintanalyzerwidget.h"
28 #include "ui_paintanalyzerwidget.h"
29 #include "paintbufferclientmodel.h"
30 
31 #include <ui/clientpropertymodel.h>
32 #include <ui/contextmenuextension.h>
33 #include <ui/searchlinecontroller.h>
34 #include <ui/propertyeditor/propertyeditordelegate.h>
35 #include <ui/uiresources.h>
36 
37 #include <common/paintanalyzerinterface.h>
38 #include <common/paintbuffermodelroles.h>
39 #include <common/objectbroker.h>
40 #include <common/sourcelocation.h>
41 
42 #include <QComboBox>
43 #include <QDebug>
44 #include <QLabel>
45 #include <QMenu>
46 #include <QToolBar>
47 
48 using namespace GammaRay;
49 
PaintAnalyzerWidget(QWidget * parent)50 PaintAnalyzerWidget::PaintAnalyzerWidget(QWidget *parent)
51     : QWidget(parent)
52     , ui(new Ui::PaintAnalyzerWidget)
53     , m_iface(nullptr)
54 {
55     ui->setupUi(this);
56     ui->commandView->header()->setObjectName("commandViewHeader");
57     ui->commandView->setItemDelegate(new PropertyEditorDelegate(this));
58     ui->commandView->setStretchLastSection(false);
59     ui->commandView->setDeferredResizeMode(0, QHeaderView::ResizeToContents);
60     ui->commandView->setDeferredResizeMode(1, QHeaderView::Stretch);
61     ui->commandView->setDeferredResizeMode(2, QHeaderView::ResizeToContents);
62 
63     ui->argumentView->setItemDelegate(new PropertyEditorDelegate(this));
64     ui->argumentView->header()->setObjectName("argumentViewHeader");
65     ui->stackTraceView->setItemDelegate(new PropertyEditorDelegate(this));
66     ui->stackTraceView->header()->setObjectName("stackTraceViewHeader");
67 
68     auto toolbar = new QToolBar;
69     // Our icons are 16x16 and support hidpi, so let force iconSize on every styles
70     toolbar->setIconSize(QSize(16, 16));
71     toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
72     ui->replayContainer->setMenuBar(toolbar);
73 
74     foreach (auto action, ui->replayWidget->interactionModeActions()->actions())
75         toolbar->addAction(action);
76     toolbar->addSeparator();
77 
78     toolbar->addAction(ui->replayWidget->zoomOutAction());
79     auto zoom = new QComboBox;
80     zoom->setModel(ui->replayWidget->zoomLevelModel());
81     toolbar->addWidget(zoom);
82     toolbar->addAction(ui->replayWidget->zoomInAction());
83     toolbar->addSeparator();
84     toolbar->addAction(ui->actionShowClipArea);
85 
86     ui->replayWidget->setSupportedInteractionModes(
87         RemoteViewWidget::ViewInteraction | RemoteViewWidget::Measuring | RemoteViewWidget::ColorPicking);
88 
89     ui->paintAnalyzerSplitter->setStretchFactor(0, 1);
90     ui->paintAnalyzerSplitter->setStretchFactor(1, 2);
91 
92     connect(zoom, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
93             ui->replayWidget, &RemoteViewWidget::setZoomLevel);
94     connect(ui->replayWidget, &RemoteViewWidget::zoomLevelChanged, zoom, &QComboBox::setCurrentIndex);
95     zoom->setCurrentIndex(ui->replayWidget->zoomLevelIndex());
96 
97     ui->actionShowClipArea->setIcon(UIResources::themedIcon(QLatin1String("visualize-clipping.png")));
98     connect(ui->actionShowClipArea, &QAction::toggled, ui->replayWidget, &PaintAnalyzerReplayView::setShowClipArea);
99     ui->actionShowClipArea->setChecked(ui->replayWidget->showClipArea());
100 
101     connect(ui->commandView, &QWidget::customContextMenuRequested, this, &PaintAnalyzerWidget::commandContextMenu);
102     connect(ui->stackTraceView, &QWidget::customContextMenuRequested, this, &PaintAnalyzerWidget::stackTraceContextMenu);
103 }
104 
105 PaintAnalyzerWidget::~PaintAnalyzerWidget() = default;
106 
setBaseName(const QString & name)107 void PaintAnalyzerWidget::setBaseName(const QString &name)
108 {
109     auto model = ObjectBroker::model(name + QStringLiteral(".paintBufferModel"));
110     auto proxy = new PaintBufferClientModel(this);
111     proxy->setSourceModel(model);
112     ui->commandView->setModel(proxy);
113     ui->commandView->setSelectionModel(ObjectBroker::selectionModel(proxy));
114     new SearchLineController(ui->commandSearchLine, proxy);
115 
116     auto clientPropModel = new ClientPropertyModel(this);
117     clientPropModel->setSourceModel(ObjectBroker::model(name + QStringLiteral(".argumentProperties")));
118     ui->argumentView->setModel(clientPropModel);
119     ui->stackTraceView->setModel(ObjectBroker::model(name + QStringLiteral(".stackTrace")));
120 
121     ui->replayWidget->setName(name + QStringLiteral(".remoteView"));
122 
123     m_iface = ObjectBroker::object<PaintAnalyzerInterface*>(name);
124     connect(m_iface, &PaintAnalyzerInterface::hasArgumentDetailsChanged, this, &PaintAnalyzerWidget::detailsChanged);
125     connect(m_iface, &PaintAnalyzerInterface::hasStackTraceChanged, this, &PaintAnalyzerWidget::detailsChanged);
126     detailsChanged();
127 }
128 
detailsChanged()129 void PaintAnalyzerWidget::detailsChanged()
130 {
131     const auto hasAnyDetails = m_iface->hasArgumentDetails() || m_iface->hasStackTrace();
132     ui->detailsTabWidget->setVisible(hasAnyDetails);
133     if (!hasAnyDetails)
134         return;
135 
136     const auto hasAllDetails = m_iface->hasArgumentDetails() && m_iface->hasStackTrace();
137     ui->detailsTabWidget->tabBar()->setVisible(hasAllDetails);
138     if (hasAllDetails)
139         return;
140 
141     ui->detailsTabWidget->setCurrentWidget(m_iface->hasArgumentDetails() ? ui->argumentTab : ui->stackTraceTab);
142 }
143 
commandContextMenu(QPoint pos)144 void PaintAnalyzerWidget::commandContextMenu(QPoint pos)
145 {
146     const auto idx = ui->commandView->indexAt(pos);
147     if (!idx.isValid())
148         return;
149 
150     const auto objectId = idx.data(PaintBufferModelRoles::ObjectIdRole).value<ObjectId>();
151 
152     QMenu contextMenu;
153     ContextMenuExtension cme(objectId);
154     cme.populateMenu(&contextMenu);
155     contextMenu.exec(ui->commandView->viewport()->mapToGlobal(pos));
156 }
157 
stackTraceContextMenu(QPoint pos)158 void PaintAnalyzerWidget::stackTraceContextMenu(QPoint pos)
159 {
160     const auto idx = ui->stackTraceView->indexAt(pos);
161     if (!idx.isValid())
162         return;
163 
164     const auto loc = idx.sibling(idx.row(), 1).data().value<SourceLocation>();
165     if (!loc.isValid())
166         return;
167 
168     QMenu contextMenu;
169     ContextMenuExtension cme;
170     cme.setLocation(ContextMenuExtension::ShowSource, loc);
171     cme.populateMenu(&contextMenu);
172     contextMenu.exec(ui->stackTraceView->viewport()->mapToGlobal(pos));
173 }
174