[rkward-cvs] SF.net SVN: rkward:[3975] trunk/rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Thu Oct 20 09:37:56 UTC 2011
Revision: 3975
http://rkward.svn.sourceforge.net/rkward/?rev=3975&view=rev
Author: tfry
Date: 2011-10-20 09:37:56 +0000 (Thu, 20 Oct 2011)
Log Message:
-----------
Add some debugging support. This is not terribly refined, so far, but I think it's fairly useful, already.
Modified Paths:
--------------
trunk/rkward/ChangeLog
trunk/rkward/rkward/agents/CMakeLists.txt
trunk/rkward/rkward/misc/rkstandardicons.cpp
trunk/rkward/rkward/misc/rkstandardicons.h
trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp
trunk/rkward/rkward/rbackend/rinterface.cpp
trunk/rkward/rkward/rbackend/rkrbackend.cpp
trunk/rkward/rkward/rbackend/rkrbackend.h
trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
trunk/rkward/rkward/rkward.cpp
trunk/rkward/rkward/windows/CMakeLists.txt
trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
trunk/rkward/rkward/windows/rkmdiwindow.cpp
trunk/rkward/rkward/windows/rkmdiwindow.h
trunk/rkward/rkward/windows/rktoolwindowbar.cpp
trunk/rkward/rkward/windows/rktoplevelwindowgui.rc
Added Paths:
-----------
trunk/rkward/rkward/agents/rkdebughandler.cpp
trunk/rkward/rkward/agents/rkdebughandler.h
trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_debugger.R
trunk/rkward/rkward/windows/rkcallstackviewer.cpp
trunk/rkward/rkward/windows/rkcallstackviewer.h
trunk/rkward/rkward/windows/rkdebugconsole.cpp
trunk/rkward/rkward/windows/rkdebugconsole.h
Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/ChangeLog 2011-10-20 09:37:56 UTC (rev 3975)
@@ -1,3 +1,4 @@
+- Add GUI support for inspecting the call stack during debugging
- The backend executable is no longer linked against KDE libraries
- Objects, which are not acceptable in a varslot, will still be shown, there, with a warning TODO: add a UI to override
Modified: trunk/rkward/rkward/agents/CMakeLists.txt
===================================================================
--- trunk/rkward/rkward/agents/CMakeLists.txt 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/agents/CMakeLists.txt 2011-10-20 09:37:56 UTC (rev 3975)
@@ -4,6 +4,7 @@
########### next target ###############
SET(agents_STAT_SRCS
+ rkdebughandler.cpp
rkeditobjectagent.cpp
rkloadagent.cpp
rkprintagent.cpp
Added: trunk/rkward/rkward/agents/rkdebughandler.cpp
===================================================================
--- trunk/rkward/rkward/agents/rkdebughandler.cpp (rev 0)
+++ trunk/rkward/rkward/agents/rkdebughandler.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,80 @@
+/***************************************************************************
+ rkdebughandler - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "rkdebughandler.h"
+
+#include "../rbackend/rkrbackendprotocol_frontend.h"
+
+#include "../debug.h"
+
+RKDebugHandler* RKDebugHandler::_instance = 0;
+
+RKDebugHandler::RKDebugHandler (QObject *parent) : QObject (parent) {
+ RK_TRACE (APP);
+
+ _state = NotInDebugger;
+ _request = 0;
+ _instance = this;
+}
+
+RKDebugHandler::~RKDebugHandler () {
+ RK_TRACE (APP);
+}
+
+void RKDebugHandler::debugCall (RBackendRequest *request, RCommand *command) {
+ RK_TRACE (APP);
+
+ _request = request;
+ if (command) _output_context = command->fullOutput ();
+ else _output_context.clear ();
+
+ _calls = request->params["calls"].toStringList ();
+ _functions = request->params["funs"].toStringList ();
+ _environments = request->params["envs"].toStringList ();
+ _locals = request->params["locals"].toStringList ();
+ _prompt = request->params["prompt"].toString ();
+
+ _state = InDebugPrompt;
+ newDebugState ();
+}
+
+void RKDebugHandler::submitDebugString (const QString &command) {
+ RK_TRACE (APP);
+
+ if (!_request) {
+ RK_ASSERT (false);
+ return;
+ }
+
+ _request->params["result"] = command;
+
+ RKRBackendProtocolFrontend::setRequestCompleted (_request);
+
+ _state = InDebugRun;
+ newDebugState ();
+}
+
+void RKDebugHandler::endDebug () {
+ RK_TRACE (APP);
+
+ _request = 0;
+ _state = NotInDebugger;
+ newDebugState ();
+}
+
+#include "rkdebughandler.moc"
+
Added: trunk/rkward/rkward/agents/rkdebughandler.h
===================================================================
--- trunk/rkward/rkward/agents/rkdebughandler.h (rev 0)
+++ trunk/rkward/rkward/agents/rkdebughandler.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,64 @@
+/***************************************************************************
+ rkdebughandler - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RKDEBUGHANDLER_H
+#define RKDEBUGHANDLER_H
+
+#include <QObject>
+
+#include "../rbackend/rcommand.h"
+
+class RBackendRequest;
+
+/** A central handler, responsible for keeping all debug related widgets up-to-date */
+class RKDebugHandler : public QObject {
+ Q_OBJECT
+public:
+ RKDebugHandler (QObject *parent);
+ ~RKDebugHandler ();
+
+ static RKDebugHandler *instance () { return _instance; };
+
+ void debugCall (RBackendRequest *request, RCommand *command);
+ void submitDebugString (const QString &command);
+ void endDebug ();
+
+ enum DebugState {
+ NotInDebugger,
+ InDebugPrompt,
+ InDebugRun
+ };
+ DebugState state () const { return _state; };
+
+ QString outputContext () const { return _output_context; };
+ QStringList calls () const { return _calls; };
+ QStringList functions () const { return _functions; };
+ QStringList environments () const { return _environments; };
+ QStringList locals () const { return _locals; };
+ QString debugPrompt () const { return _prompt; };
+signals:
+ void newDebugState ();
+private:
+ QStringList _calls, _functions, _environments, _locals;
+ QString _prompt, _output_context;
+ DebugState _state;
+ RBackendRequest *_request;
+
+ static RKDebugHandler *_instance;
+};
+
+#endif
Modified: trunk/rkward/rkward/misc/rkstandardicons.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkstandardicons.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/misc/rkstandardicons.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -106,6 +106,8 @@
icons[WindowSearchHelp] = KIcon ("help-contents");
icons[WindowPendingJobs] = KIcon ("system-run");
icons[WindowFileBrowser] = KIcon ("folder");
+ icons[WindowDebugConsole] = KIcon ("view-process-system");
+ icons[WindowCallstackViewer] = KIcon ("view-sort-ascending");
icons[DocumentPDF] = KIcon ("application-pdf");
@@ -165,6 +167,8 @@
if (window->isType (RKMDIWindow::SearchHelpWindow)) return icons[WindowSearchHelp];
if (window->isType (RKMDIWindow::PendingJobsWindow)) return icons[WindowPendingJobs];
if (window->isType (RKMDIWindow::FileBrowserWindow)) return icons[WindowFileBrowser];
+ if (window->isType (RKMDIWindow::DebugConsoleWindow)) return icons[WindowDebugConsole];
+ if (window->isType (RKMDIWindow::CallstackViewerWindow)) return icons[WindowCallstackViewer];
RK_ASSERT (false);
return QIcon ();
Modified: trunk/rkward/rkward/misc/rkstandardicons.h
===================================================================
--- trunk/rkward/rkward/misc/rkstandardicons.h 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/misc/rkstandardicons.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -102,6 +102,8 @@
WindowSearchHelp,
WindowPendingJobs,
WindowFileBrowser,
+ WindowDebugConsole,
+ WindowCallstackViewer,
DocumentPDF,
Modified: trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -257,14 +257,12 @@
void RKStandardComponentGUI::updateCodeNow () {
RK_TRACE (PLUGIN);
- code_display->setReadOnly (false); // sigh. The kate part does not allow setting text programatically, when it is read only
if (!code_property->isValid ()) {
code_display->setText (i18n ("Processing. Please wait"));
RK_DO (qDebug ("code not ready to be displayed: pre %d, cal %d, pri %d", !code_property->preprocess ().isNull (), !code_property->calculate ().isNull (), !code_property->printout ().isNull ()), PLUGIN, DL_DEBUG);
} else {
code_display->setText ("local({\n" + code_property->preprocess () + code_property->calculate () + code_property->printout () + "})\n");
}
- code_display->setReadOnly (true);
}
///////////////////////////////// RKStandardComponentWizard /////////////////////////////////
Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -36,6 +36,7 @@
#include "../agents/showedittextfileagent.h"
#include "../agents/rkeditobjectagent.h"
#include "../agents/rkprintagent.h"
+#include "../agents/rkdebughandler.h"
#include "../windows/rcontrolwindow.h"
#include "../windows/rkworkplace.h"
#include "../windows/rkcommandlog.h"
@@ -106,6 +107,7 @@
issueCommand (fake);
new RKSessionVars (this);
+ new RKDebugHandler (this);
new RKRBackendProtocolFrontend (this);
RKRBackendProtocolFrontend::instance ()->setupBackend ();
@@ -606,6 +608,8 @@
}
} else if (call == "printPreview") {
RKPrintAgent::printPostscript (calllist.value (1), true);
+ } else if (call == "endBrowserContext") {
+ RKDebugHandler::instance ()->endDebug ();
} else {
return (QStringList ("Error: unrecognized request '" + call + "'."));
}
@@ -766,11 +770,15 @@
dummy_command = true;
}
+
bool ok = RKReadLineDialog::readLine (0, i18n ("R backend requests information"), request->params["prompt"].toString (), command, &result);
request->params["result"] = QVariant (result);
if (dummy_command) delete command;
if (!ok) request->params["cancelled"] = QVariant (true);
+ } else if (type == RBackendRequest::Debugger) {
+ RKDebugHandler::instance ()->debugCall (request, runningCommand ());
+ return; // request will be closed by the debug handler
} else if ((type == RBackendRequest::ShowFiles) || (type == RBackendRequest::EditFiles)) {
ShowEditTextFileAgent::showEditFiles (request);
return; // we are not done, yet!
Modified: trunk/rkward/rkward/rbackend/rkrbackend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/rbackend/rkrbackend.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -31,7 +31,7 @@
// statics
RKRBackend *RKRBackend::this_pointer = 0;
-RKRBackend::RKReplStatus RKRBackend::repl_status = { QByteArray (), 0, true, 0, 0, RKRBackend::RKReplStatus::NoUserCommand, 0, false, false };
+RKRBackend::RKReplStatus RKRBackend::repl_status = { QByteArray (), 0, true, 0, 0, RKRBackend::RKReplStatus::NoUserCommand, 0, RKRBackend::RKReplStatus::NotInBrowserContext, false };
void* RKRBackend::default_global_context = 0;
#include <qstring.h>
@@ -195,7 +195,7 @@
Q_UNUSED (value);
Q_UNUSED (visible);
- if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.in_browser_context)) { // Yes, toplevel-handlers _do_ get called in a browser context!
+ if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context)) { // Yes, toplevel-handlers _do_ get called in a browser context!
RK_ASSERT (RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandRunning);
if (succeeded) {
RKRBackend::repl_status.user_command_successful_up_to = RKRBackend::repl_status.user_command_parsed_up_to;
@@ -265,14 +265,14 @@
RK_ASSERT (buf && buflen);
RK_ASSERT (RKRBackend::repl_status.eval_depth >= 0);
- if (RKRBackend::repl_status.in_browser_context) { // previously we were in a browser context. Check, whether we've left that.
+ if (RKRBackend::repl_status.browser_context) { // previously we were in a browser context. Check, whether we've left that.
if (RKRBackend::default_global_context == R_GlobalContext) {
- RKRBackend::repl_status.in_browser_context = false;
- RK_ASSERT (!hist);
+ RKRBackend::repl_status.browser_context = RKRBackend::RKReplStatus::NotInBrowserContext;
+ RKRBackend::this_pointer->handlePlainGenericRequest (QStringList ("endBrowserContext"), false);
}
}
- if ((!RKRBackend::repl_status.in_browser_context) && (RKRBackend::repl_status.eval_depth == 0)) {
+ if ((!RKRBackend::repl_status.browser_context) && (RKRBackend::repl_status.eval_depth == 0)) {
while (1) {
if (RKRBackend::repl_status.user_command_status == RKRBackend::RKReplStatus::NoUserCommand) {
RCommandProxy *command = RKRBackend::this_pointer->fetchNextCommand ();
@@ -371,14 +371,38 @@
// here, we handle readline() calls and such, i.e. not the regular prompt for code
// browser() also takes us here.
+ QVariantMap params;
+ RBackendRequest::RCallbackType request_type = RBackendRequest::ReadLine;
+ params["prompt"] = QVariant (prompt);
+ params["cancelled"] = QVariant (false);
+
+ // add info for browser requests
if (hist && (RKRBackend::default_global_context != R_GlobalContext)) {
- // TODO: give browser() special handling!
- RKRBackend::repl_status.in_browser_context = true;
+ if (RKRBackend::repl_status.browser_context == RKRBackend::RKReplStatus::InBrowserContextPreventRecursion) {
+ qstrncpy ((char *) buf, "n\n", buflen); // skip this, by feeding the browser() a continue
+ return 1;
+ } else {
+ RKRBackend::repl_status.browser_context = RKRBackend::RKReplStatus::InBrowserContextPreventRecursion;
+ RCommandProxy *dummy = RKRBackend::this_pointer->runDirectCommand (".rk.callstack.info()", RCommand::GetStructuredData);
+
+ request_type = RBackendRequest::Debugger;
+ if ((dummy->getDataType () == RData::StructureVector) && (dummy->getDataLength () >= 4)) {
+ params["calls"] = QVariant (dummy->getStructureVector ()[0]->getStringVector ());
+ params["funs"] = QVariant (dummy->getStructureVector ()[1]->getStringVector ());
+ params["envs"] = QVariant (dummy->getStructureVector ()[2]->getStringVector ());
+ params["locals"] = QVariant (dummy->getStructureVector ()[3]->getStringVector ());
+ } else {
+ RK_ASSERT (false);
+ }
+
+ RKRBackend::repl_status.browser_context = RKRBackend::RKReplStatus::InBrowserContext;
+ }
+
+ RK_ASSERT (RKRBackend::repl_status.browser_context == RKRBackend::RKReplStatus::InBrowserContext);
}
- RBackendRequest request (true, RBackendRequest::ReadLine);
- request.params["prompt"] = QVariant (prompt);
- request.params["cancelled"] = QVariant (false);
+ RBackendRequest request (true, request_type);
+ request.params = params;
RKRBackend::this_pointer->handleRequest (&request);
if (request.params["cancelled"].toBool ()) {
@@ -427,7 +451,7 @@
RK_TRACE (RBACKEND);
// output while nothing else is running (including handlers?) -> This may be a syntax error.
- if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.in_browser_context) && (!RKRBackend::this_pointer->isKilled ())) {
+ if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context) && (!RKRBackend::this_pointer->isKilled ())) {
if (RKRBackend::repl_status.user_command_status == RKRBackend::RKReplStatus::UserCommandTransmitted) {
// status UserCommandTransmitted might have been set from RKToplevelStatementFinishedHandler, too, in which case all is fine
// (we're probably inside another task handler at this point, then)
@@ -443,6 +467,7 @@
}
if (RKRBackend::this_pointer->killed == RKRBackend::AlreadyDead) return; // this check is mostly for fork()ed clients
+ if (RKRBackend::repl_status.browser_context == RKRBackend::RKReplStatus::InBrowserContextPreventRecursion) return;
RKRBackend::this_pointer->fetchStdoutStderr (true);
RKRBackend::this_pointer->handleOutput (RKRBackend::this_pointer->current_locale_codec->toUnicode (buf, buflen), buflen, type == 0 ? ROutput::Output : ROutput::Warning);
}
@@ -843,7 +868,7 @@
SEXP doError (SEXP call) {
RK_TRACE (RBACKEND);
- if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.in_browser_context) && (!RKRBackend::this_pointer->isKilled ()) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled)) {
+ if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context) && (!RKRBackend::this_pointer->isKilled ()) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled)) {
RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandFailed;
}
if (RKRBackend::repl_status.interrupted) {
Modified: trunk/rkward/rkward/rbackend/rkrbackend.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.h 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/rbackend/rkrbackend.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -160,7 +160,11 @@
ReplIterationKilled
} user_command_status;
int eval_depth; // Number (depth) of non-user commands currently running. User commands can only run at depth 0
- bool in_browser_context;
+ enum {
+ NotInBrowserContext = 0,
+ InBrowserContext,
+ InBrowserContextPreventRecursion
+ } browser_context;
bool interrupted;
};
static RKReplStatus repl_status;
Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -44,6 +44,7 @@
HistoricalSubstackRequest,
PlainGenericRequest,
SetParamsFromBackend,
+ Debugger,
CommandLineIn, /**< The next line of the current user command has been submitted in the backend. */
#ifndef RKWARD_THREADED
Output, /**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */
Added: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_debugger.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_debugger.R (rev 0)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_debugger.R 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,19 @@
+# gather debug information.
+# Note: subsequent browser() calls should be suppressed while inside this function!
+.rk.callstack.info <- function () {
+ nframes <- sys.nframe() - 1 # strip this function call
+ calls <- character (0)
+ funs <- character (0)
+ envs <- character (0)
+ locals <- character (0)
+
+ if (nframes > 0) {
+ for (i in 1:nframes) {
+ calls[i] <- as.character (try (paste (deparse (sys.call (i)), collapse="\n")), silent=TRUE)
+ funs[i] <- as.character (try (paste (deparse (sys.function (i), control="all"), collapse="\n"), silent=TRUE))
+ envs[i] <- as.character (try (capture.output (print (environment (sys.function (i)))), silent=TRUE))
+ locals[i] <- as.character (try (paste (ls (sys.frame (i), all.names=TRUE), collapse="\n"), silent=TRUE))
+ }
+ }
+ list ("calls"=calls, "functions"=funs, "environments"=envs, "locals"=locals)
+}
Modified: trunk/rkward/rkward/rkward.cpp
===================================================================
--- trunk/rkward/rkward/rkward.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/rkward.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -82,6 +82,8 @@
#include "windows/rktoplevelwindowgui.h"
#include "windows/rkfilebrowser.h"
#include "windows/rktoolwindowlist.h"
+#include "windows/rkdebugconsole.h"
+#include "windows/rkcallstackviewer.h"
#include "rkconsole.h"
#include "debug.h"
#include "version.h"
@@ -343,6 +345,15 @@
RKHelpSearchWindow::main_help_search = help_search;
RKToolWindowList::registerToolWindow (help_search, "helpsearch", RKToolWindowList::Bottom, Qt::AltModifier + Qt::Key_6);
+ RKCallstackViewer::_instance = new RKCallstackViewer (0, true);
+ RKCallstackViewer::instance ()->setCaption (i18n ("Debugger Frames"));
+ RKToolWindowList::registerToolWindow (RKCallstackViewer::instance (), "debugframes", RKToolWindowList::Right, Qt::AltModifier + Qt::Key_8);
+
+ // HACK: Creating this _after_ the callstackviewer is important, so the debug console will end up the active window when entering a debug context
+ RKDebugConsole::_instance = new RKDebugConsole (0, true);
+ RKDebugConsole::instance ()->setCaption (i18n ("Debugger Console"));
+ RKToolWindowList::registerToolWindow (RKDebugConsole::instance (), "debugconsole", RKToolWindowList::Nowhere, Qt::AltModifier + Qt::Key_7);
+
RKWorkplace::mainWorkplace ()->placeToolWindows ();
}
Modified: trunk/rkward/rkward/windows/CMakeLists.txt
===================================================================
--- trunk/rkward/rkward/windows/CMakeLists.txt 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/CMakeLists.txt 2011-10-20 09:37:56 UTC (rev 3975)
@@ -4,6 +4,8 @@
SET(windows_STAT_SRCS
rkcommandeditorwindow.cpp
+ rkdebugconsole.cpp
+ rkcallstackviewer.cpp
rkhtmlwindow.cpp
rcontrolwindow.cpp
detachedwindowcontainer.cpp
Added: trunk/rkward/rkward/windows/rkcallstackviewer.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkcallstackviewer.cpp (rev 0)
+++ trunk/rkward/rkward/windows/rkcallstackviewer.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,151 @@
+/***************************************************************************
+ rkcallstackviewer - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "rkcallstackviewer.h"
+
+#include <klocale.h>
+#include <kvbox.h>
+
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QListWidget>
+#include <QTextDocument>
+
+#include "../misc/rkdummypart.h"
+#include "../agents/rkdebughandler.h"
+#include "rkcommandeditorwindow.h"
+
+#include "../debug.h"
+
+RKCallstackViewer* RKCallstackViewer::_instance = 0;
+
+RKCallstackViewer::RKCallstackViewer (QWidget *parent, bool tool_window, const char *name) : RKMDIWindow (parent, RKMDIWindow::CallstackViewerWindow, tool_window, name) {
+ RK_TRACE (APP);
+
+ real_widget = 0;
+
+ QVBoxLayout *layout = new QVBoxLayout (this);
+ layout->setContentsMargins (0, 0, 0, 0);
+ layout_widget = new KVBox (this);
+ layout->addWidget (layout_widget);
+ layout_widget->setFocusPolicy (Qt::StrongFocus);
+
+ setPart (new RKDummyPart (this, layout_widget));
+ initializeActivationSignals ();
+
+ connect (RKDebugHandler::instance (), SIGNAL (newDebugState()), this, SLOT (newDebugState()));
+}
+
+RKCallstackViewer::~RKCallstackViewer () {
+ RK_TRACE (APP);
+}
+
+void RKCallstackViewer::showEvent (QShowEvent *e) {
+ RK_TRACE (APP);
+
+ createRealWidget ();
+ RKMDIWindow::showEvent (e);
+}
+
+void RKCallstackViewer::createRealWidget () {
+ RK_TRACE (APP);
+
+ if (!real_widget) {
+ RK_DO (qDebug ("creating callstack viewer"), APP, DL_INFO);
+
+ real_widget = new RKCallstackViewerWidget (layout_widget);
+ setFocusProxy (real_widget);
+ }
+}
+
+void RKCallstackViewer::newDebugState () {
+ RK_TRACE (APP);
+
+ if (!real_widget) createRealWidget ();
+ else real_widget->updateState ();
+ if (RKDebugHandler::instance ()->state () == RKDebugHandler::InDebugPrompt) activate ();
+}
+
+
+
+RKCallstackViewerWidget::RKCallstackViewerWidget (QWidget *parent) : QWidget (parent) {
+ RK_TRACE (APP);
+
+ QHBoxLayout *h_layout = new QHBoxLayout (this);
+ h_layout->setContentsMargins (0, 0, 0, 0);
+
+ QVBoxLayout *v_layout = new QVBoxLayout ();
+ h_layout->addLayout (v_layout);
+ h_layout->setStretchFactor (v_layout, 1);
+
+ QLabel *label = new QLabel (i18n ("<b>Active calls</b>"), this);
+ v_layout->addWidget (label);
+ frame_selector = new QListWidget (this);
+ frame_selector->setSelectionMode (QAbstractItemView::SingleSelection);
+ connect (frame_selector, SIGNAL (currentRowChanged(int)), this, SLOT (frameChanged(int)));
+ v_layout->addWidget (frame_selector);
+
+ v_layout = new QVBoxLayout ();
+ h_layout->addLayout (v_layout);
+ h_layout->setStretchFactor (v_layout, 2);
+
+ frame_info = new QLabel (this);
+ frame_info->setWordWrap (true);
+ v_layout->addWidget (frame_info);
+
+ frame_source = new RKCommandEditorWindow (this, true);
+ v_layout->addWidget (frame_source);
+
+ updateState ();
+}
+
+RKCallstackViewerWidget::~RKCallstackViewerWidget () {
+ RK_TRACE (APP);
+}
+
+void RKCallstackViewerWidget::updateState () {
+ RK_TRACE (APP);
+
+ if (RKDebugHandler::instance ()->state () == RKDebugHandler::NotInDebugger) {
+ QString info = i18n ("Not in a debugger context");
+ frame_source->setText (info);
+ frame_selector->clear ();
+ frame_info->setText ("<b>" + info + "</b>");
+ } else if (RKDebugHandler::instance ()->state () == RKDebugHandler::InDebugPrompt) {
+ frame_selector->clear ();
+ frame_selector->setEnabled (true);
+ frame_selector->insertItems (0, RKDebugHandler::instance ()->calls ());
+ frame_selector->setCurrentRow (frame_selector->count () - 1);
+ } else {
+ frame_selector->setEnabled (false);
+ }
+}
+
+void RKCallstackViewerWidget::frameChanged (int frame_number) {
+ RK_TRACE (APP);
+
+ if (RKDebugHandler::instance ()->state () == RKDebugHandler::NotInDebugger) return;
+
+ frame_info->setText (i18n ("<b>Current call:</b> %1<br><b>Environment:</b> %2<br><b>Local objects:</b> %3",
+ Qt::escape (RKDebugHandler::instance ()->calls ().value (frame_number)),
+ Qt::escape (RKDebugHandler::instance ()->environments ().value (frame_number)),
+ Qt::escape (RKDebugHandler::instance ()->locals ().value (frame_number).split ('\n').join (", "))));
+ frame_source->setText (RKDebugHandler::instance ()->functions ().value (frame_number));
+}
+
+#include "rkcallstackviewer.moc"
Added: trunk/rkward/rkward/windows/rkcallstackviewer.h
===================================================================
--- trunk/rkward/rkward/windows/rkcallstackviewer.h (rev 0)
+++ trunk/rkward/rkward/windows/rkcallstackviewer.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,65 @@
+/***************************************************************************
+ rkcallstackviewer - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RKCALLSTACKVIEWER_H
+#define RKCALLSTACKVIEWER_H
+
+#include "rkmdiwindow.h"
+
+class RKCallstackViewerWidget;
+class RKCommandEditorWindow;
+class QListWidget;
+class QLabel;
+
+/** The call stack (tool) window. In order to save some startup time, the widget is not really created until it is first shown. Hence, this is mostly just a wrapper around RKCallstackViewerWidget */
+class RKCallstackViewer : public RKMDIWindow {
+ Q_OBJECT
+public:
+ RKCallstackViewer (QWidget *parent, bool tool_window, const char *name=0);
+ ~RKCallstackViewer ();
+
+/** reimplemented to create the real widget only when the viewer is shown for the first time */
+ void showEvent (QShowEvent *e);
+ static RKCallstackViewer *instance () { return _instance; };
+public slots:
+ void newDebugState ();
+private:
+ void createRealWidget ();
+ RKCallstackViewerWidget *real_widget;
+ QWidget *layout_widget;
+friend class RKWardMainWindow;
+ static RKCallstackViewer *_instance;
+};
+
+/** The internal widget used in RKCallstackViewer
+*/
+class RKCallstackViewerWidget : public QWidget {
+ Q_OBJECT
+public:
+ RKCallstackViewerWidget (QWidget *parent);
+ ~RKCallstackViewerWidget ();
+
+ void updateState ();
+private slots:
+ void frameChanged (int frame_number);
+private:
+ QListWidget *frame_selector;
+ QLabel *frame_info;
+ RKCommandEditorWindow *frame_source;
+};
+
+#endif
Modified: trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -483,7 +483,9 @@
void RKCommandEditorWindow::setText (const QString &text) {
RK_TRACE (COMMANDEDITOR);
+ m_doc->setReadWrite (true);
m_doc->setText (text);
+ m_doc->setReadWrite (false);
}
void RKCommandEditorWindow::updateCaption (KTextEditor::Document*) {
Added: trunk/rkward/rkward/windows/rkdebugconsole.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkdebugconsole.cpp (rev 0)
+++ trunk/rkward/rkward/windows/rkdebugconsole.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,151 @@
+/***************************************************************************
+ rkdebugconsole - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "rkdebugconsole.h"
+
+#include <QPushButton>
+#include <QTextEdit>
+#include <QLineEdit>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "../agents/rkdebughandler.h"
+#include "../misc/rkdummypart.h"
+
+#include "../debug.h"
+
+RKDebugConsole* RKDebugConsole::_instance = 0;
+
+RKDebugConsole::RKDebugConsole (QWidget *parent, bool tool_window, const char *name) : RKMDIWindow (parent, DebugConsoleWindow, tool_window, name) {
+ RK_TRACE (APP);
+
+ QVBoxLayout *main_layout = new QVBoxLayout (this);
+ main_layout->setContentsMargins (0, 0, 0, 0);
+ QHBoxLayout *upper_layout = new QHBoxLayout ();
+ main_layout->addLayout (upper_layout);
+
+ context_view = new QTextEdit (this);
+ context_view->setReadOnly (true);
+ context_view->setAcceptRichText (false);
+ upper_layout->addWidget (context_view);
+
+ QVBoxLayout *button_layout = new QVBoxLayout ();
+ upper_layout->addLayout (button_layout);
+ step_button = new QPushButton (i18n ("Next"), this);
+ connect (step_button, SIGNAL (clicked()), this, SLOT (stepButtonClicked()));
+ button_layout->addWidget (step_button);
+ continue_button = new QPushButton (i18n ("Continue"), this);
+ connect (continue_button, SIGNAL (clicked()), this, SLOT (continueButtonClicked()));
+ button_layout->addWidget (continue_button);
+ cancel_button = new QPushButton (i18n ("Cancel"), this);
+ connect (cancel_button, SIGNAL (clicked()), this, SLOT (cancelButtonClicked()));
+ button_layout->addWidget (cancel_button);
+ button_layout->addStretch ();
+
+ QHBoxLayout *lower_layout = new QHBoxLayout ();
+ main_layout->addLayout (lower_layout);
+
+ prompt_label = new QLabel (this);
+ lower_layout->addWidget (prompt_label);
+ reply_edit = new QLineEdit (this);
+ connect (reply_edit, SIGNAL (returnPressed()), this, SLOT (sendReply()));
+ lower_layout->addWidget (reply_edit);
+ setFocusProxy (reply_edit);
+
+ setFocusPolicy (Qt::StrongFocus);
+
+ setPart (new RKDummyPart (this, this));
+ initializeActivationSignals ();
+
+ connect (RKDebugHandler::instance (), SIGNAL (newDebugState()), this, SLOT (newDebugState()));
+ newDebugState ();
+}
+
+RKDebugConsole::~RKDebugConsole () {
+ RK_TRACE (APP);
+}
+
+void RKDebugConsole::newDebugState () {
+ RK_TRACE (APP);
+
+ bool enable = true;
+ if (RKDebugHandler::instance ()->state () == RKDebugHandler::NotInDebugger) {
+ context_view->setPlainText (i18n ("Not in a debugger context"));
+ setEnabled (false);
+ return;
+ } else if (RKDebugHandler::instance ()->state () == RKDebugHandler::InDebugRun) {
+ enable = false;
+ reply_edit->setEnabled (false);
+ } else {
+ context_view->setPlainText (RKDebugHandler::instance ()->outputContext ());
+ prompt_label->setText (RKDebugHandler::instance ()->debugPrompt ());
+ reply_edit->setEnabled (true); // must come before focus
+ activate (true);
+ }
+
+ setEnabled (true);
+ step_button->setEnabled (enable);
+ continue_button->setEnabled (enable);
+ cancel_button->setEnabled (enable);
+}
+
+void RKDebugConsole::sendReply () {
+ RK_TRACE (APP);
+
+ sendReply (reply_edit->text ());
+ reply_edit->clear ();
+}
+
+void RKDebugConsole::stepButtonClicked () {
+ RK_TRACE (APP);
+
+ sendReply ("n\n");
+}
+
+void RKDebugConsole::continueButtonClicked () {
+ RK_TRACE (APP);
+
+ sendReply ("cont\n");
+}
+
+void RKDebugConsole::cancelButtonClicked () {
+ RK_TRACE (APP);
+
+ sendReply ("Q\n");
+}
+
+void RKDebugConsole::sendReply (const QString &reply) {
+ RK_TRACE (APP);
+
+ RKDebugHandler::instance ()->submitDebugString (reply);
+}
+
+bool RKDebugConsole::close (bool also_delete) {
+ RK_TRACE (APP);
+
+ if (RKDebugHandler::instance ()->state () != RKDebugHandler::NotInDebugger) {
+ KMessageBox::sorry (this, i18n ("This window cannot be closed, while a debugger is active. If you have no idea what this means, and you want to get out, press the 'Cancel' button on the right hand side of this window."));
+ return false;
+ }
+ return RKMDIWindow::close (also_delete);
+}
+
+#include "rkdebugconsole.moc"
Added: trunk/rkward/rkward/windows/rkdebugconsole.h
===================================================================
--- trunk/rkward/rkward/windows/rkdebugconsole.h (rev 0)
+++ trunk/rkward/rkward/windows/rkdebugconsole.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -0,0 +1,61 @@
+/***************************************************************************
+ rkdebugconsole - description
+ -------------------
+ begin : Wed Oct 19 2011
+ copyright : (C) 2011 by Thomas Friedrichsmeier
+ email : tfry at users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RKDEBUGCONSOLE_H
+#define RKDEBUGCONSOLE_H
+
+#include "rkmdiwindow.h"
+
+class QPushButton;
+class QLineEdit;
+class QTextEdit;
+class QLabel;
+
+/** A very simple debugger console */
+class RKDebugConsole : public RKMDIWindow {
+ Q_OBJECT
+public:
+ RKDebugConsole (QWidget *parent, bool tool_window, const char *name=0);
+ ~RKDebugConsole ();
+
+ static RKDebugConsole *instance () { return _instance; };
+
+ // reimplemented to refuse closing while inside the debugger
+ bool close (bool auto_delete);
+public slots:
+ void newDebugState ();
+private slots:
+ void sendReply ();
+ void stepButtonClicked ();
+ void continueButtonClicked ();
+ void cancelButtonClicked ();
+private:
+ void sendReply (const QString &reply);
+
+ QTextEdit* context_view;
+ QLineEdit* reply_edit;
+ QLabel* prompt_label;
+
+ QPushButton* step_button;
+ QPushButton* continue_button;
+ QPushButton* cancel_button;
+
+friend class RKWardMainWindow;
+ static RKDebugConsole *_instance;
+};
+
+#endif
Modified: trunk/rkward/rkward/windows/rkmdiwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkmdiwindow.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/rkmdiwindow.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -152,7 +152,12 @@
if (!isAttached ()) {
topLevelWidget ()->deleteLater ();
// flee the dying DetachedWindowContainer
- RKWorkplace::mainWorkplace ()->attachWindow (this);
+ if (tool_window_bar) RKWorkplace::mainWorkplace ()->attachWindow (this);
+ else {
+ state = Attached;
+ hide ();
+ setParent (0);
+ }
}
if (tool_window_bar) tool_window_bar->hideWidget (this);
Modified: trunk/rkward/rkward/windows/rkmdiwindow.h
===================================================================
--- trunk/rkward/rkward/windows/rkmdiwindow.h 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/rkmdiwindow.h 2011-10-20 09:37:56 UTC (rev 3975)
@@ -53,9 +53,11 @@
SearchHelpWindow=1 << 13,
PendingJobsWindow=1 << 14,
FileBrowserWindow=1 << 15,
+ DebugConsoleWindow=1 << 16,
+ CallstackViewerWindow=1 << 17,
- DocumentWindow=1 << 20,
- ToolWindow=1 << 21,
+ DocumentWindow=1 << 29,
+ ToolWindow=1 << 30,
AnyType=DocumentWindow | ToolWindow
};
Modified: trunk/rkward/rkward/windows/rktoolwindowbar.cpp
===================================================================
--- trunk/rkward/rkward/windows/rktoolwindowbar.cpp 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/rktoolwindowbar.cpp 2011-10-20 09:37:56 UTC (rev 3975)
@@ -170,6 +170,11 @@
widget_to_id.remove (widget);
widget->tool_window_bar = 0;
+ if (widget->isAttached ()) {
+ widget->setParent (0);
+ widget->hide ();
+ }
+
if (was_active_in_bar) {
RK_ASSERT (widget->isAttached ());
container->hide ();
@@ -237,7 +242,8 @@
RK_ASSERT (widget);
if (widget->isActive ()) {
- widget->close (false);
+ if (!widget->isAttached ()) widget->close (false);
+ else hideWidget (widget);
} else {
widget->activate (true);
}
Modified: trunk/rkward/rkward/windows/rktoplevelwindowgui.rc
===================================================================
--- trunk/rkward/rkward/windows/rktoplevelwindowgui.rc 2011-10-19 21:09:36 UTC (rev 3974)
+++ trunk/rkward/rkward/windows/rktoplevelwindowgui.rc 2011-10-20 09:37:56 UTC (rev 3975)
@@ -1,5 +1,5 @@
<!DOCTYPE kpartgui>
-<kpartgui name="rkward_toplevel" version="560">
+<kpartgui name="rkward_toplevel" version="580">
<MenuBar>
<Merge/>
<Menu name="window"><text>&Window</text>
@@ -16,6 +16,8 @@
<Action name="window_show_pendingjobs"/>
<Action name="window_show_console"/>
<Action name="window_show_helpsearch"/>
+ <Action name="window_show_debugconsole"/>
+ <Action name="window_show_debugframes"/>
<Separator/>
<Action name="window_activate_docview"/>
</Menu>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the rkward-tracker
mailing list