summaryrefslogtreecommitdiffstats
path: root/languages/cpp/debugger/gdboutputwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/cpp/debugger/gdboutputwidget.cpp')
-rw-r--r--languages/cpp/debugger/gdboutputwidget.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/languages/cpp/debugger/gdboutputwidget.cpp b/languages/cpp/debugger/gdboutputwidget.cpp
new file mode 100644
index 00000000..817f8692
--- /dev/null
+++ b/languages/cpp/debugger/gdboutputwidget.cpp
@@ -0,0 +1,376 @@
+// *************************************************************************
+// gdboutputwidget.cpp - description
+// -------------------
+// begin : 10th April 2003
+// copyright : (C) 2003 by John Birch
+// email : jbb@kdevelop.org
+// **************************************************************************
+//
+// **************************************************************************
+// * *
+// * 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 "gdboutputwidget.h"
+#include "dbgcontroller.h"
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtextedit.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdom.h>
+
+
+namespace GDBDebugger
+{
+
+/***************************************************************************/
+
+GDBOutputWidget::GDBOutputWidget( QWidget *parent, const char *name) :
+ QWidget(parent, name),
+ m_userGDBCmdEditor(0),
+ m_Interrupt(0),
+ m_gdbView(0),
+ showInternalCommands_(false),
+ maxLines_(5000)
+{
+
+ m_gdbView = new OutputText(this);
+ m_gdbView->setTextFormat(QTextEdit::LogText);
+
+ QBoxLayout *userGDBCmdEntry = new QHBoxLayout();
+ m_userGDBCmdEditor = new KHistoryCombo (this, "gdb-user-cmd-editor");
+
+ QLabel *label = new QLabel(i18n("&GDB cmd:"), this);
+ label->setBuddy(m_userGDBCmdEditor);
+ userGDBCmdEntry->addWidget(label);
+
+ userGDBCmdEntry->addWidget(m_userGDBCmdEditor);
+ userGDBCmdEntry->setStretchFactor(m_userGDBCmdEditor, 1);
+
+ m_Interrupt = new QToolButton( this, "add breakpoint" );
+ m_Interrupt->setSizePolicy ( QSizePolicy ( (QSizePolicy::SizeType)0,
+ ( QSizePolicy::SizeType)0,
+ 0,
+ 0,
+ m_Interrupt->sizePolicy().hasHeightForWidth())
+ );
+ m_Interrupt->setPixmap ( SmallIcon ( "player_pause" ) );
+ userGDBCmdEntry->addWidget(m_Interrupt);
+ QToolTip::add ( m_Interrupt, i18n ( "Pause execution of the app to enter gdb commands" ) );
+
+ QVBoxLayout *topLayout = new QVBoxLayout(this, 2);
+ topLayout->addWidget(m_gdbView, 10);
+ topLayout->addLayout(userGDBCmdEntry);
+
+ slotDbgStatus( "", s_dbgNotStarted);
+
+ connect( m_userGDBCmdEditor, SIGNAL(returnPressed()), SLOT(slotGDBCmd()) );
+ connect( m_Interrupt, SIGNAL(clicked()), SIGNAL(breakInto()));
+
+ connect( &updateTimer_, SIGNAL(timeout()),
+ this, SLOT(flushPending()));
+}
+
+/***************************************************************************/
+
+GDBOutputWidget::~GDBOutputWidget()
+{
+ delete m_gdbView;
+ delete m_userGDBCmdEditor;
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::clear()
+{
+ if (m_gdbView)
+ m_gdbView->clear();
+
+ userCommands_.clear();
+ allCommands_.clear();
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::slotInternalCommandStdout(const char* line)
+{
+ newStdoutLine(line, true);
+}
+
+void GDBOutputWidget::slotUserCommandStdout(const char* line)
+{
+ newStdoutLine(line, false);
+}
+
+namespace {
+ QString colorify(QString text, const QString& color)
+ {
+ // Make sure the newline is at the end of the newly-added
+ // string. This is so that we can always correctly remove
+ // newline inside 'flushPending'.
+ Q_ASSERT(text.endsWith("\n"));
+ if (text.endsWith("\n"))
+ {
+ text.remove(text.length()-1, 1);
+ }
+ text = "<font color=\"" + color + "\">" + text + "</font>\n";
+ return text;
+ }
+}
+
+
+void GDBOutputWidget::newStdoutLine(const QString& line,
+ bool internal)
+{
+ QString s = html_escape(line);
+ if (s.startsWith("(gdb)"))
+ {
+ s = colorify(s, "blue");
+ }
+
+ allCommands_.append(s);
+ allCommandsRaw_.append(line);
+ trimList(allCommands_, maxLines_);
+ trimList(allCommandsRaw_, maxLines_);
+
+ if (!internal)
+ {
+ userCommands_.append(s);
+ userCommandsRaw_.append(line);
+ trimList(userCommands_, maxLines_);
+ trimList(userCommandsRaw_, maxLines_);
+ }
+
+ if (!internal || showInternalCommands_)
+ showLine(s);
+}
+
+
+void GDBOutputWidget::showLine(const QString& line)
+{
+ pendingOutput_ += line;
+
+ // To improve performance, we update the view after some delay.
+ if (!updateTimer_.isActive())
+ {
+ updateTimer_.start(100, true /* single shot */);
+ }
+}
+
+void GDBOutputWidget::trimList(QStringList& l, unsigned max_size)
+{
+ unsigned int length = l.count();
+ if (length > max_size)
+ {
+ for(int to_delete = length - max_size; to_delete; --to_delete)
+ {
+ l.erase(l.begin());
+ }
+ }
+}
+
+void GDBOutputWidget::setShowInternalCommands(bool show)
+{
+ if (show != showInternalCommands_)
+ {
+ showInternalCommands_ = show;
+
+ // Set of strings to show changes, text edit still has old
+ // set. Refresh.
+ m_gdbView->clear();
+ QStringList& newList =
+ showInternalCommands_ ? allCommands_ : userCommands_;
+
+ QStringList::iterator i = newList.begin(), e = newList.end();
+ for(; i != e; ++i)
+ {
+ // Note that color formatting is already applied to '*i'.
+ showLine(*i);
+ }
+ }
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::slotReceivedStderr(const char* line)
+{
+ QString colored = colorify(html_escape(line), "red");
+ // Errors are shown inside user commands too.
+ allCommands_.append(colored);
+ trimList(allCommands_, maxLines_);
+ userCommands_.append(colored);
+ trimList(userCommands_, maxLines_);
+
+ allCommandsRaw_.append(line);
+ trimList(allCommandsRaw_, maxLines_);
+ userCommandsRaw_.append(line);
+ trimList(userCommandsRaw_, maxLines_);
+
+ showLine(colored);
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::slotGDBCmd()
+{
+ QString GDBCmd(m_userGDBCmdEditor->currentText());
+ if (!GDBCmd.isEmpty())
+ {
+ m_userGDBCmdEditor->addToHistory(GDBCmd);
+ m_userGDBCmdEditor->clearEdit();
+ emit userGDBCmd(GDBCmd);
+ }
+}
+
+void GDBOutputWidget::flushPending()
+{
+ m_gdbView->setUpdatesEnabled(false);
+
+ // QTextEdit adds newline after paragraph automatically.
+ // So, remove trailing newline to avoid double newlines.
+ if (pendingOutput_.endsWith("\n"))
+ pendingOutput_.remove(pendingOutput_.length()-1, 1);
+ Q_ASSERT(!pendingOutput_.endsWith("\n"));
+
+ m_gdbView->append(pendingOutput_);
+ pendingOutput_ = "";
+
+ m_gdbView->scrollToBottom();
+ m_gdbView->setUpdatesEnabled(true);
+ m_gdbView->update();
+ m_userGDBCmdEditor->setFocus();
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::slotDbgStatus(const QString &, int statusFlag)
+{
+ if (statusFlag & s_dbgNotStarted)
+ {
+ m_Interrupt->setEnabled(false);
+ m_userGDBCmdEditor->setEnabled(false);
+ return;
+ }
+ else
+ {
+ m_Interrupt->setEnabled(true);
+ }
+
+ if (statusFlag & s_dbgBusy)
+ {
+ m_userGDBCmdEditor->setEnabled(false);
+ }
+ else
+ {
+ m_userGDBCmdEditor->setEnabled(true);
+ }
+}
+
+/***************************************************************************/
+
+void GDBOutputWidget::focusInEvent(QFocusEvent */*e*/)
+{
+ m_gdbView->scrollToBottom();
+ m_userGDBCmdEditor->setFocus();
+}
+
+QString GDBOutputWidget::html_escape(const QString& s)
+{
+ QString r(s);
+ r.replace("<", "&lt;");
+ r.replace(">", "&gt;");
+ return r;
+}
+
+void GDBOutputWidget::savePartialProjectSession(QDomElement* el)
+{
+ QDomDocument doc = el->ownerDocument();
+
+ QDomElement showInternal = doc.createElement("showInternalCommands");
+ showInternal.setAttribute("value", QString::number(showInternalCommands_));
+
+ el->appendChild(showInternal);
+}
+
+void GDBOutputWidget::restorePartialProjectSession(const QDomElement* el)
+{
+ QDomElement showInternal =
+ el->namedItem("showInternalCommands").toElement();
+
+ if (!showInternal.isNull())
+ {
+ showInternalCommands_ = showInternal.attribute("value", "0").toInt();
+ }
+}
+
+
+//void OutputText::contextMenuEvent(QContextMenuEvent* e)
+QPopupMenu* OutputText::createPopupMenu(const QPoint&)
+{
+ KPopupMenu* popup = new KPopupMenu;
+
+ int id = popup->insertItem(i18n("Show Internal Commands"),
+ this,
+ SLOT(toggleShowInternalCommands()));
+
+ popup->setItemChecked(id, parent_->showInternalCommands_);
+ popup->setWhatsThis(
+ id,
+ i18n(
+ "Controls if commands issued internally by KDevelop "
+ "will be shown or not.<br>"
+ "This option will affect only future commands, it will not "
+ "add or remove already issued commands from the view."));
+
+ popup->insertItem(i18n("Copy All"),
+ this,
+ SLOT(copyAll()));
+
+
+ return popup;
+}
+
+void OutputText::copyAll()
+{
+ /* See comments for allCommandRaw_ for explanations of
+ this complex logic, as opposed to calling text(). */
+ QStringList& raw = parent_->showInternalCommands_ ?
+ parent_->allCommandsRaw_ : parent_->userCommandsRaw_;
+ QString text;
+ for (unsigned i = 0; i < raw.size(); ++i)
+ text += raw[i];
+
+ // Make sure the text is pastable both with Ctrl-C and with
+ // middle click.
+ QApplication::clipboard()->setText(text, QClipboard::Clipboard);
+ QApplication::clipboard()->setText(text, QClipboard::Selection);
+}
+
+void OutputText::toggleShowInternalCommands()
+{
+ parent_->setShowInternalCommands(!parent_->showInternalCommands_);
+}
+
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+}
+
+
+#include "gdboutputwidget.moc"
+