1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtSCriptTools module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qscriptdebuggercodewidget_p.h"
41#include "qscriptdebuggercodewidgetinterface_p_p.h"
42#include "qscriptdebuggercodeview_p.h"
43#include "qscriptdebuggerscriptsmodel_p.h"
44#include "qscriptbreakpointsmodel_p.h"
45#include "qscripttooltipproviderinterface_p.h"
46
47#include <QtCore/qdebug.h>
48#include <QtWidgets/qboxlayout.h>
49#include <QtWidgets/qstackedwidget.h>
50
51QT_BEGIN_NAMESPACE
52
53class QScriptDebuggerCodeWidgetPrivate
54 : public QScriptDebuggerCodeWidgetInterfacePrivate
55{
56 Q_DECLARE_PUBLIC(QScriptDebuggerCodeWidget)
57public:
58 QScriptDebuggerCodeWidgetPrivate();
59 ~QScriptDebuggerCodeWidgetPrivate();
60
61 qint64 scriptId(QScriptDebuggerCodeViewInterface *view) const;
62
63 // private slots
64 void _q_onBreakpointToggleRequest(int lineNumber, bool on);
65 void _q_onBreakpointEnableRequest(int lineNumber, bool enable);
66 void _q_onBreakpointsAboutToBeRemoved(const QModelIndex&, int, int);
67 void _q_onBreakpointsInserted(const QModelIndex&, int, int);
68 void _q_onBreakpointsDataChanged(const QModelIndex &, const QModelIndex &);
69 void _q_onScriptsChanged();
70 void _q_onToolTipRequest(const QPoint &pos, int lineNumber, const QStringList &path);
71
72 QScriptDebuggerScriptsModel *scriptsModel;
73 QStackedWidget *viewStack;
74 QHash<qint64, QScriptDebuggerCodeViewInterface*> viewHash;
75 QScriptBreakpointsModel *breakpointsModel;
76 QScriptToolTipProviderInterface *toolTipProvider;
77};
78
79QScriptDebuggerCodeWidgetPrivate::QScriptDebuggerCodeWidgetPrivate()
80{
81 scriptsModel = 0;
82 breakpointsModel = 0;
83 toolTipProvider = 0;
84}
85
86QScriptDebuggerCodeWidgetPrivate::~QScriptDebuggerCodeWidgetPrivate()
87{
88}
89
90qint64 QScriptDebuggerCodeWidgetPrivate::scriptId(QScriptDebuggerCodeViewInterface *view) const
91{
92 if (!view)
93 return -1;
94 return viewHash.key(value: view);
95}
96
97void QScriptDebuggerCodeWidgetPrivate::_q_onBreakpointToggleRequest(int lineNumber, bool on)
98{
99 QScriptDebuggerCodeViewInterface *view = qobject_cast<QScriptDebuggerCodeViewInterface*>(object: q_func()->sender());
100 qint64 sid = scriptId(view);
101 Q_ASSERT(sid != -1);
102 if (on) {
103 QScriptBreakpointData data(sid, lineNumber);
104 data.setFileName(scriptsModel->scriptData(id: sid).fileName());
105 breakpointsModel->setBreakpoint(data);
106 } else {
107 int bpid = breakpointsModel->resolveBreakpoint(scriptId: sid, lineNumber);
108 if (bpid == -1)
109 bpid = breakpointsModel->resolveBreakpoint(fileName: scriptsModel->scriptData(id: sid).fileName(), lineNumber);
110 Q_ASSERT(bpid != -1);
111 breakpointsModel->deleteBreakpoint(id: bpid);
112 }
113}
114
115void QScriptDebuggerCodeWidgetPrivate::_q_onBreakpointEnableRequest(int lineNumber, bool enable)
116{
117 QScriptDebuggerCodeViewInterface *view = qobject_cast<QScriptDebuggerCodeViewInterface*>(object: q_func()->sender());
118 qint64 sid = scriptId(view);
119 int bpid = breakpointsModel->resolveBreakpoint(scriptId: sid, lineNumber);
120 if (bpid == -1)
121 bpid = breakpointsModel->resolveBreakpoint(fileName: scriptsModel->scriptData(id: sid).fileName(), lineNumber);
122 Q_ASSERT(bpid != -1);
123 QScriptBreakpointData data = breakpointsModel->breakpointData(id: bpid);
124 data.setEnabled(enable);
125 breakpointsModel->setBreakpointData(id: bpid, data);
126}
127
128void QScriptDebuggerCodeWidgetPrivate::_q_onBreakpointsAboutToBeRemoved(
129 const QModelIndex &, int first, int last)
130{
131 for (int i = first; i <= last; ++i) {
132 QScriptBreakpointData data = breakpointsModel->breakpointDataAt(row: i);
133 qint64 scriptId = data.scriptId();
134 if (scriptId == -1) {
135 scriptId = scriptsModel->resolveScript(fileName: data.fileName());
136 if (scriptId == -1)
137 continue;
138 }
139 QScriptDebuggerCodeViewInterface *view = viewHash.value(key: scriptId);
140 if (!view)
141 continue;
142 view->deleteBreakpoint(lineNumber: data.lineNumber());
143 }
144}
145
146void QScriptDebuggerCodeWidgetPrivate::_q_onBreakpointsInserted(
147 const QModelIndex &, int first, int last)
148{
149 for (int i = first; i <= last; ++i) {
150 QScriptBreakpointData data = breakpointsModel->breakpointDataAt(row: i);
151 qint64 scriptId = data.scriptId();
152 if (scriptId == -1) {
153 scriptId = scriptsModel->resolveScript(fileName: data.fileName());
154 if (scriptId == -1)
155 continue;
156 }
157 QScriptDebuggerCodeViewInterface *view = viewHash.value(key: scriptId);
158 if (!view)
159 continue;
160 view->setBreakpoint(data.lineNumber());
161 }
162}
163
164void QScriptDebuggerCodeWidgetPrivate::_q_onBreakpointsDataChanged(
165 const QModelIndex &tl, const QModelIndex &br)
166{
167 for (int i = tl.row(); i <= br.row(); ++i) {
168 QScriptBreakpointData data = breakpointsModel->breakpointDataAt(row: i);
169 qint64 scriptId = data.scriptId();
170 if (scriptId == -1) {
171 scriptId = scriptsModel->resolveScript(fileName: data.fileName());
172 if (scriptId == -1)
173 continue;
174 }
175 QScriptDebuggerCodeViewInterface *view = viewHash.value(key: scriptId);
176 if (!view)
177 continue;
178 view->setBreakpointEnabled(lineNumber: data.lineNumber(), enable: data.isEnabled());
179 }
180}
181
182void QScriptDebuggerCodeWidgetPrivate::_q_onScriptsChanged()
183{
184 // kill editors for scripts that have been removed
185 QHash<qint64, QScriptDebuggerCodeViewInterface*>::iterator it;
186 for (it = viewHash.begin(); it != viewHash.end(); ) {
187 if (!scriptsModel->scriptData(id: it.key()).isValid()) {
188 it = viewHash.erase(it);
189 } else
190 ++it;
191 }
192}
193
194void QScriptDebuggerCodeWidgetPrivate::_q_onToolTipRequest(
195 const QPoint &pos, int lineNumber, const QStringList &path)
196{
197 toolTipProvider->showToolTip(pos, /*frameIndex=*/-1, lineNumber, path);
198}
199
200QScriptDebuggerCodeWidget::QScriptDebuggerCodeWidget(QWidget *parent)
201 : QScriptDebuggerCodeWidgetInterface(*new QScriptDebuggerCodeWidgetPrivate, parent, {})
202{
203 Q_D(QScriptDebuggerCodeWidget);
204 QVBoxLayout *vbox = new QVBoxLayout(this);
205 vbox->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
206 d->viewStack = new QStackedWidget();
207 vbox->addWidget(d->viewStack);
208}
209
210QScriptDebuggerCodeWidget::~QScriptDebuggerCodeWidget()
211{
212}
213
214QScriptDebuggerScriptsModel *QScriptDebuggerCodeWidget::scriptsModel() const
215{
216 Q_D(const QScriptDebuggerCodeWidget);
217 return d->scriptsModel;
218}
219
220void QScriptDebuggerCodeWidget::setScriptsModel(QScriptDebuggerScriptsModel *model)
221{
222 Q_D(QScriptDebuggerCodeWidget);
223 d->scriptsModel = model;
224 QObject::connect(sender: model, SIGNAL(layoutChanged()),
225 receiver: this, SLOT(_q_onScriptsChanged()));
226}
227
228qint64 QScriptDebuggerCodeWidget::currentScriptId() const
229{
230 Q_D(const QScriptDebuggerCodeWidget);
231 return d->scriptId(view: currentView());
232}
233
234void QScriptDebuggerCodeWidget::setCurrentScript(qint64 scriptId)
235{
236 Q_D(QScriptDebuggerCodeWidget);
237 if (scriptId == -1) {
238 // ### show "native script"
239 return;
240 }
241 QScriptDebuggerCodeViewInterface *view = d->viewHash.value(key: scriptId);
242 if (!view) {
243 Q_ASSERT(d->scriptsModel != 0);
244 QScriptScriptData data = d->scriptsModel->scriptData(id: scriptId);
245 if (!data.isValid())
246 return;
247 view = new QScriptDebuggerCodeView(); // ### use factory, so user can provide his own view
248 view->setBaseLineNumber(data.baseLineNumber());
249 view->setText(data.contents());
250 view->setExecutableLineNumbers(d->scriptsModel->executableLineNumbers(scriptId));
251 QObject::connect(sender: view, SIGNAL(breakpointToggleRequest(int,bool)),
252 receiver: this, SLOT(_q_onBreakpointToggleRequest(int,bool)));
253 QObject::connect(sender: view, SIGNAL(breakpointEnableRequest(int,bool)),
254 receiver: this, SLOT(_q_onBreakpointEnableRequest(int,bool)));
255 QObject::connect(sender: view, SIGNAL(toolTipRequest(QPoint,int,QStringList)),
256 receiver: this, SLOT(_q_onToolTipRequest(QPoint,int,QStringList)));
257 d->viewStack->addWidget(w: view);
258 d->viewHash.insert(key: scriptId, value: view);
259 }
260 d->viewStack->setCurrentWidget(view);
261}
262
263void QScriptDebuggerCodeWidget::invalidateExecutionLineNumbers()
264{
265 Q_D(QScriptDebuggerCodeWidget);
266 QHash<qint64, QScriptDebuggerCodeViewInterface*>::const_iterator it;
267 for (it = d->viewHash.constBegin(); it != d->viewHash.constEnd(); ++it)
268 it.value()->setExecutionLineNumber(lineNumber: -1, /*error=*/false);
269}
270
271QScriptBreakpointsModel *QScriptDebuggerCodeWidget::breakpointsModel() const
272{
273 Q_D(const QScriptDebuggerCodeWidget);
274 return d->breakpointsModel;
275}
276
277void QScriptDebuggerCodeWidget::setBreakpointsModel(QScriptBreakpointsModel *model)
278{
279 Q_D(QScriptDebuggerCodeWidget);
280 d->breakpointsModel = model;
281 QObject::connect(sender: model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
282 receiver: this, SLOT(_q_onBreakpointsAboutToBeRemoved(QModelIndex,int,int)));
283 QObject::connect(sender: model, SIGNAL(rowsInserted(QModelIndex,int,int)),
284 receiver: this, SLOT(_q_onBreakpointsInserted(QModelIndex,int,int)));
285 QObject::connect(sender: model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
286 receiver: this, SLOT(_q_onBreakpointsDataChanged(QModelIndex,QModelIndex)));
287}
288
289void QScriptDebuggerCodeWidget::setToolTipProvider(QScriptToolTipProviderInterface *toolTipProvider)
290{
291 Q_D(QScriptDebuggerCodeWidget);
292 d->toolTipProvider = toolTipProvider;
293}
294
295QScriptDebuggerCodeViewInterface *QScriptDebuggerCodeWidget::currentView() const
296{
297 Q_D(const QScriptDebuggerCodeWidget);
298 return qobject_cast<QScriptDebuggerCodeViewInterface*>(object: d->viewStack->currentWidget());
299}
300
301QT_END_NAMESPACE
302
303#include "moc_qscriptdebuggercodewidget_p.cpp"
304

source code of qtscript/src/scripttools/debugging/qscriptdebuggercodewidget.cpp