source: trunk/examples/script/qsdbg/scriptdebugger.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 22.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:BSD$
10** You may use this file under the terms of the BSD license as follows:
11**
12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
25**
26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "scriptdebugger.h"
42#include "scriptbreakpointmanager.h"
43
44#include <QtScript/QScriptEngine>
45#include <QtScript/QScriptEngineAgent>
46#include <QtScript/QScriptContextInfo>
47#include <QtScript/QScriptValueIterator>
48#include <QtCore/QTextStream>
49#include <QtCore/QStack>
50
51static QString safeValueToString(const QScriptValue &value)
52{
53 if (value.isObject())
54 return QLatin1String("[object Object]");
55 else
56 return value.toString();
57}
58
59class ScriptInfo;
60class ScriptBreakpointManager;
61
62class ScriptDebuggerPrivate
63 : public QScriptEngineAgent
64{
65 Q_DECLARE_PUBLIC(ScriptDebugger)
66public:
67 enum Mode {
68 Run,
69 StepInto,
70 StepOver
71 };
72
73 ScriptDebuggerPrivate(QScriptEngine *engine);
74 ~ScriptDebuggerPrivate();
75
76 // QScriptEngineAgent interface
77 void scriptLoad(qint64 id, const QString &program,
78 const QString &fileName, int lineNumber);
79 void scriptUnload(qint64 id);
80
81 void positionChange(qint64 scriptId,
82 int lineNumber, int columnNumber);
83
84 void functionEntry(qint64 scriptId);
85 void functionExit(qint64 scriptId,
86 const QScriptValue &returnValue);
87
88 void exceptionThrow(qint64 scriptId,
89 const QScriptValue &exception, bool hasHandler);
90
91
92 void interactive();
93 bool executeCommand(const QString &command, const QStringList &args);
94
95 void setMode(Mode mode);
96 Mode mode() const;
97
98 int frameCount() const;
99 void setCurrentFrameIndex(int index);
100 int currentFrameIndex() const;
101
102 QScriptContext *frameContext(int index) const;
103 QScriptContext *currentFrameContext() const;
104
105 ScriptInfo *scriptInfo(QScriptContext *context) const;
106
107 int listLineNumber() const;
108 void setListLineNumber(int lineNumber);
109
110 QString readLine();
111 void output(const QString &text);
112 void message(const QString &text);
113 void errorMessage(const QString &text);
114
115 // attributes
116 QTextStream *m_defaultInputStream;
117 QTextStream *m_defaultOutputStream;
118 QTextStream *m_defaultErrorStream;
119 QTextStream *m_inputStream;
120 QTextStream *m_outputStream;
121 QTextStream *m_errorStream;
122
123 ScriptBreakpointManager *m_bpManager;
124 Mode m_mode;
125 QMap<qint64, ScriptInfo*> m_scripts;
126 QMap<QScriptContext*, QStack<qint64> > m_contextProgramIds;
127
128 QString m_lastInteractiveCommand;
129 QString m_commandPrefix;
130 int m_stepDepth;
131 int m_currentFrameIndex;
132 int m_listLineNumber;
133
134 ScriptDebugger *q_ptr;
135};
136
137class ScriptInfo
138{
139public:
140 ScriptInfo(const QString &code, const QString &fileName, int lineNumber)
141 : m_code(code), m_fileName(fileName), m_lineNumber(lineNumber)
142 { }
143
144 inline QString code() const
145 { return m_code; }
146 inline QString fileName() const
147 { return m_fileName; }
148 inline int lineNumber() const
149 { return m_lineNumber; }
150
151 QString lineText(int lineNumber);
152 QMap<int, int> m_lineOffsets;
153
154private:
155 int lineOffset(int lineNumber);
156
157 QString m_code;
158 QString m_fileName;
159 int m_lineNumber;
160};
161
162int ScriptInfo::lineOffset(int lineNumber)
163{
164 QMap<int, int>::const_iterator it = m_lineOffsets.constFind(lineNumber);
165 if (it != m_lineOffsets.constEnd())
166 return it.value();
167
168 int offset;
169 it = m_lineOffsets.constFind(lineNumber - 1);
170 if (it != m_lineOffsets.constEnd()) {
171 offset = it.value();
172 offset = m_code.indexOf(QLatin1Char('\n'), offset);
173 if (offset != -1)
174 ++offset;
175 m_lineOffsets.insert(lineNumber, offset);
176 } else {
177 int index;
178 it = m_lineOffsets.lowerBound(lineNumber);
179 --it;
180 if (it != m_lineOffsets.constBegin()) {
181 index = it.key();
182 offset = it.value();
183 } else {
184 index = m_lineNumber;
185 offset = 0;
186 }
187 int j = index;
188 for ( ; j < lineNumber; ++j) {
189 m_lineOffsets.insert(j, offset);
190 offset = m_code.indexOf(QLatin1Char('\n'), offset);
191 if (offset == -1)
192 break;
193 ++offset;
194 }
195 m_lineOffsets.insert(j, offset);
196 }
197 return offset;
198}
199
200QString ScriptInfo::lineText(int lineNumber)
201{
202 int startOffset = lineOffset(lineNumber);
203 if (startOffset == -1)
204 return QString();
205 int endOffset = lineOffset(lineNumber + 1);
206 if (endOffset == -1)
207 return m_code.mid(startOffset);
208 else
209 return m_code.mid(startOffset, endOffset - startOffset - 1);
210}
211
212
213
214ScriptDebuggerPrivate::ScriptDebuggerPrivate(QScriptEngine *engine)
215 : QScriptEngineAgent(engine), m_mode(Run)
216{
217 m_commandPrefix = QLatin1String(".");
218 m_bpManager = new ScriptBreakpointManager;
219 m_defaultInputStream = new QTextStream(stdin);
220 m_defaultOutputStream = new QTextStream(stdout);
221 m_defaultErrorStream = new QTextStream(stderr);
222 m_inputStream = m_defaultInputStream;
223 m_outputStream = m_defaultOutputStream;
224 m_errorStream = m_defaultErrorStream;
225}
226
227ScriptDebuggerPrivate::~ScriptDebuggerPrivate()
228{
229 delete m_defaultInputStream;
230 delete m_defaultOutputStream;
231 delete m_defaultErrorStream;
232 delete m_bpManager;
233 qDeleteAll(m_scripts);
234}
235
236QString ScriptDebuggerPrivate::readLine()
237{
238 return m_inputStream->readLine();
239}
240
241void ScriptDebuggerPrivate::output(const QString &text)
242{
243 *m_outputStream << text;
244}
245
246void ScriptDebuggerPrivate::message(const QString &text)
247{
248 *m_outputStream << text << endl;
249 m_outputStream->flush();
250}
251
252void ScriptDebuggerPrivate::errorMessage(const QString &text)
253{
254 *m_errorStream << text << endl;
255 m_errorStream->flush();
256}
257
258void ScriptDebuggerPrivate::setMode(Mode mode)
259{
260 m_mode = mode;
261}
262
263ScriptDebuggerPrivate::Mode ScriptDebuggerPrivate::mode() const
264{
265 return m_mode;
266}
267
268QScriptContext *ScriptDebuggerPrivate::frameContext(int index) const
269{
270 QScriptContext *ctx = engine()->currentContext();
271 for (int i = 0; i < index; ++i) {
272 ctx = ctx->parentContext();
273 if (!ctx)
274 break;
275 }
276 return ctx;
277}
278
279int ScriptDebuggerPrivate::currentFrameIndex() const
280{
281 return m_currentFrameIndex;
282}
283
284void ScriptDebuggerPrivate::setCurrentFrameIndex(int index)
285{
286 m_currentFrameIndex = index;
287 m_listLineNumber = -1;
288}
289
290int ScriptDebuggerPrivate::listLineNumber() const
291{
292 return m_listLineNumber;
293}
294
295void ScriptDebuggerPrivate::setListLineNumber(int lineNumber)
296{
297 m_listLineNumber = lineNumber;
298}
299
300QScriptContext *ScriptDebuggerPrivate::currentFrameContext() const
301{
302 return frameContext(currentFrameIndex());
303}
304
305int ScriptDebuggerPrivate::frameCount() const
306{
307 int count = 0;
308 QScriptContext *ctx = engine()->currentContext();
309 while (ctx) {
310 ++count;
311 ctx = ctx->parentContext();
312 }
313 return count;
314}
315
316ScriptInfo *ScriptDebuggerPrivate::scriptInfo(QScriptContext *context) const
317{
318 QStack<qint64> pids = m_contextProgramIds.value(context);
319 if (pids.isEmpty())
320 return 0;
321 return m_scripts.value(pids.top());
322}
323
324void ScriptDebuggerPrivate::interactive()
325{
326 setCurrentFrameIndex(0);
327
328 QString qsdbgPrompt = QString::fromLatin1("(qsdbg) ");
329 QString dotPrompt = QString::fromLatin1(".... ");
330 QString prompt = qsdbgPrompt;
331
332 QString code;
333
334 forever {
335
336 *m_outputStream << prompt;
337 m_outputStream->flush();
338
339 QString line = readLine();
340
341 if (code.isEmpty() && (line.isEmpty() || line.startsWith(m_commandPrefix))) {
342 if (line.isEmpty())
343 line = m_lastInteractiveCommand;
344 else
345 m_lastInteractiveCommand = line;
346
347 QStringList parts = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
348 if (!parts.isEmpty()) {
349 QString command = parts.takeFirst().mid(1);
350 if (executeCommand(command, parts))
351 break;
352 }
353
354 } else {
355 if (line.isEmpty())
356 continue;
357
358 code += line;
359 code += QLatin1Char('\n');
360
361 if (line.trimmed().isEmpty()) {
362 continue;
363
364 } else if (! engine()->canEvaluate(code)) {
365 prompt = dotPrompt;
366
367 } else {
368 setMode(Run);
369 QScriptValue result = engine()->evaluate(code, QLatin1String("typein"));
370
371 code.clear();
372 prompt = qsdbgPrompt;
373
374 if (! result.isUndefined()) {
375 errorMessage(result.toString());
376 engine()->clearExceptions();
377 }
378 }
379 }
380 }
381}
382
383bool ScriptDebuggerPrivate::executeCommand(const QString &command, const QStringList &args)
384{
385 if (command == QLatin1String("c")
386 || command == QLatin1String("continue")) {
387 setMode(Run);
388 return true;
389 } else if (command == QLatin1String("s")
390 || command == QLatin1String("step")) {
391 setMode(StepInto);
392 return true;
393 } else if (command == QLatin1String("n")
394 || command == QLatin1String("next")) {
395 setMode(StepOver);
396 m_stepDepth = 0;
397 return true;
398 } else if (command == QLatin1String("f")
399 || command == QLatin1String("frame")) {
400 bool ok = false;
401 int index = args.value(0).toInt(&ok);
402 if (ok) {
403 if (index < 0 || index >= frameCount()) {
404 errorMessage("No such frame.");
405 } else {
406 setCurrentFrameIndex(index);
407 QScriptContext *ctx = currentFrameContext();
408 message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
409 }
410 }
411 } else if (command == QLatin1String("bt")
412 || command == QLatin1String("backtrace")) {
413 QScriptContext *ctx = engine()->currentContext();
414 int index = -1;
415 while (ctx) {
416 ++index;
417 QString line = ctx->toString();
418 message(QString::fromLatin1("#%0 %1").arg(index).arg(line));
419 ctx = ctx->parentContext();
420 }
421 } else if (command == QLatin1String("up")) {
422 int index = currentFrameIndex() + 1;
423 if (index == frameCount()) {
424 errorMessage(QString::fromLatin1("Initial frame selected; you cannot go up."));
425 } else {
426 setCurrentFrameIndex(index);
427 QScriptContext *ctx = currentFrameContext();
428 message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
429 }
430 } else if (command == QLatin1String("down")) {
431 int index = currentFrameIndex() - 1;
432 if (index < 0) {
433 errorMessage(QString::fromLatin1("Bottom (innermost) frame selected; you cannot go down."));
434 } else {
435 setCurrentFrameIndex(index);
436 QScriptContext *ctx = currentFrameContext();
437 message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
438 }
439 } else if (command == QLatin1String("b")
440 || command == QLatin1String("break")) {
441 QString str = args.value(0);
442 int colonIndex = str.indexOf(QLatin1Char(':'));
443 if (colonIndex != -1) {
444 // filename:line form
445 QString fileName = str.left(colonIndex);
446 int lineNumber = str.mid(colonIndex+1).toInt();
447 int id = m_bpManager->setBreakpoint(fileName, lineNumber);
448 message(QString::fromLatin1("Breakpoint %0 at %1, line %2.").arg(id+1).arg(fileName).arg(lineNumber));
449 } else {
450 // function
451 QScriptValue fun = engine()->globalObject().property(str);
452 if (fun.isFunction()) {
453 int id = m_bpManager->setBreakpoint(fun);
454 message(QString::fromLatin1("Breakpoint %0 at %1().").arg(id+1).arg(str));
455 }
456 }
457 } else if (command == QLatin1String("d")
458 || command == QLatin1String("delete")) {
459 int id = args.value(0).toInt() - 1;
460 m_bpManager->removeBreakpoint(id);
461 } else if (command == QLatin1String("disable")) {
462 int id = args.value(0).toInt() - 1;
463 m_bpManager->setBreakpointEnabled(id, false);
464 } else if (command == QLatin1String("enable")) {
465 int id = args.value(0).toInt() - 1;
466 m_bpManager->setBreakpointEnabled(id, true);
467 } else if (command == QLatin1String("list")) {
468 QScriptContext *ctx = currentFrameContext();
469 ScriptInfo *progInfo = scriptInfo(ctx);
470 if (!progInfo) {
471 errorMessage("No source text available for this frame.");
472 } else {
473 QScriptContextInfo ctxInfo(ctx);
474 bool ok;
475 int line = args.value(0).toInt(&ok);
476 if (ok) {
477 line = qMax(1, line - 5);
478 } else {
479 line = listLineNumber();
480 if (line == -1)
481 line = qMax(progInfo->lineNumber(), ctxInfo.lineNumber() - 5);
482 }
483 for (int i = line; i < line + 10; ++i) {
484 message(QString::fromLatin1("%0\t%1").arg(i).arg(progInfo->lineText(i)));
485 }
486 setListLineNumber(line + 10);
487 }
488 } else if (command == QLatin1String("info")) {
489 if (args.size() < 1) {
490 } else {
491 QString what = args.value(0);
492 if (what == QLatin1String("locals")) {
493 QScriptValueIterator it(currentFrameContext()->activationObject());
494 while (it.hasNext()) {
495 it.next();
496 QString line;
497 line.append(it.name());
498 line.append(QLatin1String(" = "));
499 line.append(safeValueToString(it.value()));
500 message(line);
501 }
502 }
503 }
504 } else if (command == QLatin1String("help")) {
505 message("continue - continue execution\n"
506 "step - step into statement\n"
507 "next - step over statement\n"
508 "list - show where you are\n"
509 "\n"
510 "break - set breakpoint\n"
511 "delete - remove breakpoint\n"
512 "disable - disable breakpoint\n"
513 "enable - enable breakpoint\n"
514 "\n"
515 "backtrace - show backtrace\n"
516 "up - one frame up\n"
517 "down - one frame down\n"
518 "frame - set frame\n"
519 "\n"
520 "info locals - show local variables");
521 } else {
522 errorMessage(QString::fromLatin1("Undefined command \"%0\". Try \"help\".")
523 .arg(command));
524 }
525
526 return false;
527}
528
529
530// QScriptEngineAgent interface
531
532void ScriptDebuggerPrivate::scriptLoad(qint64 id, const QString &program,
533 const QString &fileName, int lineNumber)
534{
535 ScriptInfo *info = new ScriptInfo(program, fileName, lineNumber);
536 m_scripts.insert(id, info);
537}
538
539void ScriptDebuggerPrivate::scriptUnload(qint64 id)
540{
541 ScriptInfo *info = m_scripts.take(id);
542 delete info;
543}
544
545void ScriptDebuggerPrivate::functionEntry(qint64 scriptId)
546{
547 if (scriptId != -1) {
548 QScriptContext *ctx = engine()->currentContext();
549 QStack<qint64> ids = m_contextProgramIds.value(ctx);
550 ids.push(scriptId);
551 m_contextProgramIds.insert(ctx, ids);
552 }
553
554 if (mode() == StepOver)
555 ++m_stepDepth;
556}
557
558void ScriptDebuggerPrivate::functionExit(qint64 scriptId,
559 const QScriptValue &/*returnValue*/)
560{
561 if (scriptId != -1) {
562 QScriptContext *ctx = engine()->currentContext();
563 QStack<qint64> ids = m_contextProgramIds.value(ctx);
564 Q_ASSERT(!ids.isEmpty());
565 Q_ASSERT(ids.top() == scriptId);
566 ids.pop();
567 m_contextProgramIds.insert(ctx, ids);
568 }
569
570 if (mode() == StepOver)
571 --m_stepDepth;
572}
573
574void ScriptDebuggerPrivate::positionChange(qint64 scriptId,
575 int lineNumber, int /*columnNumber*/)
576{
577 ScriptInfo *info = 0;
578 bool enterInteractiveMode = false;
579
580 if (m_bpManager->hasBreakpoints()) {
581 // check if we hit a breakpoint
582 info = m_scripts.value(scriptId);
583 QScriptContext *ctx = engine()->currentContext();
584 QScriptContextInfo ctxInfo(ctx);
585 QScriptValue callee = ctx->callee();
586
587 // try fileName:lineNumber
588 int bpid = m_bpManager->findBreakpoint(info->fileName(), lineNumber);
589 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
590 message(QString::fromLatin1("Breakpoint %0 at %1:%2")
591 .arg(bpid + 1).arg(info->fileName()).arg(lineNumber));
592 if (m_bpManager->isBreakpointSingleShot(bpid))
593 m_bpManager->removeBreakpoint(bpid);
594 }
595 if (bpid == -1) {
596 // try function
597 bpid = m_bpManager->findBreakpoint(callee);
598 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
599 message(QString::fromLatin1("Breakpoint %0, %1()")
600 .arg(bpid + 1).arg(ctxInfo.functionName()));
601 if (m_bpManager->isBreakpointSingleShot(bpid))
602 m_bpManager->removeBreakpoint(bpid);
603 }
604 }
605 if ((bpid == -1) && !ctxInfo.functionName().isEmpty()) {
606 // try functionName:fileName
607 bpid = m_bpManager->findBreakpoint(ctxInfo.functionName(), ctxInfo.fileName());
608 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
609 message(QString::fromLatin1("Breakpoint %0, %1():%2").arg(bpid + 1)
610 .arg(ctxInfo.functionName()).arg(ctxInfo.fileName()));
611 if (m_bpManager->isBreakpointSingleShot(bpid))
612 m_bpManager->removeBreakpoint(bpid);
613 }
614 }
615
616 enterInteractiveMode = (bpid != -1);
617 }
618
619 switch (mode()) {
620 case Run:
621 break;
622
623 case StepInto:
624 enterInteractiveMode = true;
625 break;
626
627 case StepOver:
628 enterInteractiveMode = enterInteractiveMode || (m_stepDepth <= 0);
629 break;
630 }
631
632 if (enterInteractiveMode) {
633 if (!info)
634 info = m_scripts.value(scriptId);
635 Q_ASSERT(info);
636 message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(info->lineText(lineNumber)));
637 interactive();
638 }
639}
640
641void ScriptDebuggerPrivate::exceptionThrow(qint64 /*scriptId*/,
642 const QScriptValue &exception,
643 bool hasHandler)
644{
645 if (!hasHandler) {
646 errorMessage(QString::fromLatin1("uncaught exception: %0").arg(exception.toString()));
647 QScriptContext *ctx = engine()->currentContext();
648 int lineNumber = QScriptContextInfo(ctx).lineNumber();
649 ScriptInfo *info = scriptInfo(ctx);
650 QString lineText = info ? info->lineText(lineNumber) : QString("(no source text available)");
651 message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(lineText));
652 interactive();
653 }
654}
655
656
657
658ScriptDebugger::ScriptDebugger(QScriptEngine *engine)
659 : d_ptr(new ScriptDebuggerPrivate(engine))
660{
661 d_ptr->q_ptr = this;
662 engine->setAgent(d_ptr);
663}
664
665ScriptDebugger::ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd)
666 : d_ptr(&dd)
667{
668 d_ptr->q_ptr = this;
669 engine->setAgent(d_ptr);
670}
671
672ScriptDebugger::~ScriptDebugger()
673{
674 delete d_ptr;
675 d_ptr = 0;
676}
677
678void ScriptDebugger::breakAtNextStatement()
679{
680 Q_D(ScriptDebugger);
681 d->setMode(ScriptDebuggerPrivate::StepInto);
682}
683
684void ScriptDebugger::setBreakpoint(const QString &fileName, int lineNumber)
685{
686 Q_D(ScriptDebugger);
687 d->m_bpManager->setBreakpoint(fileName, lineNumber);
688}
689
690void ScriptDebugger::setBreakpoint(const QString &functionName, const QString &fileName)
691{
692 Q_D(ScriptDebugger);
693 d->m_bpManager->setBreakpoint(functionName, fileName);
694}
695
696void ScriptDebugger::setBreakpoint(const QScriptValue &function)
697{
698 Q_D(ScriptDebugger);
699 d->m_bpManager->setBreakpoint(function);
700}
701
702QTextStream *ScriptDebugger::inputStream() const
703{
704 Q_D(const ScriptDebugger);
705 return d->m_inputStream;
706}
707
708void ScriptDebugger::setInputStream(QTextStream *inputStream)
709{
710 Q_D(ScriptDebugger);
711 d->m_inputStream = inputStream;
712}
713
714QTextStream *ScriptDebugger::outputStream() const
715{
716 Q_D(const ScriptDebugger);
717 return d->m_outputStream;
718}
719
720void ScriptDebugger::setOutputStream(QTextStream *outputStream)
721{
722 Q_D(ScriptDebugger);
723 d->m_outputStream = outputStream;
724}
725
726QTextStream *ScriptDebugger::errorStream() const
727{
728 Q_D(const ScriptDebugger);
729 return d->m_errorStream;
730}
731
732void ScriptDebugger::setErrorStream(QTextStream *errorStream)
733{
734 Q_D(ScriptDebugger);
735 d->m_errorStream = errorStream;
736}
Note: See TracBrowser for help on using the repository browser.