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 "qscriptbreakpointsmodel_p.h"
41#include "qscriptdebuggerjobschedulerinterface_p.h"
42#include "qscriptdebuggercommandschedulerjob_p.h"
43#include "qscriptdebuggercommandschedulerfrontend_p.h"
44
45#include "private/qabstractitemmodel_p.h"
46
47#include <QtCore/qpair.h>
48#include <QtCore/qcoreapplication.h>
49#include <QtGui/qicon.h>
50#include <QtCore/qdebug.h>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \since 4.5
56 \class QScriptBreakpointsModel
57 \internal
58*/
59
60class QScriptBreakpointsModelPrivate
61 : public QAbstractItemModelPrivate
62{
63 Q_DECLARE_PUBLIC(QScriptBreakpointsModel)
64public:
65 QScriptBreakpointsModelPrivate();
66 ~QScriptBreakpointsModelPrivate();
67
68 QScriptDebuggerJobSchedulerInterface *jobScheduler;
69 QScriptDebuggerCommandSchedulerInterface *commandScheduler;
70 QList<QPair<int, QScriptBreakpointData> > breakpoints;
71};
72
73QScriptBreakpointsModelPrivate::QScriptBreakpointsModelPrivate()
74{
75}
76
77QScriptBreakpointsModelPrivate::~QScriptBreakpointsModelPrivate()
78{
79}
80
81QScriptBreakpointsModel::QScriptBreakpointsModel(
82 QScriptDebuggerJobSchedulerInterface *jobScheduler,
83 QScriptDebuggerCommandSchedulerInterface *commandScheduler,
84 QObject *parent)
85 : QAbstractItemModel(*new QScriptBreakpointsModelPrivate, parent)
86{
87 Q_D(QScriptBreakpointsModel);
88 d->jobScheduler = jobScheduler;
89 d->commandScheduler = commandScheduler;
90}
91
92QScriptBreakpointsModel::~QScriptBreakpointsModel()
93{
94}
95
96namespace
97{
98
99class SetBreakpointJob : public QScriptDebuggerCommandSchedulerJob
100{
101public:
102 SetBreakpointJob(const QScriptBreakpointData &data,
103 QScriptDebuggerCommandSchedulerInterface *scheduler)
104 : QScriptDebuggerCommandSchedulerJob(scheduler),
105 m_data(data)
106 { }
107
108 void start()
109 {
110 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
111 frontend.scheduleSetBreakpoint(data: m_data);
112 }
113
114 void handleResponse(const QScriptDebuggerResponse &, int)
115 {
116 finish();
117 }
118
119private:
120 QScriptBreakpointData m_data;
121};
122
123} // namespace
124
125/*!
126 Sets a breakpoint defined by the given \a data.
127 A new row will be inserted into the model if the breakpoint could be
128 successfully set.
129*/
130void QScriptBreakpointsModel::setBreakpoint(const QScriptBreakpointData &data)
131{
132 Q_D(QScriptBreakpointsModel);
133 QScriptDebuggerJob *job = new SetBreakpointJob(data, d->commandScheduler);
134 d->jobScheduler->scheduleJob(job);
135}
136
137namespace
138{
139
140class SetBreakpointDataJob : public QScriptDebuggerCommandSchedulerJob
141{
142public:
143 SetBreakpointDataJob(int id, const QScriptBreakpointData &data,
144 QScriptDebuggerCommandSchedulerInterface *scheduler)
145 : QScriptDebuggerCommandSchedulerJob(scheduler),
146 m_id(id), m_data(data)
147 { }
148
149 void start()
150 {
151 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
152 frontend.scheduleSetBreakpointData(id: m_id, data: m_data);
153 }
154
155 void handleResponse(const QScriptDebuggerResponse &, int)
156 {
157 finish();
158 }
159
160private:
161 int m_id;
162 QScriptBreakpointData m_data;
163};
164
165} // namespace
166
167/*!
168 Sets the \a data associated with the breakpoint identified by \a id.
169 A dataChanged() signal will be emitted if the breakpoint data could
170 be successfully changed.
171*/
172void QScriptBreakpointsModel::setBreakpointData(int id, const QScriptBreakpointData &data)
173{
174 Q_D(QScriptBreakpointsModel);
175 QScriptDebuggerJob *job = new SetBreakpointDataJob(id, data, d->commandScheduler);
176 d->jobScheduler->scheduleJob(job);
177}
178
179namespace
180{
181
182class DeleteBreakpointJob : public QScriptDebuggerCommandSchedulerJob
183{
184public:
185 DeleteBreakpointJob(int id, QScriptDebuggerCommandSchedulerInterface *scheduler)
186 : QScriptDebuggerCommandSchedulerJob(scheduler),
187 m_id(id)
188 { }
189
190 void start()
191 {
192 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
193 frontend.scheduleDeleteBreakpoint(id: m_id);
194 }
195
196 void handleResponse(const QScriptDebuggerResponse &, int)
197 {
198 finish();
199 }
200
201private:
202 int m_id;
203};
204
205} // namespace
206
207/*!
208 Deletes the breakpoint with the given \a id.
209 The corresponding row in the model will be removed if the breakpoint
210 was successfully deleted.
211*/
212void QScriptBreakpointsModel::deleteBreakpoint(int id)
213{
214 Q_D(QScriptBreakpointsModel);
215 QScriptDebuggerJob *job = new DeleteBreakpointJob(id, d->commandScheduler);
216 d->jobScheduler->scheduleJob(job);
217}
218
219/*!
220 Adds a breakpoint to the model. This function does not actually set
221 a breakpoint (i.e. it doesn't communicate with the debugger).
222*/
223void QScriptBreakpointsModel::addBreakpoint(int id, const QScriptBreakpointData &data)
224{
225 Q_D(QScriptBreakpointsModel);
226 int rowIndex = d->breakpoints.size();
227 beginInsertRows(parent: QModelIndex(), first: rowIndex, last: rowIndex);
228 d->breakpoints.append(t: qMakePair(x: id, y: data));
229 endInsertRows();
230}
231
232/*!
233 Modify the \a data of breakpoint \a id.
234*/
235void QScriptBreakpointsModel::modifyBreakpoint(int id, const QScriptBreakpointData &data)
236{
237 Q_D(QScriptBreakpointsModel);
238 for (int i = 0; i < d->breakpoints.size(); ++i) {
239 if (d->breakpoints.at(i).first == id) {
240 d->breakpoints[i] = qMakePair(x: id, y: data);
241 emit dataChanged(topLeft: createIndex(arow: i, acolumn: 0), bottomRight: createIndex(arow: i, acolumn: columnCount()-1));
242 break;
243 }
244 }
245}
246
247/*!
248 Remove the breakpoint identified by \a id from the model. This
249 function does not delete the breakpoint (i.e. it doesn't communicate
250 with the debugger).
251*/
252void QScriptBreakpointsModel::removeBreakpoint(int id)
253{
254 Q_D(QScriptBreakpointsModel);
255 for (int i = 0; i < d->breakpoints.size(); ++i) {
256 if (d->breakpoints.at(i).first == id) {
257 beginRemoveRows(parent: QModelIndex(), first: i, last: i);
258 d->breakpoints.removeAt(i);
259 endRemoveRows();
260 break;
261 }
262 }
263}
264
265/*!
266 Returns the id of the breakpoint at the given \a row.
267*/
268int QScriptBreakpointsModel::breakpointIdAt(int row) const
269{
270 Q_D(const QScriptBreakpointsModel);
271 return d->breakpoints.at(i: row).first;
272}
273
274/*!
275 Returns the data for the breakpoint at the given \a row.
276*/
277QScriptBreakpointData QScriptBreakpointsModel::breakpointDataAt(int row) const
278{
279 Q_D(const QScriptBreakpointsModel);
280 return d->breakpoints.at(i: row).second;
281}
282
283QScriptBreakpointData QScriptBreakpointsModel::breakpointData(int id) const
284{
285 Q_D(const QScriptBreakpointsModel);
286 for (int i = 0; i < d->breakpoints.size(); ++i) {
287 if (d->breakpoints.at(i).first == id)
288 return d->breakpoints.at(i).second;
289 }
290 return QScriptBreakpointData();
291}
292
293/*!
294 Tries to find a breakpoint with the given \a scriptId and \a
295 lineNumber. Returns the id of the first breakpoint that matches, or
296 -1 if no such breakpoint is found.
297*/
298int QScriptBreakpointsModel::resolveBreakpoint(qint64 scriptId, int lineNumber) const
299{
300 Q_D(const QScriptBreakpointsModel);
301 for (int i = 0; i < d->breakpoints.size(); ++i) {
302 if ((d->breakpoints.at(i).second.scriptId() == scriptId)
303 && (d->breakpoints.at(i).second.lineNumber() == lineNumber)) {
304 return d->breakpoints.at(i).first;
305 }
306 }
307 return -1;
308}
309
310int QScriptBreakpointsModel::resolveBreakpoint(const QString &fileName, int lineNumber) const
311{
312 Q_D(const QScriptBreakpointsModel);
313 for (int i = 0; i < d->breakpoints.size(); ++i) {
314 if ((d->breakpoints.at(i).second.fileName() == fileName)
315 && (d->breakpoints.at(i).second.lineNumber() == lineNumber)) {
316 return d->breakpoints.at(i).first;
317 }
318 }
319 return -1;
320}
321
322/*!
323 \reimp
324*/
325QModelIndex QScriptBreakpointsModel::index(int row, int column, const QModelIndex &parent) const
326{
327 Q_D(const QScriptBreakpointsModel);
328 if (parent.isValid())
329 return QModelIndex();
330 if ((row < 0) || (row >= d->breakpoints.size()))
331 return QModelIndex();
332 if ((column < 0) || (column >= columnCount()))
333 return QModelIndex();
334 return createIndex(arow: row, acolumn: column);
335}
336
337/*!
338 \reimp
339*/
340QModelIndex QScriptBreakpointsModel::parent(const QModelIndex &) const
341{
342 return QModelIndex();
343}
344
345/*!
346 \reimp
347*/
348int QScriptBreakpointsModel::columnCount(const QModelIndex &parent) const
349{
350 if (!parent.isValid())
351 return 6;
352 return 0;
353}
354
355/*!
356 \reimp
357*/
358int QScriptBreakpointsModel::rowCount(const QModelIndex &parent) const
359{
360 Q_D(const QScriptBreakpointsModel);
361 if (!parent.isValid())
362 return d->breakpoints.size();
363 return 0;
364}
365
366/*!
367 \reimp
368*/
369QVariant QScriptBreakpointsModel::data(const QModelIndex &index, int role) const
370{
371 Q_D(const QScriptBreakpointsModel);
372 if (!index.isValid() || (index.row() >= d->breakpoints.size()))
373 return QVariant();
374 const QPair<int, QScriptBreakpointData> &item = d->breakpoints.at(i: index.row());
375 if (role == Qt::DisplayRole) {
376 if (index.column() == 0)
377 return item.first;
378 else if (index.column() == 1) {
379 QString loc = item.second.fileName();
380 if (loc.isEmpty())
381 loc = QString::fromLatin1(str: "<anonymous script, id=%0>").arg(a: item.second.scriptId());
382 loc.append(s: QString::fromLatin1(str: ":%0").arg(a: item.second.lineNumber()));
383 return loc;
384 } else if (index.column() == 2) {
385 if (!item.second.condition().isEmpty())
386 return item.second.condition();
387 } else if (index.column() == 3) {
388 if (item.second.ignoreCount() != 0)
389 return item.second.ignoreCount();
390 } else if (index.column() == 5) {
391 return item.second.hitCount();
392 }
393 } else if (role == Qt::CheckStateRole) {
394 if (index.column() == 0) {
395 return item.second.isEnabled() ? Qt::Checked : Qt::Unchecked;
396 } else if (index.column() == 4) {
397 return item.second.isSingleShot() ? Qt::Checked : Qt::Unchecked;
398 }
399 } else if (role == Qt::EditRole) {
400 if (index.column() == 2)
401 return item.second.condition();
402 else if (index.column() == 3)
403 return item.second.ignoreCount();
404 }
405 return QVariant();
406}
407
408/*!
409 \reimp
410*/
411bool QScriptBreakpointsModel::setData(const QModelIndex &index, const QVariant &value, int role)
412{
413 Q_D(QScriptBreakpointsModel);
414 if (!index.isValid() || (index.row() >= d->breakpoints.size()))
415 return false;
416 const QPair<int, QScriptBreakpointData> &item = d->breakpoints.at(i: index.row());
417 QScriptBreakpointData modifiedData;
418 int col = index.column();
419 if ((col == 0) || (col == 4)) {
420 if (role == Qt::CheckStateRole) {
421 modifiedData = item.second;
422 if (col == 0)
423 modifiedData.setEnabled(value.toInt() == Qt::Checked);
424 else
425 modifiedData.setSingleShot(value.toInt() == Qt::Checked);
426 }
427 } else if (col == 2) {
428 if (role == Qt::EditRole) {
429 modifiedData = item.second;
430 modifiedData.setCondition(value.toString());
431 }
432 } else if (col == 3) {
433 if (role == Qt::EditRole) {
434 modifiedData = item.second;
435 modifiedData.setIgnoreCount(value.toInt());
436 }
437 }
438 if (!modifiedData.isValid())
439 return false;
440 QScriptDebuggerJob *job = new SetBreakpointDataJob(item.first, modifiedData, d->commandScheduler);
441 d->jobScheduler->scheduleJob(job);
442 return true;
443}
444
445/*!
446 \reimp
447*/
448QVariant QScriptBreakpointsModel::headerData(int section, Qt::Orientation orient, int role) const
449{
450 if (orient == Qt::Horizontal) {
451 if (role == Qt::DisplayRole) {
452 if (section == 0)
453 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "ID");
454 else if (section == 1)
455 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "Location");
456 else if (section == 2)
457 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "Condition");
458 else if (section == 3)
459 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "Ignore-count");
460 else if (section == 4)
461 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "Single-shot");
462 else if (section == 5)
463 return QCoreApplication::translate(context: "QScriptBreakpointsModel", key: "Hit-count");
464 }
465 }
466 return QVariant();
467}
468
469/*!
470 \reimp
471*/
472Qt::ItemFlags QScriptBreakpointsModel::flags(const QModelIndex &index) const
473{
474 if (!index.isValid())
475 return {};
476 Qt::ItemFlags ret = QAbstractItemModel::flags(index);
477 switch (index.column()) {
478 case 0:
479 ret |= Qt::ItemIsUserCheckable;
480 break;
481 case 1:
482 break;
483 case 2:
484 ret |= Qt::ItemIsEditable;
485 break;
486 case 3:
487 ret |= Qt::ItemIsEditable;
488 break;
489 case 4:
490 ret |= Qt::ItemIsUserCheckable;
491 break;
492 }
493 return ret;
494}
495
496QT_END_NAMESPACE
497

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