From e9ae80694875f869892f13f4fcaf1170a00dea41 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdewebdev@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- quanta/components/debugger/Makefile.am | 25 + quanta/components/debugger/backtracelistview.cpp | 128 ++ quanta/components/debugger/backtracelistview.h | 93 ++ .../debugger/conditionalbreakpointdialog.cpp | 100 ++ .../debugger/conditionalbreakpointdialog.h | 56 + .../debugger/conditionalbreakpointdialogs.ui | 329 ++++++ quanta/components/debugger/dbgp/Makefile.am | 17 + quanta/components/debugger/dbgp/dbgpnetwork.cpp | 314 +++++ quanta/components/debugger/dbgp/dbgpnetwork.h | 76 ++ quanta/components/debugger/dbgp/dbgpsettings.cpp | 44 + quanta/components/debugger/dbgp/dbgpsettings.h | 35 + quanta/components/debugger/dbgp/dbgpsettingss.ui | 728 ++++++++++++ quanta/components/debugger/dbgp/qbytearrayfifo.cpp | 76 ++ quanta/components/debugger/dbgp/qbytearrayfifo.h | 43 + .../debugger/dbgp/quantadebuggerdbgp.cpp | 1042 ++++++++++++++++ .../debugger/dbgp/quantadebuggerdbgp.desktop | 44 + .../components/debugger/dbgp/quantadebuggerdbgp.h | 166 +++ quanta/components/debugger/debuggerbreakpoint.cpp | 181 +++ quanta/components/debugger/debuggerbreakpoint.h | 85 ++ .../components/debugger/debuggerbreakpointlist.cpp | 193 +++ .../components/debugger/debuggerbreakpointlist.h | 58 + .../components/debugger/debuggerbreakpointview.cpp | 193 +++ .../components/debugger/debuggerbreakpointview.h | 74 ++ quanta/components/debugger/debuggermanager.cpp | 850 +++++++++++++ quanta/components/debugger/debuggermanager.h | 128 ++ quanta/components/debugger/debuggerui.cpp | 205 ++++ quanta/components/debugger/debuggerui.h | 90 ++ quanta/components/debugger/debuggervariable.cpp | 283 +++++ quanta/components/debugger/debuggervariable.h | 103 ++ quanta/components/debugger/debuggervariablesets.ui | 185 +++ quanta/components/debugger/gubed/Makefile.am | 18 + quanta/components/debugger/gubed/gubedsettings.cpp | 41 + quanta/components/debugger/gubed/gubedsettings.h | 36 + quanta/components/debugger/gubed/gubedsettingss.ui | 762 ++++++++++++ .../debugger/gubed/quantadebuggergubed.cpp | 1247 ++++++++++++++++++++ .../debugger/gubed/quantadebuggergubed.desktop | 48 + .../debugger/gubed/quantadebuggergubed.h | 153 +++ quanta/components/debugger/interfaces/Makefile.am | 17 + .../debugger/interfaces/debuggerclient.cpp | 160 +++ .../debugger/interfaces/debuggerclient.h | 115 ++ .../debugger/interfaces/debuggerinterface.cpp | 26 + .../debugger/interfaces/debuggerinterface.h | 80 ++ .../debugger/interfaces/quantadebugger.desktop | 45 + quanta/components/debugger/pathmapper.cpp | 228 ++++ quanta/components/debugger/pathmapper.h | 55 + quanta/components/debugger/pathmapperdialog.cpp | 102 ++ quanta/components/debugger/pathmapperdialog.h | 52 + quanta/components/debugger/pathmapperdialogs.ui | 345 ++++++ .../debugger/quantadebuggerinterface.cpp | 176 +++ .../components/debugger/quantadebuggerinterface.h | 75 ++ quanta/components/debugger/variableslistview.cpp | 290 +++++ quanta/components/debugger/variableslistview.h | 71 ++ 52 files changed, 10086 insertions(+) create mode 100644 quanta/components/debugger/Makefile.am create mode 100644 quanta/components/debugger/backtracelistview.cpp create mode 100644 quanta/components/debugger/backtracelistview.h create mode 100644 quanta/components/debugger/conditionalbreakpointdialog.cpp create mode 100644 quanta/components/debugger/conditionalbreakpointdialog.h create mode 100644 quanta/components/debugger/conditionalbreakpointdialogs.ui create mode 100644 quanta/components/debugger/dbgp/Makefile.am create mode 100644 quanta/components/debugger/dbgp/dbgpnetwork.cpp create mode 100644 quanta/components/debugger/dbgp/dbgpnetwork.h create mode 100644 quanta/components/debugger/dbgp/dbgpsettings.cpp create mode 100644 quanta/components/debugger/dbgp/dbgpsettings.h create mode 100644 quanta/components/debugger/dbgp/dbgpsettingss.ui create mode 100644 quanta/components/debugger/dbgp/qbytearrayfifo.cpp create mode 100644 quanta/components/debugger/dbgp/qbytearrayfifo.h create mode 100644 quanta/components/debugger/dbgp/quantadebuggerdbgp.cpp create mode 100644 quanta/components/debugger/dbgp/quantadebuggerdbgp.desktop create mode 100644 quanta/components/debugger/dbgp/quantadebuggerdbgp.h create mode 100644 quanta/components/debugger/debuggerbreakpoint.cpp create mode 100644 quanta/components/debugger/debuggerbreakpoint.h create mode 100644 quanta/components/debugger/debuggerbreakpointlist.cpp create mode 100644 quanta/components/debugger/debuggerbreakpointlist.h create mode 100644 quanta/components/debugger/debuggerbreakpointview.cpp create mode 100644 quanta/components/debugger/debuggerbreakpointview.h create mode 100644 quanta/components/debugger/debuggermanager.cpp create mode 100644 quanta/components/debugger/debuggermanager.h create mode 100644 quanta/components/debugger/debuggerui.cpp create mode 100644 quanta/components/debugger/debuggerui.h create mode 100644 quanta/components/debugger/debuggervariable.cpp create mode 100644 quanta/components/debugger/debuggervariable.h create mode 100644 quanta/components/debugger/debuggervariablesets.ui create mode 100644 quanta/components/debugger/gubed/Makefile.am create mode 100644 quanta/components/debugger/gubed/gubedsettings.cpp create mode 100644 quanta/components/debugger/gubed/gubedsettings.h create mode 100644 quanta/components/debugger/gubed/gubedsettingss.ui create mode 100644 quanta/components/debugger/gubed/quantadebuggergubed.cpp create mode 100644 quanta/components/debugger/gubed/quantadebuggergubed.desktop create mode 100644 quanta/components/debugger/gubed/quantadebuggergubed.h create mode 100644 quanta/components/debugger/interfaces/Makefile.am create mode 100644 quanta/components/debugger/interfaces/debuggerclient.cpp create mode 100644 quanta/components/debugger/interfaces/debuggerclient.h create mode 100644 quanta/components/debugger/interfaces/debuggerinterface.cpp create mode 100644 quanta/components/debugger/interfaces/debuggerinterface.h create mode 100644 quanta/components/debugger/interfaces/quantadebugger.desktop create mode 100644 quanta/components/debugger/pathmapper.cpp create mode 100644 quanta/components/debugger/pathmapper.h create mode 100644 quanta/components/debugger/pathmapperdialog.cpp create mode 100644 quanta/components/debugger/pathmapperdialog.h create mode 100644 quanta/components/debugger/pathmapperdialogs.ui create mode 100644 quanta/components/debugger/quantadebuggerinterface.cpp create mode 100644 quanta/components/debugger/quantadebuggerinterface.h create mode 100644 quanta/components/debugger/variableslistview.cpp create mode 100644 quanta/components/debugger/variableslistview.h (limited to 'quanta/components/debugger') diff --git a/quanta/components/debugger/Makefile.am b/quanta/components/debugger/Makefile.am new file mode 100644 index 00000000..f24e455d --- /dev/null +++ b/quanta/components/debugger/Makefile.am @@ -0,0 +1,25 @@ +SUBDIRS = interfaces gubed dbgp +METASOURCES = AUTO + + +noinst_LTLIBRARIES = libdebuggermanager.la + +libdebuggermanager_la_LDFLAGS = $(all_libraries) +libdebuggermanager_la_LIBADD = interfaces/libdebuggerinterface.la +libdebuggermanager_la_SOURCES = debuggermanager.cpp debuggerbreakpoint.cpp \ + quantadebuggerinterface.cpp debuggervariable.cpp debuggerui.cpp variableslistview.cpp \ + debuggerbreakpointlist.cpp debuggervariablesets.ui debuggerbreakpointview.cpp pathmapper.cpp \ + pathmapperdialogs.ui pathmapperdialog.cpp pathmapperdialog.h conditionalbreakpointdialogs.ui \ + conditionalbreakpointdialog.cpp conditionalbreakpointdialog.h backtracelistview.cpp + +AM_CPPFLAGS = -I$(top_srcdir)/quanta/components/debuggerquanta \ + -I$(top_srcdir)/quanta/components/debugger/interfaces \ + -I$(top_srcdir)/quanta/project \ + -I$(top_srcdir)/quanta/utility \ + -I$(top_srcdir)/quanta/src \ + -I$(top_srcdir)/quanta/parsers \ + -I$(top_srcdir)/quanta/parts/preview \ + -I$(top_srcdir)/quanta/messages \ + -I$(top_srcdir)/lib \ + $(KMDI_INCLUDES) $(all_includes) +noinst_HEADERS = pathmapper.h backtracelistview.h diff --git a/quanta/components/debugger/backtracelistview.cpp b/quanta/components/debugger/backtracelistview.cpp new file mode 100644 index 00000000..aa5c8c95 --- /dev/null +++ b/quanta/components/debugger/backtracelistview.cpp @@ -0,0 +1,128 @@ +/*************************************************************************** + backtracelistview.cpp + -------------------------- + begin : 2005-07-31 + copyright : (C) 2005 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// KDE Includes +#include +#include +#include +#include +#include + +// Quanta includes +#include "backtracelistview.h" +#include "debuggerclient.h" +#include "debuggermanager.h" +#include "resource.h" +#include "quanta.h" + +namespace BacktraceListviewColumns +{ + // The enums must correspond to the order of the columns + // If you change here, change the column adding + enum Columns + { + Level = 0, + Type, + File, + Line, + Function + }; +} + +BacktraceListviewItem::BacktraceListviewItem(BacktraceListview* view) + : KListViewItem(view) +{ +} + + +BacktraceListview::BacktraceListview(QWidget *parent, const char *name) + : KListView(parent, name) +{ + int charwidth = this->fontMetrics().width("0"); + // If you change the order here, change the BacktraceListviewColumns enums above + addColumn("#", charwidth * 3); + addColumn(i18n("Type"), charwidth * 10); + addColumn(i18n("File"), charwidth * 60); + addColumn(i18n("Line"), charwidth * 6); + addColumn(i18n("Function"), charwidth * 30); + + setSorting(BacktraceListviewColumns::Level); // Sort on the level column + setAllColumnsShowFocus(true); + + // Jump to bt + connect(this, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int) ), this, SLOT(slotBacktraceDoubleClick( QListViewItem *, const QPoint &, int))); +} + + +BacktraceListview::~BacktraceListview() +{} + +void BacktraceListview::backtraceShow(int level, BacktraceType type, const QString& filename, long line, const QString& func) +{ + BacktraceListviewItem* item = new BacktraceListviewItem(this); + item->setLevel(level); + item->setType(type); + item->setFilename(filename); + item->setLine(line); + item->setFunc(func); + + item->setText(BacktraceListviewColumns::File, filename); + item->setText(BacktraceListviewColumns::Function, func); + item->setText(BacktraceListviewColumns::Level, QString::number(level)); + item->setText(BacktraceListviewColumns::Line, QString::number(line + 1)); + item->setText(BacktraceListviewColumns::Type, type == File ? i18n("File") : i18n("Eval")); + + insertItem(item); +} + +void BacktraceListview::keyPressEvent(QKeyEvent *e) +{ + if(e->key() != Qt::Key_Enter) + { + e->ignore(); + return; + } + + if(selectedItem()) + jumpHistory(selectedItem()); +} + +void BacktraceListview::clear() +{ + KListView::clear(); +} + +void BacktraceListview::slotBacktraceDoubleClick(QListViewItem *item, const QPoint &, int ) +{ + if(!item) + return; + + jumpHistory(item); +} + +void BacktraceListview::jumpHistory(QListViewItem *item) +{ + BacktraceListviewItem* btitem = dynamic_cast(item); + + if(btitem->type() == File) + { + quantaApp->gotoFileAndLine(btitem->filename(), btitem->line(), 0); + } + +} + +#include "backtracelistview.moc" diff --git a/quanta/components/debugger/backtracelistview.h b/quanta/components/debugger/backtracelistview.h new file mode 100644 index 00000000..e00d0afc --- /dev/null +++ b/quanta/components/debugger/backtracelistview.h @@ -0,0 +1,93 @@ +/*************************************************************************** + Backtracelistview.h + ------------------------ + begin : 2005-07-31 + copyright : (C) 2005 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 BACKTRACELISTVIEW_H +#define BACKTRACELISTVIEW_H + +#include +#include +#include + +class BacktraceListview; + + +enum BacktraceType +{ + File = 0, + Eval +}; + + +class BacktraceListviewItem : public KListViewItem +{ + private: + BacktraceType m_type; + QString m_filename; + QString m_func; + long m_line; + long m_level; + + public: + BacktraceListviewItem(); + BacktraceListviewItem(BacktraceListview* view); + + // Type + BacktraceType type() const { return m_type; } + void setType(BacktraceType type) { m_type = type; } + + // Filename + QString filename() const { return m_filename; } + void setFilename(const QString &filename) { m_filename = filename; } + + // Function + QString func() const { return m_func; } + void setFunc(const QString &func) { m_func = func; } + + // Line + long line() const { return m_line; } + void setLine(long line) { m_line= line; } + + // Level + long level() const { return m_level; } + void setLevel(long level) { m_level = level; } + +}; + +class BacktraceListview : public KListView +{ + Q_OBJECT + + public: + + BacktraceListview(QWidget *parent = 0, const char *name = 0); + ~BacktraceListview(); + + void backtraceShow(int level, BacktraceType type, const QString& filename, long line, const QString& func); + + void clear(); + + public slots: + void slotBacktraceDoubleClick(QListViewItem *item, const QPoint &point, int column); + + private: + void keyPressEvent(QKeyEvent *e); + void jumpHistory(QListViewItem *item); + +}; + +#endif diff --git a/quanta/components/debugger/conditionalbreakpointdialog.cpp b/quanta/components/debugger/conditionalbreakpointdialog.cpp new file mode 100644 index 00000000..943c33d4 --- /dev/null +++ b/quanta/components/debugger/conditionalbreakpointdialog.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + conditionalbreakpointdialog.cpp + -------------------- + begin : 2005-01-08 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "conditionalbreakpointdialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debuggerbreakpoint.h" + +ConditionalBreakpointDialog::ConditionalBreakpointDialog(const QString& expression, const QString& inFile, const QString& inClass, const QString& inFunction) + : ConditionalBreakpointDialogS(0, "ConditionalBreakpointDialog", false, 0) +{ + comboExpression->setCurrentText(expression); + lineFile->setText(inFile); + lineClass->setText(inClass); + lineFunction->setText(inFunction); + + buttonClearFile->setPixmap(SmallIcon("clear_left")); + buttonClearClass->setPixmap(SmallIcon("clear_left")); + buttonClearFunction->setPixmap(SmallIcon("clear_left")); + + connect(comboExpression, SIGNAL(textChanged(const QString&)), this, SLOT(slotExpressionChanged())); + + connect(buttonClearFile, SIGNAL(pressed()), this, SLOT(slotClearFile())); + connect(buttonClearClass, SIGNAL(pressed()), this, SLOT(slotClearClass())); + connect(buttonClearFunction, SIGNAL(pressed()), this, SLOT(slotClearFunction())); + + slotExpressionChanged(); +} + +ConditionalBreakpointDialog::~ConditionalBreakpointDialog() +{ +} + +void ConditionalBreakpointDialog::slotExpressionChanged() +{ + + if(comboExpression->currentText().find( QRegExp("[^=!]=[^=]"), 0 ) >= 0) + ledWarning->on(); + else + ledWarning->off(); + +} + +void ConditionalBreakpointDialog::slotClearFile() +{ + lineFile->setText(""); +} + +void ConditionalBreakpointDialog::slotClearClass() +{ + lineClass->setText(""); +} + +void ConditionalBreakpointDialog::slotClearFunction() +{ + lineFunction->setText(""); +} + +/*DebuggerBreakpoint::Types type()*/ + +DebuggerBreakpoint *ConditionalBreakpointDialog::breakpoint() +{ + if(comboExpression->currentText().isEmpty()) + return NULL; + + DebuggerBreakpoint *bp = new DebuggerBreakpoint( + (radioOnChange->isChecked() ? DebuggerBreakpoint::ConditionalChange : DebuggerBreakpoint::ConditionalTrue), + comboExpression->currentText(), + lineFile->text(), + lineClass->text(), + lineFunction->text()); + + return bp; +} + + +#include "conditionalbreakpointdialog.moc" + diff --git a/quanta/components/debugger/conditionalbreakpointdialog.h b/quanta/components/debugger/conditionalbreakpointdialog.h new file mode 100644 index 00000000..fdae39a3 --- /dev/null +++ b/quanta/components/debugger/conditionalbreakpointdialog.h @@ -0,0 +1,56 @@ +/*************************************************************************** + conditionalbreakpointdialog.h + ------------------ + begin : 2004-04-05 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 CONDITIONALBREAKPOINTDIALOG_H +#define CONDITIONALBREAKPOINTDIALOG_H + +#include "conditionalbreakpointdialogs.h" +#include "debuggerbreakpoint.h" + +class ConditionalBreakpointDialog : public ConditionalBreakpointDialogS +{ + Q_OBJECT + + public: + enum Break + { + OnTrue = 0, + OnChange + }; + + ConditionalBreakpointDialog(const QString& expression, const QString& inFile, const QString& inClass, const QString& inFunction); + ~ConditionalBreakpointDialog(); + +// QString expression(); +// QString inFile(); +// QString inClass(); +// QString inFunction(); +// DebuggerBreakpoint::Types type(); + + DebuggerBreakpoint *breakpoint(); + + public slots: + void slotExpressionChanged(); + void slotClearFile(); + void slotClearClass(); + void slotClearFunction(); + + private: + +}; + +#endif // CONDITIONALBREAKPOINTDIALOG_H + diff --git a/quanta/components/debugger/conditionalbreakpointdialogs.ui b/quanta/components/debugger/conditionalbreakpointdialogs.ui new file mode 100644 index 00000000..8e4a1bf2 --- /dev/null +++ b/quanta/components/debugger/conditionalbreakpointdialogs.ui @@ -0,0 +1,329 @@ + +ConditionalBreakpointDialogS + + + ConditionalBreakpointDialogS + + + + 0 + 0 + 564 + 432 + + + + Add Conditional Breakpoint + + + true + + + + unnamed + + + + lblExpression + + + + 4 + 5 + 0 + 0 + + + + Expression: + + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + &Cancel + + + + + + true + + + + + + + buttonGroup1 + + + Break When + + + + unnamed + + + + radioOnTrue + + + When expression is true + + + + + radioOnChange + + + When expression changes + + + true + + + + + + + spacer8 + + + Vertical + + + Expanding + + + + 30 + 20 + + + + + + comboExpression + + + true + + + + + ledWarning + + + + 22 + 22 + + + + + 22 + 22 + + + + Off + + + + 255 + 0 + 0 + + + + Lit when a finding a single equal sign in expression (common error) + + + + + groupBox10 + + + Only Break In + + + + unnamed + + + + lblValue + + + + 5 + 5 + 0 + 0 + + + + File: + + + AlignVCenter + + + + + lblValue_2 + + + + 5 + 5 + 0 + 0 + + + + Objects of class: + + + AlignVCenter + + + + + lblValue_3 + + + + 5 + 5 + 0 + 0 + + + + Function: + + + AlignVCenter + + + + + lineFile + + + + + lineFunction + + + + + buttonClearFile + + + x + + + + + buttonClearFunction + + + x + + + + + buttonClearClass + + + x + + + + + lineClass + + + + + + + + + + + buttonOk + clicked() + ConditionalBreakpointDialogS + accept() + + + buttonCancel + clicked() + ConditionalBreakpointDialogS + reject() + + + + buttonOk + buttonCancel + + + + kcombobox.h + klineedit.h + kled.h + + diff --git a/quanta/components/debugger/dbgp/Makefile.am b/quanta/components/debugger/dbgp/Makefile.am new file mode 100644 index 00000000..fbff3bdf --- /dev/null +++ b/quanta/components/debugger/dbgp/Makefile.am @@ -0,0 +1,17 @@ +METASOURCES = AUTO + +kde_module_LTLIBRARIES = quantadebuggerdbgp.la + +quantadebuggerdbgp_la_SOURCES = quantadebuggerdbgp.cpp dbgpsettingss.ui \ + dbgpsettings.cpp dbgpnetwork.cpp qbytearrayfifo.cpp +quantadebuggerdbgp_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +quantadebuggerdbgp_la_LIBADD = ../interfaces/libdebuggerinterface.la $(LIB_KPARTS) +kde_services_DATA = quantadebuggerdbgp.desktop + +INCLUDES = -I$(top_srcdir)/quanta/components/debugger \ + -I$(top_srcdir)/quanta/components/debugger/interfaces -I$(top_srcdir)/quanta/components/debugger/dbgp \ + -I$(top_srcdir)/quanta/project -I$(top_srcdir)/quanta/utility $(all_includes) + + +noinst_HEADERS = dbgpsettings.h quantadebuggerdbgp.h dbgpnetwork.h \ + qbytearrayfifo.h diff --git a/quanta/components/debugger/dbgp/dbgpnetwork.cpp b/quanta/components/debugger/dbgp/dbgpnetwork.cpp new file mode 100644 index 00000000..87306448 --- /dev/null +++ b/quanta/components/debugger/dbgp/dbgpnetwork.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2005 by Linus McCabe, + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbgpnetwork.h" + +#include +#include +#include +#include + +DBGpNetwork::DBGpNetwork() +: QObject() +{ + m_socket = NULL; + m_server = NULL; + m_datalen = -1; + m_transaction_id = 0; +} + +DBGpNetwork::~DBGpNetwork() +{ +} + +void DBGpNetwork::sessionStart(bool useproxy, const QString& server, const QString & service) +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + m_useproxy = useproxy; + + if(m_useproxy) + { + if(m_socket) + { +// m_socket->setBufferSize(-1); + connect(m_socket, SIGNAL(gotError(int)), this, SLOT(slotError(int))); + connect(m_socket, SIGNAL(connected(const KResolverEntry &)), this, SLOT(slotConnected(const KNetwork::KResolverEntry &))); + connect(m_socket, SIGNAL(closed()), this, SLOT(slotConnectionClosed())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + connect(m_socket, SIGNAL(destroyed()), this, SLOT(slotSocketDestroyed())); + m_socket->connect(); + emit active(false); + kdDebug(24002) << k_funcinfo << ", proxy:" << server << ", " << service << endl; + } + } + else + { + if(!m_server) + { + m_server = new KNetwork::KServerSocket(service); + + m_server->setAddressReuseable(true); + connect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + connect(m_server, SIGNAL(gotError(int)), this, SLOT(slotError(int))); + + if(m_server->listen()) + { + emit active(true); + emit networkError(i18n("Listening on port %1").arg(service), true); + } + else + { + delete m_server; + m_server = NULL; + emit active(false); + emit networkError(i18n("Unable to listen on port %1").arg(service), true); + } + } + } +} + + +void DBGpNetwork::sessionEnd() +{ + // Close socket + if(m_socket) + { + m_socket->flush(); + disconnect(m_socket, SIGNAL(closed()), this, SLOT(slotConnectionClosed())); + if (m_socket) + m_socket->close(); + delete m_socket; + m_socket = 0L; + } + + // Close the server + if(m_server) + { + m_server->close(); + delete m_server; + m_server = NULL; + } + + // Fake a connection closed signal + slotConnectionClosed(); + emit active(false); +} + + +// Socket errors +void DBGpNetwork::slotError(int) +{ + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + if(m_socket) + { + kdDebug(24002) << k_funcinfo << ", " << m_socket->errorString() << endl; + if(m_socket->error() == KNetwork::KSocketBase::RemotelyDisconnected) + { + slotConnectionClosed(); + emit networkError(i18n("Disconnected from remote host"), true); + return; + } + + if(m_socket->error()) + { + emit networkError(m_socket->errorString(), true); + } + } + + if(m_server && m_server->error()) + { + kdDebug(24002) << k_funcinfo << ", " << m_server->errorString() << endl; + emit networkError(m_server->errorString(), true); + } +} + +// slotReadyAccept +void DBGpNetwork::slotReadyAccept() +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + if(!m_socket) + { + disconnect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + + m_socket = (KNetwork::KStreamSocket *)m_server->accept(); // KSocketServer returns a KStreamSocket (!) + if(m_socket) + { + kdDebug(24002) << k_funcinfo << ", ready" << ", m_socket" << m_socket << endl; + m_socket->enableRead(true); + m_socket->setAddressReuseable(true); +// m_socket->setSocketFlags(KExtendedSocket::inetSocket | KExtendedSocket::inputBufferedSocket); +// m_socket->setBufferSize(-1); + connect(m_socket, SIGNAL(gotError(int)), this, SLOT(slotError(int))); + connect(m_socket, SIGNAL(connected(const KResolverEntry &)), this, SLOT(slotConnected(const KResolverEntry &))); + connect(m_socket, SIGNAL(closed()), this, SLOT(slotConnectionClosed())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + connected(); + } + else + { + kdDebug(24002) << k_funcinfo << ", " << m_server->errorString() << endl; + } + } + +} + +// Connection established +void DBGpNetwork::slotConnected(const KResolverEntry &) +{ + connected(); +} + +bool DBGpNetwork::isConnected() +{ + return m_socket != NULL && m_socket->state() == KNetwork::KClientSocketBase::Connected; +} + +bool DBGpNetwork::isActive() +{ + return + (m_socket != NULL && m_socket->state() == KNetwork::KClientSocketBase::Connected) + || (m_server != NULL); +} + +void DBGpNetwork::connected() +{ + + kdDebug(24002) << k_funcinfo << endl; + emit connected(true); +// debuggerInterface()->enableAction("debug_disconnect", true); +// debuggerInterface()->enableAction("debug_request", false); +} + +// Connectio closed +void DBGpNetwork::slotConnectionClosed() +{ + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + + // Check if we have more data to read + slotReadyRead(); +// kdDebug(24002) << k_funcinfo << "buffer: " << m_buffer << endl; + + if(m_socket) + { + m_socket->flush(); + m_socket->close(); + delete m_socket; + m_socket = NULL; + } + + if(m_server) + connect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + + // Disable all session related actions and enable connection action + emit connected(false); + emit active(m_server != NULL); + +} + + +//called when m_socket is destroyed either by deleting it or if XDebug disconnects from the client +void DBGpNetwork::slotSocketDestroyed() +{ + kdDebug(24002) << k_funcinfo << " , m_server: " << m_server << ", m_socket" << m_socket << endl; + + m_socket = NULL; //m_socket is already wrong, without this the app would crash on the next m_socket->close() or delete m_socket call. + slotConnectionClosed(); +} + + +// Data from socket +void DBGpNetwork::slotReadyRead() +{ + + // Data from dbgp + while(m_socket && (m_socket->bytesAvailable() > 0 || m_fifo.length() >= (unsigned long)m_datalen)) + { + int bytes; + QString data; + + if(m_socket && m_socket->bytesAvailable() > 0 ) + { + // Read all available bytes from socket and append them to the buffer + bytes = m_socket->bytesAvailable(); + char* buffer = new char[bytes]; + m_socket->readBlock(buffer, bytes); + + // Put it in the fifo buffer + m_fifo.append(buffer, bytes); + + delete[] buffer; + } + + while(1) + { + // If datalen == -1, we didnt read the size yet, otherwise we're reading data. + if(m_datalen == -1) + { + bytes = m_fifo.find('\0'); + if(bytes < 0) + break; + + data = m_fifo.retrieve(); + m_datalen = data.toLong(); + + } + if(m_datalen != -1 && (long)m_fifo.length() >= m_datalen + 1) + { + data = m_fifo.retrieve(); + m_datalen = -1; + emit command(data); + } + else + break; + } + } +} + +long DBGpNetwork::sendCommand(const QString & command) +{ + return sendCommand(command, ""); +} + +long DBGpNetwork::sendCommand(const QString & command, const QString & arguments) +{ + if(!isConnected()) + return false; + + m_transaction_id++; + QString commandline = command + QString(" -i %1").arg(m_transaction_id) + (!arguments.isEmpty() ? " " : "") + arguments; + + kdDebug(24002) << k_funcinfo << ", sending: " << commandline << endl; + + m_socket->writeBlock(commandline.latin1(), commandline.length() + 1); // Send string + NULL termination + + return m_transaction_id; +} + +long DBGpNetwork::sendCommand( const QString & command, const QString & arguments, const QString & data ) +{ + QByteArrayFifo buffer; + buffer.append(data.ascii(), data.length()); + return sendCommand(command, arguments + " -- " + buffer.base64Encoded()); +} + +// #include "dbgpnetwork.moc" + +#include "dbgpnetwork.moc" diff --git a/quanta/components/debugger/dbgp/dbgpnetwork.h b/quanta/components/debugger/dbgp/dbgpnetwork.h new file mode 100644 index 00000000..0651bc08 --- /dev/null +++ b/quanta/components/debugger/dbgp/dbgpnetwork.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005 by Linus McCabe, + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef dbgpnetwork_H +#define dbgpnetwork_H + +#include +#include + +#include "qbytearrayfifo.h" + +//using namespace KNetwork; +class KResolverEntry; + +class DBGpNetwork : public QObject +{ + Q_OBJECT + + private: + KNetwork::KStreamSocket *m_socket; + KNetwork::KServerSocket *m_server; + QByteArrayFifo m_fifo; + bool m_useproxy; + long m_datalen; + long m_transaction_id; + + void connected(); + + signals: + void active(bool isOnline); + void connected(bool isConnected); + void networkError(const QString &error, bool log); + void command(const QString& data); + + public: + DBGpNetwork(); + ~DBGpNetwork(); + + virtual void sessionStart(bool useproxy, const QString& server, const QString & service); + virtual void sessionEnd(); + + bool isConnected(); + bool isActive(); + + long sendCommand(const QString & command); + long sendCommand(const QString & command, const QString & arguments); + long sendCommand(const QString & command, const QString & arguments, const QString & data); + + public slots: + // Socket slots + void slotConnected(const KResolverEntry &); + void slotConnectionClosed(); + void slotError(int); + void slotReadyRead(); + void slotReadyAccept(); + void slotSocketDestroyed(); +}; + + +#endif // dbgpnetwork_H diff --git a/quanta/components/debugger/dbgp/dbgpsettings.cpp b/quanta/components/debugger/dbgp/dbgpsettings.cpp new file mode 100644 index 00000000..80b7eaf1 --- /dev/null +++ b/quanta/components/debugger/dbgp/dbgpsettings.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + dbgpsettings.cpp + ------------------- + begin : 2004-04-05 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "qlineedit.h" +#include "qcheckbox.h" +#include "dbgpsettings.h" +#include + +DBGpSettings::DBGpSettings(const QString &protocolversion) + : DBGpSettingsS(0, "DBGpSettings", false, 0) +{ + textAbout->setText(textAbout->text().replace("%PROTOCOLVERSION%", protocolversion)); + connect(checkLocalProject, SIGNAL(toggled(bool)), this, SLOT(slotLocalProjectToggle(bool))); +} + +DBGpSettings::~DBGpSettings() +{ +} + +void DBGpSettings::slotLocalProjectToggle( bool localproject) +{ + lineServerBasedir->setEnabled(!localproject); + lineLocalBasedir->setEnabled(!localproject); +} + + + + +#include "dbgpsettings.moc" + diff --git a/quanta/components/debugger/dbgp/dbgpsettings.h b/quanta/components/debugger/dbgp/dbgpsettings.h new file mode 100644 index 00000000..4f2721ff --- /dev/null +++ b/quanta/components/debugger/dbgp/dbgpsettings.h @@ -0,0 +1,35 @@ +/*************************************************************************** + dbgpsettings.h + ------------------- + begin : 2005-08-01 + copyright : (C) 2005 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DBGPSETTINGS_H +#define DBGPSETTINGS_H + +#include "dbgpsettingss.h" + +class DBGpSettings : public DBGpSettingsS +{ + Q_OBJECT + + public: + DBGpSettings(const QString &protocolversion); + ~DBGpSettings(); + + public slots: + virtual void slotLocalProjectToggle(bool localproject); +}; + +#endif + diff --git a/quanta/components/debugger/dbgp/dbgpsettingss.ui b/quanta/components/debugger/dbgp/dbgpsettingss.ui new file mode 100644 index 00000000..2b846a7e --- /dev/null +++ b/quanta/components/debugger/dbgp/dbgpsettingss.ui @@ -0,0 +1,728 @@ + +DBGpSettingsS + + + DBGpSettingsS + + + + 0 + 0 + 569 + 467 + + + + DBGp Settings + + + true + + + + unnamed + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + Ca&ncel + + + true + + + + + + + tabWidget2 + + + true + + + + 5 + 5 + 1 + 1 + + + + + tab + + + &General + + + + unnamed + + + + groupBox2 + + + Connection Settings + + + + unnamed + + + + lblDebuggerServerListenPort + + + + 5 + 5 + 1 + 0 + + + + Listen port: + + + + + lineServerListenPort + + + + 7 + 0 + 4 + 0 + + + + + + lblRequest + + + + 5 + 5 + 1 + 0 + + + + Request URL: + + + + + lineStartSession + + + + 7 + 0 + 4 + 0 + + + + See "What's This?" for available variables + + + %afn - Filename of the current script +%afd - Absolute directory of the current script +%afp - Absolute path (directory + filename) of the current script + +%rfpd - Directory of the current script relative to project root +%rfpp - Path of the current script relative to project root + +%rfdd - Directory of the current script relative to document root +%rfdp - Path of the current script relative to document root + +%apd - Project root +%add - Document root of current script + + + + + + + spacer4 + + + Vertical + + + Expanding + + + + 21 + 40 + + + + + + groupBox1 + + + Directory Mapping + + + + unnamed + + + + lineServerBasedir + + + + 7 + 0 + 4 + 0 + + + + + + lblDebuggerServerBasedir + + + + 5 + 5 + 1 + 0 + + + + Server basedir: + + + + + lineLocalBasedir + + + + 7 + 0 + 4 + 0 + + + + + + + + + checkLocalProject + + + + 1 + 0 + 4 + 0 + + + + + + + + + + + + lblDebuggerLocalBasedir + + + + 5 + 5 + 1 + 0 + + + + Local basedir: + + + + + lblLocalProject + + + + 5 + 5 + 1 + 0 + + + + Local project: + + + + + + + groupBox3_2 + + + Profiling + + + + unnamed + + + + lineProfilerFilename + + + + 7 + 0 + 4 + 0 + + + + See "What's This?" for available variables + + + Path to the profiler output +%a - Appid as returned from the debugger +%c - CRC32 of the initial filepath + + + + + lblRequest_2 + + + + 5 + 5 + 1 + 0 + + + + Profiler output: + + + + + lblLocalProject_2 + + + + 5 + 5 + 1 + 0 + + + + Map profiler output: + + + + + checkProfilerMapFilename + + + + 1 + 0 + 4 + 0 + + + + + + + + + + If this checkbox is checked, the profiler output filename will be mapped using the basedirs just like the remote script files. + + + + + lblLocalProject_2_2 + + + + 5 + 5 + 1 + 0 + + + + Open automatically: + + + + + checkProfilerAutoOpen + + + + 1 + 0 + 4 + 0 + + + + + + + + + + If this checkbox is checked, the profiler output will be opened automatically once the session ends. + + + + + + + + + tab + + + Deb&ug Behavior + + + + unnamed + + + + groupBox4 + + + Error Handling + + + + unnamed + + + + checkBreakOnUserError + + + + 7 + 0 + 0 + 0 + + + + User errors + + + + + lblBreakOn + + + Break on: + + + AlignTop + + + + + checkBreakOnUserWarning + + + + 7 + 0 + 0 + 0 + + + + User warnings + + + + + checkBreakOnUserNotice + + + + 7 + 0 + 0 + 0 + + + + User notices + + + + + checkBreakOnNotice + + + + 7 + 0 + 0 + 0 + + + + Notices + + + + + checkBreakOnWarning + + + + 7 + 0 + 0 + 0 + + + + W&arnings + + + + + + + groupBox5 + + + Execution + + + + unnamed + + + + + Pause + + + image0 + + + + + Run + + + image1 + + + + comboDefaultExecutionState + + + + + lblDefaultExecutionMode + + + Default mode: + + + AlignVCenter + + + + + + + spacer4_3 + + + Vertical + + + Expanding + + + + 21 + 40 + + + + + + + + TabPage + + + &About + + + + unnamed + + + + textLabel1 + + + + 5 + 4 + 0 + 0 + + + + <h4>DBGp Plugin for Quanta +</h4> + + + + + textAbout + + + true + + + <html><head><meta name="qrichtext" content="1" /></head><body style="font-size:10pt;font-family:Bitstream Vera Sans"> +<p><span style="font-weight:600">About</span></p> +<p>DBGp is a debugger protocol defined by the developers of Xdebug. This plugin integrates debuggers that supports the DBGp protocol with Quanta. </p> +<p>In order to use this plugin for PHP debugging, you need to get a supporting debugger. Currently, only <a href="http://xdebug.org">Xdebug</a> is tested.</p> +<p>For more info about Xdebug, please visit the Xdebug website at <a href="http://xdebug.org">http://xdebug.org</a> </p> +<p><span style="font-weight:600">Technical Details</span></p> +<p>This version of the debugger supports version %PROTOCOLVERSION% of the DBGp protocol. </p> +</body></html> + + + + + + + + + + 89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff610000027f49444154388d7d93df4b53611cc69ff73de7ccb375dcdad46d2e3269036d21c4420a0b898484e82a08a2a02238a41741dd77e14dff4074d521efbae8a61b2f6a892062604e53117165e28f864dd73adb999e3cdb79cfe9c25a9c4dfa5e3e3ccfe7fdfee02538a412830b226075c3b662804d006b9567a5d4b4d2a7d77a494d5002c81370c20075797dc7fd157804139f77445846a14898fe9a67ead38f4aff661d2031b81006a1e3a16053c7ddcb3e5c3cc5c1ebe1000046c5c6a7af3a86c776b1b2bef3c3cdb2373ebcb83a5e052406e725103a9388473a1e5d13d1e8e60f9b0c1566e1655245727a3b2f19cb5d13c3b7bfff71da43a16073c7bd4b024667b56aa0b7cb0b009858fca75deff1622367357d59d58764597e481203332238317be74ad8d7798ca2ffacbf6a4eceaa00e0d0dea554ac6feb50deaabbc15f635d3c806e9728f9fc6e865cc172b49c2b9875633c1bf34033fca00db6a495a33d3c805840a2c8692638426a00953a40a9dc0000a0820842f9180f80941987cd3c0717ef04bc598ac02354f0b80642c8c1f6096cca03d66a51b791ce37d7bd06007a45a80b7304d8370db82c3d4379564a31a350a404a0f45086a3dc0283c83358fbea5e80a5e7e8b4d2a713a60f53238b36afe630c75b54c45b5487d6eed3408d2c04333712e437b608009c93937e2634a5cec79ba3019febbf1dfc2c9631b594cb448cd19b216e2d55ddda0579245a165adf9f89f94e76b649203517b16d1be9cd5dccafa8997065f241982c4f2a8aa2395cbdf75fb5eac289218fe7c8adf6904b3ada7870b242c9c07ab6bc67e8ea48c89c7a1ee2d6161545d1809adf0800b22cbbbe99a7231a17ed21948f11d894587a26c0d273417e630b405e5194f25fff6f6493fb9b9d8e82910000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000ac49444154388ded94c10dc33008453f5637ea061ec24cd2293289976083ce440f6d2262b012da5b95277188133f7f4560e0e2039dfc4eb39e621f164097894455c30280debbdb539c0180881c25dcd15a73f2509c8588c0cc3b795a4c445b0170bf65e596158f821969f19af4e8b02bf1f7e2b3890bf09eb8f145660223b63eb6a267ad00e209b47d6cfb39143f824be42e825aab5b4f27b6f2993483db2c223a4aa3db6b0633ff14e80f79015c6574466adcb13f0000000049454e44ae426082 + + + + + buttonOk + clicked() + DBGpSettingsS + accept() + + + buttonCancel + clicked() + DBGpSettingsS + reject() + + + + tabWidget2 + lineLocalBasedir + lineServerBasedir + lineServerListenPort + checkBreakOnNotice + checkBreakOnWarning + checkBreakOnUserNotice + checkBreakOnUserWarning + checkBreakOnUserError + comboDefaultExecutionState + buttonOk + buttonCancel + + + slotLocalProjectToggled(bool) + checkLocalProject_toggled(bool) + slotLocalProjectToggle(bool) + + + + ktextbrowser.h + + diff --git a/quanta/components/debugger/dbgp/qbytearrayfifo.cpp b/quanta/components/debugger/dbgp/qbytearrayfifo.cpp new file mode 100644 index 00000000..3060e43d --- /dev/null +++ b/quanta/components/debugger/dbgp/qbytearrayfifo.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005 by Linus McCabe, + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "qbytearrayfifo.h" +#include +#include + +QByteArrayFifo::QByteArrayFifo( ) +{ + m_size = 0; + m_array.resize(0); +} + +QString QByteArrayFifo::retrieve( ) +{ + // See if there's a null teminator somewhere + QString str(m_array); + size_t size = str.length() + 1; + + // Decrease size and move bytes to the beginning of the array + m_size -= size; + for(size_t cnt = 0; cnt < m_size; cnt++) + m_array[cnt] = m_array[cnt + size]; + + // Resize array, needed for find() to work + m_array.resize(m_size); + + return str; +} + +bool QByteArrayFifo::append(const char * chars, size_t size ) +{ + // Resize the array, fail if not possible + if(!m_array.resize(m_size + size )) + return false; + + // Copy the elements + for(size_t cnt = 0; cnt < size; cnt++) + m_array[cnt + m_size] = chars[cnt]; + + // Increase size var + m_size += size; + + return true; +} + +long QByteArrayFifo::find( char character ) +{ + // If size is 0, find() outputs a warning for some reason + if(m_size == 0) + return -1; + + return m_array.find(character); +} + +QString QByteArrayFifo::base64Encoded() +{ + return KCodecs::base64Encode(m_array); +} + diff --git a/quanta/components/debugger/dbgp/qbytearrayfifo.h b/quanta/components/debugger/dbgp/qbytearrayfifo.h new file mode 100644 index 00000000..a422bc3d --- /dev/null +++ b/quanta/components/debugger/dbgp/qbytearrayfifo.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005 by Linus McCabe, + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef qbytearrayfifo_H +#define qbytearrayfifo_H + +#include +#include + +class QByteArrayFifo +{ + + public: + QByteArrayFifo(); + bool append(const char * chars, size_t size); + QString retrieve(); + QString base64Encoded(); + long find(char character); + size_t length() { return m_size; } + + private: + QByteArray m_array; + size_t m_size; + +}; + +#endif // qbytearrayfifo_H diff --git a/quanta/components/debugger/dbgp/quantadebuggerdbgp.cpp b/quanta/components/debugger/dbgp/quantadebuggerdbgp.cpp new file mode 100644 index 00000000..100ec9d3 --- /dev/null +++ b/quanta/components/debugger/dbgp/quantadebuggerdbgp.cpp @@ -0,0 +1,1042 @@ +/*************************************************************************** + quantadebuggerdbgp.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "debuggerclient.h" +#include "quantadebuggerdbgp.h" +#include "debuggerinterface.h" +#include "debuggerbreakpoint.h" +#include "dbgpsettings.h" +#include "debuggervariable.h" +#include "variableslistview.h" +#include "pathmapper.h" + + + +K_EXPORT_COMPONENT_FACTORY( quantadebuggerdbgp, + KGenericFactory("quantadebuggerdbgp")) + +const char QuantaDebuggerDBGp::protocolversion[] = "1.0"; + +QuantaDebuggerDBGp::QuantaDebuggerDBGp (QObject *parent, const char*, const QStringList&) + : DebuggerClient (parent, "DBGp") +{ + // Create a socket object and set up its signals + m_errormask = 1794; + m_supportsasync = false; + m_defaultExecutionState = Starting; + setExecutionState(m_defaultExecutionState); + emit updateStatus(DebuggerUI::NoSession); + + connect(&m_network, SIGNAL(command(const QString&)), this, SLOT(processCommand(const QString&))); + connect(&m_network, SIGNAL(active(bool)), this, SLOT(slotNetworkActive(bool))); + connect(&m_network, SIGNAL(connected(bool)), this, SLOT(slotNetworkConnected(bool))); + connect(&m_network, SIGNAL(networkError(const QString &, bool)), this, SLOT(slotNetworkError(const QString &, bool))); + +} + + +QuantaDebuggerDBGp::~QuantaDebuggerDBGp () +{ + +// kdDebug(24002) << k_funcinfo << endl; + + m_network.sessionEnd(); +} + +void QuantaDebuggerDBGp::slotNetworkActive(bool active) +{ + // debuggerInterface() might not be available, for example from project dialog + if(!debuggerInterface()) + return; + + debuggerInterface()->enableAction("debug_request", active); + debuggerInterface()->enableAction("debug_connect", !active); + debuggerInterface()->enableAction("debug_disconnect", active); + + setExecutionState(m_defaultExecutionState); + + if(active) + emit updateStatus(DebuggerUI::AwaitingConnection); + else + emit updateStatus(DebuggerUI::NoSession); + +} + +void QuantaDebuggerDBGp::slotNetworkConnected(bool connected) +{ + // debuggerInterface() might not be available, for example from project dialog + if(!debuggerInterface()) + return; + + m_active = connected; + + debuggerInterface()->enableAction("debug_run", connected); + debuggerInterface()->enableAction("debug_leap", connected); + debuggerInterface()->enableAction("debug_pause", connected); + debuggerInterface()->enableAction("debug_kill", connected); + + debuggerInterface()->enableAction("debug_stepinto", connected); + debuggerInterface()->enableAction("debug_stepover", connected); + debuggerInterface()->enableAction("debug_stepout", connected); + + debuggerInterface()->setActiveLine("", 0); + if(connected) + emit updateStatus(DebuggerUI::Connected); + else + { + setExecutionState(m_defaultExecutionState); + emit updateStatus(DebuggerUI::AwaitingConnection); + + profilerOpen(false); + } + +} + +void QuantaDebuggerDBGp::slotNetworkError(const QString &errormsg, bool log) +{ + debuggerInterface()->showStatus(errormsg, log); +} + + +// Try to make a connection to the dbgp server +void QuantaDebuggerDBGp::startSession() +{ + kdDebug(24002) << k_funcinfo << endl; + + m_network.sessionStart(m_useproxy, m_serverHost, m_useproxy ? m_serverPort : m_listenPort); +// setExecutionState(Starting); +} + + +void QuantaDebuggerDBGp::endSession() +{ + + kdDebug(24002) << k_funcinfo << endl; + + // Close the socket + m_network.sessionEnd(); + +// debuggerInterface()->enableAction("debug_request", false); +// debuggerInterface()->enableAction("debug_run", false); +// debuggerInterface()->enableAction("debug_leap", false); +// debuggerInterface()->enableAction("debug_pause", false); + +} + + +// Change executionstate of the script +void QuantaDebuggerDBGp::setExecutionState( const State & state, bool forcesend ) +{ + if(m_executionState != state || forcesend) + { + if(state == Running) + m_network.sendCommand("run"); + else if (state == Break) + m_network.sendCommand("break"); + } + m_executionState = state; + + if(debuggerInterface()) { + // The run action will be active if we're started, stopped or paused + debuggerInterface()->enableAction("debug_run", m_executionState == Break || m_executionState == Starting || m_executionState == Stopped); + + // The pause action will be enabled if we're running and either supports async or we're not connected (ie will start running) + debuggerInterface()->enableAction("debug_pause", m_executionState == Running && (m_supportsasync || !isActive())) ; + + // Kill is active if we're paused, just started of the debugger supports async, as long as we have an active session + debuggerInterface()->enableAction("debug_kill", isActive() && (m_executionState == Break || (m_executionState == Running && m_supportsasync) || m_executionState == Starting || m_executionState == Stopping )); + + // These are only activated when we have an active seesion and are paused + debuggerInterface()->enableAction("debug_stepinto", isActive() && (m_executionState == Break || m_executionState == Starting )); + debuggerInterface()->enableAction("debug_stepout", isActive() && (m_executionState == Break || m_executionState == Starting)); + debuggerInterface()->enableAction("debug_stepover", isActive() && (m_executionState == Break || m_executionState == Starting)); + } + +} + +// Change executionstate of the script +void QuantaDebuggerDBGp::setExecutionState(const QString &state) +{ + kdDebug(24002) << k_funcinfo << state << endl; + + if(state == "starting") + { + setExecutionState(Starting); + emit updateStatus(DebuggerUI::Paused); + } + else if(state == "stopping") + { + setExecutionState(Stopping); + emit updateStatus(DebuggerUI::Paused); + m_network.slotSocketDestroyed(); //XDebug disconnects when stopped and destroys our socket + } + else if(state == "stopped") + { + setExecutionState(Stopped); + emit updateStatus(DebuggerUI::Paused); + m_network.slotSocketDestroyed(); //XDebug disconnects when stopped and destroys our socket + } + else if(state == "running") + { + setExecutionState(Running); + emit updateStatus(DebuggerUI::Running); + } + else if(state == "break") + { + setExecutionState(Break); + emit updateStatus(DebuggerUI::Paused); + } + +} + +// Return capabilities of dbgp +const uint QuantaDebuggerDBGp::supports(DebuggerClientCapabilities::Capabilities cap) +{ + switch(cap) + { + case DebuggerClientCapabilities::LineBreakpoints: +// case DebuggerClientCapabilities::ConditionalBreakpoints: + case DebuggerClientCapabilities::StartSession: + case DebuggerClientCapabilities::EndSession: + case DebuggerClientCapabilities::Kill: + case DebuggerClientCapabilities::Pause: + case DebuggerClientCapabilities::Run: + //case DebuggerClientCapabilities::Skip: + case DebuggerClientCapabilities::StepOut: + case DebuggerClientCapabilities::StepInto: + case DebuggerClientCapabilities::StepOver: + case DebuggerClientCapabilities::Watches: + case DebuggerClientCapabilities::VariableSetValue: + case DebuggerClientCapabilities::ProfilerOpen: + return true; + + default: + return false; + } +} + + +// Process a dbgp command +void QuantaDebuggerDBGp::processCommand(const QString& datas) +{ + kdDebug(24002) << k_lineinfo << datas.left(50) << " (" << datas.length() << " bytes)" << endl; + + QDomDocument data; + data.setContent(datas); + kdDebug(24002) << datas << endl; + + // Did we get a normal response? + if(data.elementsByTagName("response").count() > 0) + { + QDomNode response = data.elementsByTagName("response").item(0); + QString command = attribute(response, "command"); + + // Status command + if(command == "status") + setExecutionState(attribute(response, "status")); + + // Callback stack + else if(command == "stack_get") + stackShow(response); + + // Reply from a user execution action + else if(command == "break" + || command == "step_over" + || command == "step_into" + || command == "step_out") + { + handleError(response); + // If this is the acknoledge of a step command, request the call stack + m_network.sendCommand("stack_get"); + setExecutionState(attribute(response, "status")); + handleError(response); + m_network.sendCommand("feature_get", "-n profiler_filename"); + sendWatches(); + } + + // Run + else if(command == "run" ) + { + setExecutionState(attribute(response, "status")); + handleError(response); + m_network.sendCommand("stack_get"); + } + + // Feature get replu + else if(command == "feature_get") + checkSupport(response); + + // Reply after adding a breakpoint + else if(command == "breakpoint_set") + setBreakpointKey(response); + + else if(command == "typemap_get") + typemapSetup(response); + + else if(command == "property_get") + showWatch(response); + + else if(command == "property_set") + propertySetResponse(response); + else if(command == "stop") + setExecutionState("stopped"); + + // Unknown command... + else + { + kdDebug(24002) << " * Unknown command: " << command << endl; + } + } + else if(data.elementsByTagName("init").count() > 0) + { + QDomNode init = data.elementsByTagName("init").item(0); + initiateSession(init); + return; + } + else + { + debuggerInterface()->showStatus(i18n("Unrecognized package: '%1%2'").arg(datas.left(50)).arg(datas.length() > 50 ? "..." : ""), true); + + kdDebug(24002) << datas << endl; + } + +} + +void QuantaDebuggerDBGp::initiateSession(const QDomNode& initpacket) +{ + if(attribute(initpacket, "protocol_version") != protocolversion) + { + debuggerInterface()->showStatus( + i18n("The debugger for %1 uses an unsupported protocol version (%2)") + .arg(attribute(initpacket, "language")) + .arg(attribute(initpacket, "protocol_version")) + , true); + + endSession(); + return; + } + QString path = attribute(initpacket, "fileuri"); + if (path.startsWith("file://")) + { + path.remove(0, 7); + } + debuggerInterface()->setActiveLine(mapServerPathToLocal(path), 0); + + // Store some vars + m_initialscript = attribute(initpacket, "fileuri"); + m_appid = attribute(initpacket, "appid"); + +// setExecutionState(Starting); +// m_network.sendCommand("feature_get", "-n encoding"); + m_network.sendCommand("feature_get", "-n supports_async"); +// m_network.sendCommand("feature_get", "-n breakpoint_types"); +// m_network.sendCommand("feature_get", "-n profiler_filename"); + m_network.sendCommand("feature_get", "-n breakpoint_set"); + m_network.sendCommand("feature_get", "-n supports_postmortem"); + m_network.sendCommand("typemap_get"); + m_network.sendCommand("feature_get", "-n quanta_initialized"); +} + +void QuantaDebuggerDBGp::stackShow(const QDomNode&node) +{ + bool foundlowlevel = false; + BacktraceType type; + QString typestr; + + // Clear backtrace + debuggerInterface()->backtraceClear(); + + // Add new one + for(QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) + { + // Type isnt currently correct with xdebug +// type = (attribute(child, "type") == "file" ? File : Eval); + typestr = attribute(child, "filename"); + if(typestr.find(QRegExp(".*%28[0-9]+%29%20%3A%20eval")) >= 0) + type = Eval; + else + type = File; + +// kdDebug(24002) << " * Stck " << attribute(child, "level") << ": " << attribute(child, "type") << " (" << type << ") = " << attribute(child, "filename") << ", " << attribute(child, "lineno") << endl; + + + // If this is the lowest level and the type + if(type == File && !foundlowlevel) + { + foundlowlevel = true; + debuggerInterface()->setActiveLine(mapServerPathToLocal(attribute(child, "filename")), attribute(child, "lineno").toLong() - 1); + } + + debuggerInterface()->backtraceShow( + attribute(child, "level").toLong(), + type, + attribute(child, "filename"), + attribute(child, "lineno").toLong() - 1, // Quanta lines are 0-based, DBGp is 1 based + attribute(child, "where")); + } + +} + +void QuantaDebuggerDBGp::checkSupport( const QDomNode & node ) +{ + QString feature = attribute(node, "feature_name"); + QString data = node.nodeValue(); + if(feature == "supports_async") + m_supportsasync = data.toLong(); + + // if the debugger supports breakpoints, we have to send all current ones + else if(feature == "breakpoint_set"/* && data.toLong()*/) + debuggerInterface()->refreshBreakpoints(); + + // Our own feature, probably not available but then we know we're done initiating + else if(feature == "quanta_initialized" ) + { + m_network.sendCommand("stack_get"); + if(m_executionState != Break) + setExecutionState(m_executionState, true); + } + +} + +QString QuantaDebuggerDBGp::attribute(const QDomNode&node, const QString &attribute) +{ + return node.attributes().namedItem(attribute).nodeValue(); +} + +// Turn on/off actions related to a debugging session +void QuantaDebuggerDBGp::debuggingState(bool enable) +{ + debuggerInterface()->enableAction("debug_kill", enable); + debuggerInterface()->enableAction("debug_stepout", enable); + debuggerInterface()->enableAction("debug_stepinto", enable); + debuggerInterface()->enableAction("debug_stepover", enable); + debuggerInterface()->enableAction("debug_skip", enable); +} + + +void QuantaDebuggerDBGp::sendWatches() +{ + for(QValueList::iterator it = m_watchlist.begin(); it != m_watchlist.end(); ++it) + m_network.sendCommand("property_get", "-n " + (*it)); +} + +// Return name of debugger +QString QuantaDebuggerDBGp::getName() +{ + return "DBGp"; // no i18n on the name +} + + +// Send HTTP Request +void QuantaDebuggerDBGp::request() +{ + QString request; + request = debuggerInterface()->activeFileParts(m_startsession); + + //if(request.startsWith(m_localBasedir, false)) + // request.remove(0, m_localBasedir.length()); + + //request = m_startsession + request; + kdDebug(24002) << k_funcinfo << ", request: " << request << endl; + debuggerInterface()->sendRequest(request); +} + + +// Go as fast as possible and dont update current line or watches +void QuantaDebuggerDBGp::run() +{ + setExecutionState(Running); +// m_network.sendCommand("run"); +// m_network.sendCommand("status"); +} + +// Step into function +void QuantaDebuggerDBGp::stepInto() +{ + m_network.sendCommand("step_into"); +} + +// Step over function +void QuantaDebuggerDBGp::stepOver() +{ + if(m_executionState == Starting) + m_network.sendCommand("step_into"); + else + m_network.sendCommand("step_over"); +} + +// Step out of function +void QuantaDebuggerDBGp::stepOut() +{ + m_network.sendCommand("step_out"); +} + + +// Kill the running script +void QuantaDebuggerDBGp::kill() +{ + m_network.sendCommand("stop"); +} + +// Pause execution +void QuantaDebuggerDBGp::pause() +{ + if(isActive()) + setExecutionState(Break); + else + setExecutionState(Starting); +// m_network.sendCommand("break"); +// m_network.sendCommand("status"); +} + + +// Add a breakpoint +void QuantaDebuggerDBGp::addBreakpoint (DebuggerBreakpoint* breakpoint) +{ + QString type; + if(breakpoint->type() == DebuggerBreakpoint::LineBreakpoint) + type = "line"; + else if(breakpoint->type() == DebuggerBreakpoint::ConditionalTrue) + type = "conditional"; + else + type = "watch"; + + long id = m_network.sendCommand( + "breakpoint_set", + "-t " + type + + " -f " + mapLocalPathToServer(breakpoint->filePath()) + + " -n " + QString::number(breakpoint->line() + 1) + , breakpoint->condition()); + + breakpoint->setKey(QString("id %1").arg(id)); +} + +void QuantaDebuggerDBGp::setBreakpointKey( const QDomNode & response ) +{ + long id; + + id = attribute(response, "transaction_id").toLong(); + if(id > 0) + { + QString oldkey = QString("id %1").arg(id); + DebuggerBreakpoint *bp = debuggerInterface()->findDebuggerBreakpoint(oldkey); + if(bp) + debuggerInterface()->updateBreakpointKey(*bp, attribute(response, "id")); + } +} + + +// Clear a breakpoint +void QuantaDebuggerDBGp::removeBreakpoint(DebuggerBreakpoint* bp) +{ + m_network.sendCommand("breakpoint_remove", "-d " + bp->key()); +} + +// A file was opened... +void QuantaDebuggerDBGp::fileOpened(const QString&) +{ +// sendCommand("reinitialize", 0); +} + +// Watch a variable +void QuantaDebuggerDBGp::addWatch(const QString & variable) +{ + if(m_watchlist.find(variable) == m_watchlist.end()) + m_watchlist.append(variable); + m_network.sendCommand("property_get", "-n " + variable); +} +// Remove watch +void QuantaDebuggerDBGp::removeWatch(DebuggerVariable *variable) +{ + if(m_watchlist.find(variable->name()) != m_watchlist.end()) + m_watchlist.remove(m_watchlist.find(variable->name())); +} + +// Show conditional breakpoint state +void QuantaDebuggerDBGp::showCondition(const StringMap &) +{ + +// DebuggerBreakpoint *bp = debuggerInterface()->newDebuggerBreakpoint(); +// bp->setType(args["type"] == "true" ? DebuggerBreakpoint::ConditionalTrue : DebuggerBreakpoint::ConditionalChange); +// bp->setCondition(args["expression"]); +// bp->setFilePath(mapServerPathToLocal(args["filename"])); +// bp->setClass(args["class"]); +// bp->setFunction(args["function"]); +// bp->setValue(args["value"]); +// +// bp->setState(DebuggerBreakpoint::Undefined); +// +// debuggerInterface()->showBreakpoint(*bp); +} + +// Read configuration +void QuantaDebuggerDBGp::readConfig(QDomNode node) +{ + // Server + QDomNode valuenode = node.namedItem("serverhost"); + m_serverHost = valuenode.firstChild().nodeValue(); + if(m_serverHost.isEmpty()) + m_serverHost = "localhost"; + + valuenode = node.namedItem("serverport"); + m_serverPort = valuenode.firstChild().nodeValue(); + if(m_serverPort.isEmpty()) + m_serverPort = "9000"; + + valuenode = node.namedItem("localbasedir"); + m_localBasedir = valuenode.firstChild().nodeValue(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setLocalBasedir(m_localBasedir); + + valuenode = node.namedItem("serverbasedir"); + m_serverBasedir = valuenode.firstChild().nodeValue(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setServerBasedir(m_serverBasedir); + + valuenode = node.namedItem("listenport"); + m_listenPort = valuenode.firstChild().nodeValue(); + if(m_listenPort.isEmpty()) + m_listenPort = "9000"; + + valuenode = node.namedItem("startsession"); + m_startsession = valuenode.firstChild().nodeValue(); + if(m_startsession.isEmpty()) + m_startsession = "http://localhost/%rfpp?XDEBUG_SESSION_START=1&XDEBUG_PROFILE"; + + valuenode = node.namedItem("defaultexecutionstate"); + if(valuenode.firstChild().nodeValue().isEmpty()) + m_defaultExecutionState = Starting; + else + { + if(valuenode.firstChild().nodeValue() == "break") + m_defaultExecutionState = Starting; + else + m_defaultExecutionState = Running; + } + + valuenode = node.namedItem("useproxy"); + m_useproxy = valuenode.firstChild().nodeValue() == "1"; + + valuenode = node.namedItem("errormask"); + m_errormask = valuenode.firstChild().nodeValue().toLong(); + kdDebug(24002) << k_funcinfo << ", m_errormask = " << m_errormask << endl; + + // Profiler + valuenode = node.namedItem("profilerfilename"); + m_profilerFilename = valuenode.firstChild().nodeValue(); + if(m_profilerFilename.isEmpty()) + m_profilerFilename = "/tmp/cachegrind.out.%a"; + + valuenode = node.namedItem("profiler_autoopen"); + m_profilerAutoOpen = valuenode.firstChild().nodeValue().toLong(); + + valuenode = node.namedItem("profiler_mapfilename"); + m_profilerMapFilename = valuenode.firstChild().nodeValue().toLong(); + + +} + + +// Show configuration +void QuantaDebuggerDBGp::showConfig(QDomNode node) +{ + DBGpSettings set(protocolversion); + + readConfig(node); + + if(m_localBasedir == "/" && m_serverBasedir == "/") + set.checkLocalProject->setChecked(true); + set.lineLocalBasedir->setText(m_localBasedir); + set.lineServerBasedir->setText(m_serverBasedir); + set.lineServerListenPort->setText(m_listenPort); + set.lineStartSession->setText(m_startsession); + if(m_defaultExecutionState == Starting) + set.comboDefaultExecutionState->setCurrentItem(0); + else + set.comboDefaultExecutionState->setCurrentItem(1); + + set.checkBreakOnNotice->setChecked(QuantaDebuggerDBGp::Notice & m_errormask); + set.checkBreakOnWarning->setChecked(QuantaDebuggerDBGp::Warning & m_errormask); + set.checkBreakOnUserNotice->setChecked(QuantaDebuggerDBGp::User_Notice & m_errormask); + set.checkBreakOnUserWarning->setChecked(QuantaDebuggerDBGp::User_Warning & m_errormask); + set.checkBreakOnUserError->setChecked(QuantaDebuggerDBGp::User_Error & m_errormask); + + set.lineProfilerFilename->setText(m_profilerFilename); + if(m_profilerAutoOpen) + set.checkProfilerAutoOpen->setChecked(true); + if(m_profilerMapFilename) + set.checkProfilerMapFilename->setChecked(true); + + if(set.exec() == QDialog::Accepted ) + { + QDomElement el; + + el = node.namedItem("localproject").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("localproject"); + node.appendChild( el ); + if(set.checkLocalProject->isChecked()) + { + m_localBasedir = "/"; + m_serverBasedir = "/"; + } + else + { + m_localBasedir = set.lineLocalBasedir->text(); + m_serverBasedir = set.lineServerBasedir->text(); + if (!m_localBasedir.endsWith("/")) + m_localBasedir.append('/'); + if (!m_serverBasedir.endsWith("/")) + m_serverBasedir.append('/'); + } + + el = node.namedItem("localbasedir").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("localbasedir"); + node.appendChild( el ); + el.appendChild( node.ownerDocument().createTextNode(m_localBasedir) ); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setLocalBasedir(m_localBasedir); + + el = node.namedItem("serverbasedir").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("serverbasedir"); + node.appendChild( el ); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setServerBasedir(m_serverBasedir); + el.appendChild( node.ownerDocument().createTextNode(m_serverBasedir) ); + + el = node.namedItem("listenport").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("listenport"); + node.appendChild( el ); + m_listenPort = set.lineServerListenPort->text(); + el.appendChild( node.ownerDocument().createTextNode(m_listenPort) ); + + el = node.namedItem("startsession").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("startsession"); + node.appendChild( el ); + m_startsession = set.lineStartSession->text(); + el.appendChild(node.ownerDocument().createTextNode(m_startsession)); + + el = node.namedItem("defaultexecutionstate").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("defaultexecutionstate"); + node.appendChild( el ); + if(set.comboDefaultExecutionState->currentItem() == 0) + { + m_defaultExecutionState = Starting; + el.appendChild(node.ownerDocument().createTextNode("break")); + } + else + { + m_defaultExecutionState = Running; + el.appendChild(node.ownerDocument().createTextNode("run")); + + } + + el = node.namedItem("errormask").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("errormask"); + node.appendChild( el ); + m_errormask = (set.checkBreakOnNotice->isChecked() ? QuantaDebuggerDBGp::Notice : 0) + + (set.checkBreakOnWarning->isChecked() ? QuantaDebuggerDBGp::Warning : 0) + + (set.checkBreakOnUserNotice->isChecked() ? QuantaDebuggerDBGp::User_Notice : 0) + + (set.checkBreakOnUserWarning->isChecked() ? QuantaDebuggerDBGp::User_Warning : 0) + + (set.checkBreakOnUserError->isChecked() ? QuantaDebuggerDBGp::User_Error : 0); + kdDebug(24002) << k_funcinfo << ", m_errormask = " << m_errormask << endl; + el.appendChild( node.ownerDocument().createTextNode(QString::number(m_errormask))); + + // Profiler + el = node.namedItem("profilerfilename").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("profilerfilename"); + node.appendChild( el ); + m_profilerFilename = set.lineProfilerFilename->text(); + el.appendChild(node.ownerDocument().createTextNode(m_profilerFilename)); + + el = node.namedItem("profilerfilename_map").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("profilerfilename_map"); + node.appendChild( el ); + m_profilerMapFilename = (set.checkProfilerMapFilename->isChecked() ? true : false); + el.appendChild(node.ownerDocument().createTextNode(m_profilerMapFilename ? "1" : "0")); + + el = node.namedItem("profiler_autoopen").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("profiler_autoopen"); + node.appendChild( el ); + m_profilerAutoOpen = (set.checkProfilerAutoOpen->isChecked() ? true : false); + el.appendChild(node.ownerDocument().createTextNode(m_profilerAutoOpen ? "1" : "0")); + } +} + +// Map a server filepath to a local one using project settings +QString QuantaDebuggerDBGp::mapServerPathToLocal(const QString& serverpath) +{ + // Translate filename from server to local + return debuggerInterface()->Mapper()->mapServerPathToLocal(serverpath); +} + +// Map a local filepath to a server one using project settings +QString QuantaDebuggerDBGp::mapLocalPathToServer(const QString& localpath) +{ + // Translate filename from local to server + return debuggerInterface()->Mapper()->mapLocalPathToServer(localpath); +} + +void QuantaDebuggerDBGp::variableSetValue(const DebuggerVariable &variable) +{ + m_network.sendCommand("property_set", "-n " + variable.name(), variable.value()); + + for(QValueList::iterator it = m_watchlist.begin(); it != m_watchlist.end(); ++it) + if((*it) == variable.name()) + { + m_network.sendCommand("property_get", "-n " + variable.name(), variable.value()); + return; + } + + return; +} + +void QuantaDebuggerDBGp::profilerOpen() +{ + profilerOpen(true); +} + +void QuantaDebuggerDBGp::profilerOpen(bool forceopen) +{ + QString profileroutput = m_profilerFilename; + profileroutput.replace("%a", m_appid); + profileroutput.replace("%c", m_initialscript); + + if(m_profilerMapFilename) + profileroutput = mapServerPathToLocal( profileroutput); + + bool exists = QFile::exists(profileroutput); + if(m_profilerAutoOpen || forceopen) + { + if(exists) + { + KRun *run = new KRun(profileroutput); + run->setAutoDelete(true); + } + else + { + if(forceopen) + KMessageBox::sorry(NULL, i18n("Unable to open profiler output (%1)").arg(profileroutput), i18n("Profiler File Error")); + else + debuggerInterface()->showStatus(i18n("Unable to open profiler output (%1)").arg(profileroutput), false); + } + } + else + { + debuggerInterface()->enableAction("debug_profiler_open", exists); + } +} + +void QuantaDebuggerDBGp::typemapSetup( const QDomNode & typemapnode ) +{ + /* + + + + + + + + + */ + +// // First defaults in case they are not sent (which seems to be the case with hash and xdebug) +// m_variabletypes["bool"] = "bool"; +// m_variabletypes["int"] = "int"; +// m_variabletypes["float"] = "float"; +// m_variabletypes["string"] = "string"; +// m_variabletypes["null"] = "null"; +// m_variabletypes["array"] = "hash"; +// m_variabletypes["hash"] = "hash"; +// m_variabletypes["object"] = "object"; +// m_variabletypes["resource"] = "resource"; + + QDomNode child = typemapnode.firstChild(); + while(!child.isNull()) + { + if(child.nodeName() == "map") + { + m_variabletypes[attribute(child, "name")] = attribute(child, "type"); + } + child = child.nextSibling(); + } +} + + +void QuantaDebuggerDBGp::showWatch( const QDomNode & variablenode) +{ + debuggerInterface()->showVariable(buildVariable(variablenode.firstChild())); +} + +void QuantaDebuggerDBGp::propertySetResponse( const QDomNode & setnode) +{ + if(attribute(setnode, "success") == "0") + { + debuggerInterface()->showStatus(i18n("Unable to set value of variable."), true); + } +} + + +DebuggerVariable* QuantaDebuggerDBGp::buildVariable( const QDomNode & variablenode) +{ + /* + Sample: + + + + + + + + + + + + + + */ + QString name = attribute(variablenode, "name"); + QString type = m_variabletypes[attribute(variablenode, "type")]; + + if(type == "int") + { + QString value = variablenode.firstChild().nodeValue(); + return debuggerInterface()->newDebuggerVariable( name, value, DebuggerVariableTypes::Integer); + } + else if (type == "string") + { + QCString value = QCString(variablenode.firstChild().nodeValue()); + value = KCodecs::base64Decode(value); + return debuggerInterface()->newDebuggerVariable( name, value, DebuggerVariableTypes::String); + } + else if (type == "bool") + { + QString value = variablenode.firstChild().nodeValue(); + return debuggerInterface()->newDebuggerVariable( name, value, DebuggerVariableTypes::Boolean); + } + else if (type == "resource") + { + QString value = variablenode.firstChild().nodeValue(); + return debuggerInterface()->newDebuggerVariable( name, value, DebuggerVariableTypes::Resource); + } + else if (type == "float") + { + QString value = variablenode.firstChild().nodeValue(); + return debuggerInterface()->newDebuggerVariable( name, value, DebuggerVariableTypes::Float); + } + else if (type == "null") + { + QString value = variablenode.firstChild().nodeValue(); + return debuggerInterface()->newDebuggerVariable( name, "", DebuggerVariableTypes::Undefined); + } + else if (type == "hash" || type == "array" || type == "object") + { + QDomNode child = variablenode.firstChild(); + QPtrList vars ; + while(!child.isNull()) + { + DebuggerVariable* var = buildVariable( child); + if(var) + vars.append(var); + + child = child.nextSibling(); + } + if(type == "object") + return debuggerInterface()->newDebuggerVariable(name, vars, DebuggerVariableTypes::Object); + else + return debuggerInterface()->newDebuggerVariable(name, vars, DebuggerVariableTypes::Array); + } + + return debuggerInterface()->newDebuggerVariable(name, "", DebuggerVariableTypes::Error);; +} + +void QuantaDebuggerDBGp::handleError(const QDomNode & statusnode ) +{ + + if(attribute(statusnode, "reason") == "error" || attribute(statusnode, "reason") == "aborted") + { + QDomNode errornode = statusnode.firstChild(); + while(!errornode.isNull()) + { + if(errornode.nodeName() == "error") + { + if(attribute(statusnode, "reason") == "error") + { + // Managable error + long error = attribute(errornode, "code").toLong(); + if(!(error & m_errormask)) + { + setExecutionState(Running); + } + else + { + emit updateStatus(DebuggerUI::HaltedOnError); + debuggerInterface()->showStatus(errornode.firstChild().nodeValue(), true); + } + break; + } + else + { + // Fatal error + emit updateStatus(DebuggerUI::HaltedOnError); + debuggerInterface()->showStatus(errornode.firstChild().nodeValue(), true); + } + } + errornode = errornode.nextSibling(); + } + } + +} + +#include "quantadebuggerdbgp.moc" diff --git a/quanta/components/debugger/dbgp/quantadebuggerdbgp.desktop b/quanta/components/debugger/dbgp/quantadebuggerdbgp.desktop new file mode 100644 index 00000000..3bebcf06 --- /dev/null +++ b/quanta/components/debugger/dbgp/quantadebuggerdbgp.desktop @@ -0,0 +1,44 @@ +[Desktop Entry] +Type=Service +Name=DBGp +Comment=DBGp debugger plugin, see http://xdebug.org +Comment[bg]=Приставка на дебъгер DBGp, http://xdebug.org +Comment[ca]=Connector de depuració DBGp, consulteu http://xdebug.org +Comment[cs]=DBGp debugger plugin, viz http://xdebug.org +Comment[da]=DBGp fejlretter-plugin, se http://xdebug.org +Comment[de]=DBGp Debugger Plugin, siehe http://xdebug.org +Comment[el]=Πρόσθετο αποσφαλματωτή DBGp, δείτε το http://xdebug.org +Comment[es]=Extensión para el depurador DBGp, vea http://xdebug.org +Comment[et]=DBGp siluri plugin, vaata http://xdebug.org +Comment[eu]=DBGp araztailearen plugina, ikusi http://xdebug.org +Comment[fa]=وصلۀ اشکال‌زدای DBGp، http://xdebug.org را ببینید +Comment[fi]=DBGp-debugliitännäinen, katso http://xdebug.org +Comment[fr]=Module de débogage DBGp, consultez http://xdebug.org +Comment[ga]=Breiseán dífhabhtóra DBGp, féach ar http://xdebug.org +Comment[gl]=Extensión DBGp para o depurador, vexa tamén http://xdebug.org +Comment[hu]=DBGp nyomkövető modul, lásd: http://xdebug.org +Comment[is]=DBGp aflúsunaríforrit. Sjá http://xdebug.org +Comment[it]=Plugin di degub DBGp, vedi http://xdebug.org +Comment[ja]=DBGp デバッガ プラグイン。http://xdebug.org をご覧ください。 +Comment[ka]=DBGp განბზიკვის მოდული, იხილეთ http://xdebug.org +Comment[lt]=DBGp derintuvės priedas, žr. http://xdebug.org +Comment[ms]=Plugin nyahpepijat DBGp, lihat http://xdebug.org +Comment[nds]=Fehlersöök-Moduul för't DBGp, kiek bi http://xdebug.org +Comment[ne]=DBGp त्रुटिमोचक प्लगइन, http://xdebug.org हेर्नुहोस् +Comment[nl]=DBGp-debugger-plugin, zie http://xdebug.org +Comment[pl]=Wtyczka debugera DBGp, patrz http://xdebug.org +Comment[pt]='Plugin' de depuração DBGp, veja http://xdebug.org +Comment[pt_BR]=Plugin de depuração DBGp, veja http://xdebug.org +Comment[ru]=Модуль для отладчика DBGp, http://xdebug.org +Comment[sk]=DBGp debuger modul, pozri http://xdebug.org +Comment[sl]=Vstavek za razhoroščevanje DBGp, glej http://xdebug.org +Comment[sr]=DBGp прикључак, види http://xdebug.org +Comment[sr@Latn]=DBGp priključak, vidi http://xdebug.org +Comment[sv]=DBGp-insticksprogram för felsökning, se http://xdebug.org +Comment[uk]=Втулок зневаджувача DBGp, див. http://xdebug.org +Comment[zh_CN]=DBGp 调试器插件,参看 http://xdebug.org +Comment[zh_HK]=DBGp 除錯器外掛程式,請參閱 http://xdebug.org +Comment[zh_TW]=DBGp 除錯器外掛程式,請參閱 http://xdebug.org +Icon=kdbg +ServiceTypes=Quanta/Debugger +X-KDE-Library=quantadebuggerdbgp diff --git a/quanta/components/debugger/dbgp/quantadebuggerdbgp.h b/quanta/components/debugger/dbgp/quantadebuggerdbgp.h new file mode 100644 index 00000000..fd8eda22 --- /dev/null +++ b/quanta/components/debugger/dbgp/quantadebuggerdbgp.h @@ -0,0 +1,166 @@ +/*************************************************************************** + phpdebugdbgp.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 QUANTADEBUGGERGUBED_H +#define QUANTADEBUGGERGUBED_H + +#include +#include +#include +#include +#include + +#include "debuggerclient.h" +#include "dbgpnetwork.h" + +typedef QValueList WatchList; +typedef QMap StringMap; + +class QuantaDebuggerDBGp : public DebuggerClient +{ + Q_OBJECT + + public: + QuantaDebuggerDBGp(QObject *parent, const char* name, const QStringList&); + ~QuantaDebuggerDBGp(); + + // Execution states + enum State + { + Starting = 0, + Stopping, + Stopped, + Running, + Break + }; + // Error codes + enum Errors + { + Warning = 2, + Notice = 8, + User_Error = 256, + User_Warning = 512, + User_Notice = 1024 + }; + + // Protocol version + static const char protocolversion[]; + + // Manager interaction + const uint supports(DebuggerClientCapabilities::Capabilities); + + // Execution control + void request(); + void run(); + void stepInto(); + void stepOver(); + void stepOut(); + void pause(); + void kill(); + void setExecutionState(const QString &state); + void setExecutionState(const State &state, bool forcesend = false); + + // Connection + void startSession(); + void endSession(); + + // Return name of debugger + QString getName(); + + // Initiation + void checkSupport(const QDomNode&node); + + // New file opened in quanta + void fileOpened(const QString& file); + + // Settings + void readConfig(QDomNode node); + void showConfig(QDomNode node); + + // Breakpoints + void addBreakpoint(DebuggerBreakpoint* breakpoint); + void removeBreakpoint(DebuggerBreakpoint* breakpoint); + void showCondition(const StringMap &args); + + // Variables + void addWatch(const QString &variable); + void removeWatch(DebuggerVariable *var); + void variableSetValue(const DebuggerVariable &variable); + void propertySetResponse( const QDomNode & setnode); + + // Call stack + void stackShow(const QDomNode&node); + + private: + DBGpNetwork m_network; + + QString m_serverBasedir; + QString m_localBasedir; + QString m_serverPort; + QString m_serverHost; + QString m_startsession; + QString m_listenPort; + QString m_profilerFilename; + QString m_appid; + QString m_initialscript; + + bool m_useproxy; + bool m_profilerAutoOpen; + bool m_profilerMapFilename; + State m_executionState, m_defaultExecutionState; + long m_errormask; + long m_displaydelay; + bool m_supportsasync; + + // Variable type mapping + StringMap m_variabletypes; + + // Internal watchlist + WatchList m_watchlist; + + void sendWatches(); + void debuggingState(bool enable); + void connected(); + + void handleError(const QDomNode & statusnode ); + + QString mapServerPathToLocal(const QString& serverpath); + QString mapLocalPathToServer(const QString& localpath); + QString bpToDBGp(DebuggerBreakpoint* breakpoint); + void setBreakpointKey(const QDomNode& response); + + QString attribute(const QDomNode&node, const QString &attribute); + void initiateSession(const QDomNode& initpacket); + + void typemapSetup(const QDomNode& typemapnode); + void showWatch(const QDomNode& typemapnode); + DebuggerVariable* buildVariable(const QDomNode& typemapnode); + + // Profiler + void profilerOpen(bool forceopen); + void profilerOpen(); + + public slots: + void slotNetworkActive(bool active); + void slotNetworkConnected(bool connected); + void slotNetworkError(const QString &errormsg, bool log); + void processCommand(const QString&); + + signals: + void updateStatus(DebuggerUI::DebuggerStatus); +}; + +#endif diff --git a/quanta/components/debugger/debuggerbreakpoint.cpp b/quanta/components/debugger/debuggerbreakpoint.cpp new file mode 100644 index 00000000..ae8ed6cb --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpoint.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + debuggerbreakpoint.cpp + ---------------------- + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "debuggerbreakpoint.h" +#include + +DebuggerBreakpoint::DebuggerBreakpoint() + : m_line(1)//, m_state(0) +{} + +DebuggerBreakpoint::DebuggerBreakpoint( const DebuggerBreakpoint & bp ) +{ + m_conditionExpr = bp.condition(); + m_filePath = bp.filePath(); + m_class = bp.inClass(); + m_function = bp.inFunction(); + m_line = bp.line(); + m_state = bp.state(); + m_key = bp.key(); + m_type = bp.type(); +} + +DebuggerBreakpoint::DebuggerBreakpoint( const DebuggerBreakpoint * bp ) +{ + m_conditionExpr = bp->condition(); + m_filePath = bp->filePath(); + m_class = bp->inClass(); + m_function = bp->inFunction(); + m_line = bp->line(); + m_state = bp->state(); + m_key = bp->key(); + m_type = bp->type(); +} + + +DebuggerBreakpoint::DebuggerBreakpoint(const QString& filePath, int line) +{ + m_filePath = filePath; + m_line = line; + m_type = DebuggerBreakpoint::LineBreakpoint; + m_state = DebuggerBreakpoint::Undefined; +} + +DebuggerBreakpoint::DebuggerBreakpoint(const Types type, + const QString& conditionExpr, const QString& filePath, + const QString& inClass, const QString& inFunction) +{ + m_conditionExpr = conditionExpr; + m_filePath = filePath; + m_class = inClass; + m_function = inFunction; + m_line = 0; + m_type = type; + m_state = DebuggerBreakpoint::Undefined; +} + +DebuggerBreakpoint::~DebuggerBreakpoint() +{} + +void DebuggerBreakpoint::setFilePath(const QString& filePath) +{ + m_filePath = filePath; +} + +void DebuggerBreakpoint::setClass(const QString& newclass) +{ + m_class = newclass; +} + +void DebuggerBreakpoint::setFunction(const QString& function) +{ + m_function = function; +} + +void DebuggerBreakpoint::setLine(int line) +{ + m_line = line; +} + +void DebuggerBreakpoint::setCondition(const QString& expression) +{ + m_conditionExpr = expression; +} + +void DebuggerBreakpoint::setValue(const QString& value) +{ + m_value = value; +} + +void DebuggerBreakpoint::setState(int state) +{ + m_state = state; +} + +void DebuggerBreakpoint::setType(DebuggerBreakpoint::Types type ) +{ + m_type = type; +} + +void DebuggerBreakpoint::setKey(const QString& value) +{ + m_key = value; +} + +const QString& DebuggerBreakpoint::key() const +{ + return m_key; +} + +const QString& DebuggerBreakpoint::filePath() const +{ + return m_filePath; +} + +const QString& DebuggerBreakpoint::value() const +{ + return m_value; +} + +const QString& DebuggerBreakpoint::inClass() const +{ + return m_class; +} +const QString& DebuggerBreakpoint::inFunction() const +{ + return m_function; +} + +DebuggerBreakpoint::Types DebuggerBreakpoint::type() const +{ + return m_type; +} + +int DebuggerBreakpoint::line() const +{ + return m_line; +} + +const QString& DebuggerBreakpoint::condition() const +{ + return m_conditionExpr; +} + +int DebuggerBreakpoint::state() const +{ + return m_state; +} + +bool DebuggerBreakpoint::operator == (DebuggerBreakpoint bp) const +{ + // If they key matches + if(!m_key.isEmpty() && bp.key() == m_key) + return true; + + // Or everything else... + if(bp.filePath() == m_filePath + && (bp.line() == m_line || m_type != DebuggerBreakpoint::LineBreakpoint) + && bp.type() == m_type + && bp.inClass() == m_class + && bp.inFunction() == m_function + && bp.condition() == m_conditionExpr + ) + return true; + return false; + +} + diff --git a/quanta/components/debugger/debuggerbreakpoint.h b/quanta/components/debugger/debuggerbreakpoint.h new file mode 100644 index 00000000..46e0950d --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpoint.h @@ -0,0 +1,85 @@ +/*************************************************************************** + debuggerbreakpoint.h + -------------------- + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERBREAKPOINT_H +#define DEBUGGERBREAKPOINT_H +#include + + +class DebuggerBreakpoint +{ + public: + enum Types + { + LineBreakpoint = 0, + ConditionalTrue, + ConditionalChange + }; + + enum States + { + Undefined = 0, + Unfulfilled, + Fulfilled, + Error + }; + + DebuggerBreakpoint(); + DebuggerBreakpoint(const DebuggerBreakpoint& bp); + DebuggerBreakpoint(const DebuggerBreakpoint* bp); + DebuggerBreakpoint(const QString& filePath, int line); // Line BP + DebuggerBreakpoint(const DebuggerBreakpoint::Types type, // Any kind + const QString& conditionExpr, const QString& filePath = "", + const QString& inClass = "", const QString& inFunction = ""); + + virtual ~DebuggerBreakpoint(); + + virtual void setFunction(const QString& filePath); + virtual void setClass(const QString& filePath); + virtual void setFilePath(const QString& filePath); + virtual void setLine(int line); + virtual void setCondition(const QString& expression); + virtual void setState(int state); + virtual void setType(Types type); + virtual void setValue(const QString& value); + virtual void setKey(const QString& value); + + virtual const QString& filePath() const; + virtual const QString& inClass() const; + virtual const QString& inFunction() const; + virtual int line() const; + virtual const QString& condition() const; + virtual int state() const; + virtual DebuggerBreakpoint::Types type() const; + virtual const QString& value() const; + virtual const QString& key() const; + + bool operator == (DebuggerBreakpoint) const; + + protected: + QString m_filePath; + QString m_class; + QString m_function; + int m_line; + QString m_conditionExpr; + int m_state; + Types m_type; + QString m_value; + QString m_key; +}; + +#endif diff --git a/quanta/components/debugger/debuggerbreakpointlist.cpp b/quanta/components/debugger/debuggerbreakpointlist.cpp new file mode 100644 index 00000000..ba117965 --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpointlist.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + debuggerbreakpointlist.cpp + -------------------------- + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 +#include +#include + +#include "debuggerbreakpointlist.h" +#include "debuggerbreakpoint.h" +#include "debuggerclient.h" +#include "debuggermanager.h" +#include "debuggerui.h" +#include "resource.h" +#include "quanta.h" + +DebuggerBreakpointList::DebuggerBreakpointList() + : m_current(0) +{ + m_breakpointList = new BreakpointList_t(); +} + +DebuggerBreakpointList::~DebuggerBreakpointList() +{ + delete m_breakpointList; +} + +void DebuggerBreakpointList::add(DebuggerBreakpoint* bp) +{ + if(quantaApp->debugger()->UI()) + quantaApp->debugger()->UI()->showBreakpoint(*bp); + + m_breakpointList->push_front(bp); + if(bp->type() == DebuggerBreakpoint::LineBreakpoint) + quantaApp->debugger()->setMark(bp->filePath(), bp->line(), true, KTextEditor::MarkInterface::markType02); +} + +void DebuggerBreakpointList::remove(DebuggerBreakpoint* bp) +{ + BreakpointList_t::iterator it = find(*bp); + if(it == m_breakpointList->end()) + return; + +// DebuggerBreakpoint bp1(bp); + + if(*bp == (*bp)) + { + DebuggerBreakpoint* tmp; + + tmp = (*it); + // Remove it from the bp-list + if(quantaApp->debugger()->UI()) + quantaApp->debugger()->UI()->deleteBreakpoint(*bp); + + // Remove editor markpoint if there is one... + if(bp->type() == DebuggerBreakpoint::LineBreakpoint) + quantaApp->debugger()->setMark(bp->filePath(), bp->line(), false, KTextEditor::MarkInterface::markType02); + + it = m_breakpointList->remove(it); + delete tmp; + } +} + + + +DebuggerBreakpoint* DebuggerBreakpointList::retrieve(const QString& filePath, int line) +{ + BreakpointList_t::iterator it; + + for(it = m_breakpointList->begin(); it != m_breakpointList->end(); ++it) + { + if((filePath == (*it)->filePath()) && + line == (*it)->line()) + { + DebuggerBreakpoint* bp = new DebuggerBreakpoint(*it); + return bp; + } + } + return 0; +} + +void DebuggerBreakpointList::clear() +{ + BreakpointList_t::iterator it; + + for(it = m_breakpointList->begin(); it != m_breakpointList->end(); ++it) + { + + // Remove it from the bp-list + quantaApp->debugger()->UI()->deleteBreakpoint(*(*it)); + + // Remove editor markpoint if there is one... + quantaApp->debugger()->setMark((*it)->filePath(), (*it)->line(), false, KTextEditor::MarkInterface::markType02); + + if(quantaApp->debugger()->client()) + quantaApp->debugger()->client()->removeBreakpoint((*it)); + } + m_breakpointList->clear(); +} + +bool DebuggerBreakpointList::exists(DebuggerBreakpoint* bp) +{ + BreakpointList_t::iterator it = find(*bp); + if(it == m_breakpointList->end()) + return false; + + if(*bp == (*it)) + return true; + + return false; +} + + +BreakpointList_t::iterator DebuggerBreakpointList::find(const DebuggerBreakpoint &bp) +{ + BreakpointList_t::iterator it; + + for(it = m_breakpointList->begin(); it != m_breakpointList->end(); ++it) + { + if(bp == (*it)) + return it; + } + return m_breakpointList->end(); +} + +void DebuggerBreakpointList::rewind() +{ + m_current = 0; +} + +DebuggerBreakpoint* DebuggerBreakpointList::next() +{ + if(m_current == 0) + { + m_current = m_breakpointList->begin(); + } + else + { + ++m_current; + } + + if(m_current != m_breakpointList->end()) + { + return (*m_current); + } + else + { + return NULL; + } +} + +DebuggerBreakpoint * DebuggerBreakpointList::findDebuggerBreakpoint( const QString & key ) +{ + BreakpointList_t::iterator it; + for(it = m_breakpointList->begin(); it != m_breakpointList->end(); ++it) + { + if((*it)->key() == key) + { + DebuggerBreakpoint *bp = new DebuggerBreakpoint((*it)); + return bp; + } + } + return NULL; +} + +void DebuggerBreakpointList::updateBreakpointKey( const DebuggerBreakpoint & bp, const QString & newkey ) +{ + //DebuggerBreakpoint *bpp = new DebuggerBreakpoint(bp); + BreakpointList_t::iterator it; + it = find(bp); + if(it != m_breakpointList->end()) + { + (*it)->setKey(newkey); + } +} + +size_t DebuggerBreakpointList::count( ) +{ + return m_breakpointList->count(); +} diff --git a/quanta/components/debugger/debuggerbreakpointlist.h b/quanta/components/debugger/debuggerbreakpointlist.h new file mode 100644 index 00000000..4ca26a95 --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpointlist.h @@ -0,0 +1,58 @@ +/*************************************************************************** + debuggerbreakpointlist.h + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERBREAKPOINTLIST_H +#define DEBUGGERBREAKPOINTLIST_H + +#include +#include +#include + +class DebuggerBreakpoint; + typedef QValueList BreakpointList_t; + +class DebuggerBreakpointList +{ + + private: + BreakpointList_t* m_breakpointList; + BreakpointList_t::iterator m_current; + BreakpointList_t::iterator find(const DebuggerBreakpoint &bp); + + public: + DebuggerBreakpointList(); + ~DebuggerBreakpointList(); + + void add(DebuggerBreakpoint*); + void remove(DebuggerBreakpoint*); + //int remove(QString filePath, int line); + void clear(); + bool exists(DebuggerBreakpoint*); + //bool exists(QString filePath, int line); + + DebuggerBreakpoint* retrieve(const QString& filePath, int line); + + DebuggerBreakpoint * findDebuggerBreakpoint(const QString& key); + void updateBreakpointKey(const DebuggerBreakpoint &bp, const QString& newkey); + + size_t count(); + void rewind(); + DebuggerBreakpoint* next(); + +}; + +#endif diff --git a/quanta/components/debugger/debuggerbreakpointview.cpp b/quanta/components/debugger/debuggerbreakpointview.cpp new file mode 100644 index 00000000..2f7eea36 --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpointview.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + debuggerbreakpointview.cpp + -------------------------- + begin : 2004-06-27 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// KDE Includes +#include +#include +#include +#include +#include +#include + +// Quanta includes +#include "debuggerbreakpointview.h" +#include "debuggerbreakpoint.h" +#include "debuggerclient.h" +#include "debuggermanager.h" +#include "resource.h" +#include "quanta.h" + +namespace DebuggerBreakpointViewColumns +{ + // The enums must correspond to the order of the columns + // If you change here, change the column adding + enum Columns + { + Expression = 0, + File, + Class, + Function, + Line, + Value + }; +} + +DebuggerBreakpointViewItem::DebuggerBreakpointViewItem(DebuggerBreakpointView* view) + : KListViewItem(view) +{ +} + + +DebuggerBreakpointView::DebuggerBreakpointView(QWidget *parent, const char *name) + : KListView(parent, name) +{ + // If you change here, change the DebuggerBreakpointViewColumns enums above + addColumn(i18n("Expression")); + addColumn(i18n("File")); + addColumn(i18n("Class")); + addColumn(i18n("Function")); + addColumn(i18n("Line")); + addColumn(i18n("Value")); + + setResizeMode(QListView::AllColumns); + setAllColumnsShowFocus(true); + + m_breakpointPopup = new KPopupMenu(this); + m_breakpointPopup->insertItem(SmallIcon("editdelete"), i18n("&Remove"), this, SLOT(slotRemoveSelected())); + + connect(this, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ), this, SLOT(slotBreakpointContextMenu(KListView *, QListViewItem *, const QPoint &))); + + // Jump to bp + connect(this, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int) ), this, SLOT(slotBreakpointDoubleClick( QListViewItem *, const QPoint &, int))); +} + + +DebuggerBreakpointView::~DebuggerBreakpointView() +{} + +void DebuggerBreakpointView::deleteBreakpoint(const DebuggerBreakpoint &bp) +{ + QListViewItem *item = findBreakpoint(bp, false); + if(item) + { + delete item; + } +} + + +void DebuggerBreakpointView::showBreakpoint(const DebuggerBreakpoint &bp) +{ + QListViewItem *item = findBreakpoint(bp); + if(!item) + return; + + if(bp.type() == DebuggerBreakpoint::LineBreakpoint) + { + item->setText(DebuggerBreakpointViewColumns::Value, ""); + item->setText(DebuggerBreakpointViewColumns::Line, QString::number(bp.line() + 1)); + } + else + { + item->setText(DebuggerBreakpointViewColumns::Value, bp.value()); + item->setText(DebuggerBreakpointViewColumns::Line, ""); + } + item->setText(DebuggerBreakpointViewColumns::File, bp.filePath()); + item->setText(DebuggerBreakpointViewColumns::Expression, bp.condition()); + item->setText(DebuggerBreakpointViewColumns::Class, bp.inClass()); + item->setText(DebuggerBreakpointViewColumns::Function, bp.inFunction()); +} + +QListViewItem* DebuggerBreakpointView::findBreakpoint(const DebuggerBreakpoint& bp, bool addIfNotExist) +{ + // Find the old item if its there + DebuggerBreakpointViewItem* item = dynamic_cast(firstChild()); + while(item) + { + if(item->breakpoint() == bp) + break; + + item = dynamic_cast(item->nextSibling()); + } + + // Insert a new item + if(!item && addIfNotExist) + { + item = new DebuggerBreakpointViewItem(this); + item->setBreakpoint(bp); + insertItem(item); + } + + return item; +} + + +DebuggerBreakpoint DebuggerBreakpointView::selected() +{ + DebuggerBreakpointViewItem* bpitem = dynamic_cast(selectedItem()); + + return bpitem->breakpoint(); +} + +void DebuggerBreakpointView::slotRemoveSelected() +{ + if(!selectedItem()) + return; + + DebuggerBreakpoint bp = selected(); + + emit removeBreakpoint(&bp); +} + +void DebuggerBreakpointView::keyPressEvent(QKeyEvent *e) +{ + if(e->key() != Qt::Key_Delete) + { + e->ignore(); + return; + } + + slotRemoveSelected(); +} + +void DebuggerBreakpointView::clear() +{ + KListView::clear(); +} + +void DebuggerBreakpointView::slotBreakpointDoubleClick(QListViewItem *item, const QPoint &, int ) +{ + if(!item) + return; + + DebuggerBreakpointViewItem* bpitem = dynamic_cast(item); + + if(!bpitem->breakpoint().filePath().isEmpty()) + { + quantaApp->gotoFileAndLine(bpitem->breakpoint().filePath(), bpitem->breakpoint().line(), 0); + } + +} + +void DebuggerBreakpointView::slotBreakpointContextMenu(KListView *, QListViewItem *, const QPoint& point) +{ + if(!selectedItem()) + return; + + m_breakpointPopup->exec(point); +} + +#include "debuggerbreakpointview.moc" diff --git a/quanta/components/debugger/debuggerbreakpointview.h b/quanta/components/debugger/debuggerbreakpointview.h new file mode 100644 index 00000000..1e3ca087 --- /dev/null +++ b/quanta/components/debugger/debuggerbreakpointview.h @@ -0,0 +1,74 @@ +/*************************************************************************** + Breakpoinlistview.h + ------------------------ + begin : 2004-06-27 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERBREAKPOINTVIEW_H +#define DEBUGGERBREAKPOINTVIEW_H + +#include +#include +#include +#include "debuggerbreakpoint.h" + +// class DebuggerBreakpoint; +class DebuggerBreakpointView; + +class DebuggerBreakpointViewItem : public KListViewItem +{ + private: + DebuggerBreakpoint m_breakpoint; + + public: + DebuggerBreakpointViewItem(); + DebuggerBreakpointViewItem(DebuggerBreakpointView* view); + + DebuggerBreakpoint breakpoint() const { return m_breakpoint; } + void setBreakpoint(const DebuggerBreakpoint &bp) { m_breakpoint = bp; } + +}; + +class DebuggerBreakpointView : public KListView +{ + Q_OBJECT + + public: + DebuggerBreakpointView(QWidget *parent = 0, const char *name = 0); + ~DebuggerBreakpointView(); + + void showBreakpoint(const DebuggerBreakpoint& bp); + void deleteBreakpoint(const DebuggerBreakpoint& bp); + + DebuggerBreakpoint selected(); + + void clear(); + + public slots: + void slotRemoveSelected(); + void slotBreakpointContextMenu(KListView *list, QListViewItem * item, const QPoint& point); + void slotBreakpointDoubleClick(QListViewItem *item, const QPoint &point, int column); + + signals: + void removeBreakpoint(DebuggerBreakpoint*); + + private: + void keyPressEvent(QKeyEvent *e); + QListViewItem* findBreakpoint(const DebuggerBreakpoint& bp, bool addIfNotExist = true); + + KPopupMenu *m_breakpointPopup; +}; + +#endif diff --git a/quanta/components/debugger/debuggermanager.cpp b/quanta/components/debugger/debuggermanager.cpp new file mode 100644 index 00000000..bbc6336c --- /dev/null +++ b/quanta/components/debugger/debuggermanager.cpp @@ -0,0 +1,850 @@ +/*************************************************************************** + phpdebuggerinterface.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + Based on work by Mathieu Kooiman + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "quanta.h" +#include "document.h" +#include "resource.h" +#include "project.h" +#include "quantadebuggerinterface.h" +#include "debuggerclient.h" +#include "debuggerbreakpoint.h" +#include "debuggerbreakpointlist.h" +#include "debuggermanager.h" +#include "messageoutput.h" +#include "viewmanager.h" +#include "quantaview.h" +#include "debuggerui.h" +#include "debuggervariable.h" +#include "pathmapper.h" +#include "variableslistview.h" +#include "conditionalbreakpointdialog.h" + +// dialogs +#include "debuggervariablesets.h" + +DebuggerManager::DebuggerManager(QObject *myparent) + : QObject(myparent) +{ + initActions(); + + // Create objects + m_breakpointList = new DebuggerBreakpointList(); + m_pathmapper = new PathMapper(this, "pathmapper"); + m_debuggerui = NULL; + m_interface = new QuantaDebuggerInterface(this, "interface"); + m_client = NULL; +} + +void DebuggerManager::slotNewProjectLoaded(const QString &projectname, const KURL &, const KURL &) +{ + if(m_client) + { + + disconnect(m_client, SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, SLOT(slotStatus(DebuggerUI::DebuggerStatus))); + + delete m_client; + m_client = NULL; + } + enableAction("*", false); + + // Remove all breakpoints + m_breakpointList->clear(); + + if(m_debuggerui) + { + delete m_debuggerui; + m_debuggerui = NULL; + } + //kdDebug(24002) << "DebuggerManager::slotNewProjectLoaded " << projectname << ", " << Project::ref()->debuggerClient << endl; + + // Load new client + if(!projectname.isEmpty()) + { + + KTrader::OfferList offers = KTrader::self()->query("Quanta/Debugger"); + KTrader::OfferList::ConstIterator iterDbg; + for(iterDbg = offers.begin(); iterDbg != offers.end(); ++iterDbg) + { + KService::Ptr service = *iterDbg; + if(Project::ref()->debuggerClient() == service->name()) + { + int errCode = 0; +//Workaround for dynamic_cast not working correctly on SUSE 10, gcc 4.0.2 +//The correct way should be a simple: +// m_client = KParts::ComponentFactory::createInstanceFromService(service, this, 0, QStringList(), &errCode); + QObject* obj = KParts::ComponentFactory::createInstanceFromService(service, this, 0, QStringList(), &errCode); + if (obj && obj->inherits("DebuggerClient")) + m_client = static_cast(obj); + + //kdDebug(24002) << service->name() << " (" << m_client << ")" << endl; + + if(!m_client) + { + emit hideSplash(); + KMessageBox::error(NULL, i18n("Unable to load the debugger plugin, error code %1 was returned: %2.").arg(errCode).arg(KLibLoader::self()->lastErrorMessage()), i18n("Debugger Error")); + } + break; + } + } + } + + // Tell client to load its settings + if (m_client) + { + QDomNode nodeThisDbg; + QDomDocument *dom = Project::ref()->sessionDom(); + QDomNode projectNode = dom->firstChild().firstChild(); + QDomNode nodeDbg = projectNode.namedItem("debuggers"); + if(nodeDbg.isNull()) + { + nodeDbg = dom->createElement("debuggers"); + projectNode.appendChild(nodeDbg); + } + + // Load this project's mapped paths + m_pathmapper->readConfig(); + + // Load this projects debugger's settings + nodeThisDbg = nodeDbg.namedItem(m_client->getName()); + if(nodeThisDbg.isNull()) + { + nodeThisDbg = dom->createElement(m_client->getName()); + nodeDbg.appendChild(nodeThisDbg); + } + + m_client->readConfig(nodeThisDbg); + + // recreate UI + m_debuggerui = new DebuggerUI(this, "debuggerui"); + connect(m_client, SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, SLOT(slotStatus(DebuggerUI::DebuggerStatus))); + + // Load saved breakpoints + if(Project::ref()->debuggerPersistentBreakpoints()) + { + QDomNode nodeBreakpoints = nodeDbg.namedItem("breakpoints"); + if(!nodeBreakpoints.isNull()) + { + QDomNode child = nodeBreakpoints.firstChild(); + while(!child.isNull()) + { + DebuggerBreakpoint* bp = new DebuggerBreakpoint(); + bp->setFilePath( child.attributes().namedItem("filepath").nodeValue()); + bp->setClass( child.attributes().namedItem("class").nodeValue()); + bp->setFunction( child.attributes().namedItem("function").nodeValue()); + bp->setCondition( child.attributes().namedItem("condition").nodeValue()); + bp->setLine( child.attributes().namedItem("line").nodeValue().toLong()); + if(child.attributes().namedItem("type").nodeValue() == "true") + bp->setType(DebuggerBreakpoint::ConditionalTrue); + else if(child.attributes().namedItem("type").nodeValue() == "change") + bp->setType(DebuggerBreakpoint::ConditionalChange); + else + bp->setType(DebuggerBreakpoint::LineBreakpoint); + + // Update client and ui + m_client->addBreakpoint(bp); + m_breakpointList->add(bp); + + // loop + child = child.nextSibling(); + } + } + } + + // Load saved Watches + if(Project::ref()->debuggerPersistentWatches()) + { + QDomNode nodeWatches = nodeDbg.namedItem("watches"); + if(!nodeWatches.isNull()) + { + QDomNode child = nodeWatches.firstChild(); + while(!child.isNull()) + { + QString watch = child.attributes().namedItem("name").nodeValue(); + DebuggerVariable *var = new DebuggerVariable(watch, "", DebuggerVariableTypes::Undefined); + m_debuggerui->addVariable(var); + m_client->addWatch(watch); + + child = child.nextSibling(); + } + } + } + + } + + initClientActions(); + + // Disable all debugactions that need a session (ie not breakpoints, etc) + slotDebugStartSession(); +} + +void DebuggerManager::initActions() +{ + KAction * newaction; + KActionCollection *ac = quantaApp->actionCollection(); + if(!ac) + return; + + //Debugger, breakpoint + newaction = new KAction(i18n("Toggle &Breakpoint"), SmallIcon("debug_breakpoint"), Qt::CTRL+Qt::SHIFT+Qt::Key_B, this, SLOT(toggleBreakpoint()), ac, "debug_breakpoints_toggle"); + newaction->setToolTip(i18n("Toggles a breakpoint at the current cursor location")); + + newaction = new KAction(i18n("&Clear Breakpoints"), 0, this, SLOT(clearBreakpoints()), ac, "debug_breakpoints_clear"); + newaction->setToolTip(i18n("Clears all breakpoints")); + + newaction = new KAction(i18n("Break When..."), SmallIcon("math_int"), 0, this, SLOT(slotConditionalBreakpoint()), ac, "debug_conditional_break"); + newaction->setToolTip(i18n("Adds a new conditional breakpoint")); + + newaction = new KAction(i18n("Break When..."), SmallIcon("math_int"), 0, this, SLOT(slotConditionalBreakpoint()), ac, "debug_conditional_breakdialog"); + newaction->setToolTip(i18n("Adds a new conditional breakpoint")); + + // Execution + newaction = new KAction(i18n("Send HTTP R&equest"), SmallIcon("debug_currentline"), 0, this, SLOT(slotDebugRequest()), ac, "debug_request"); + newaction->setToolTip(i18n("Initiate HTTP Request to the server with debugging activated")); + + newaction = new KAction(i18n("&Trace"), SmallIcon("debug_run"), 0, this, SLOT(slotDebugTrace()), ac, "debug_trace"); + newaction->setToolTip(i18n("Traces through the script. If a script is currently not being debugged, it will start in trace mode when started")); + + newaction = new KAction(i18n("&Run"), SmallIcon("debug_leap"), 0, this, SLOT(slotDebugRun()), ac, "debug_run"); + newaction->setToolTip(i18n("Runs the script. If a script is currently not being debugged, it will start in run mode when started")); + + newaction = new KAction(i18n("&Step"), SmallIcon("debug_stepover"), 0, this, SLOT(slotDebugStepOver()), ac, "debug_stepover"); + newaction->setToolTip(i18n("Executes the next line of execution, but does not step into functions or includes")); + + newaction = new KAction(i18n("Step &Into"), SmallIcon("debug_stepinto"), 0, this, SLOT(slotDebugStepInto()), ac, "debug_stepinto"); + newaction->setToolTip(i18n("Executes the next line of execution and steps into it if it is a function call or inclusion of a file")); + + newaction = new KAction(i18n("S&kip"), SmallIcon("debug_skip"), 0, this, SLOT(slotDebugSkip()), ac, "debug_skip"); + newaction->setToolTip(i18n("Skips the next command of execution and makes the next command the current one")); + + newaction = new KAction(i18n("Step &Out"), SmallIcon("debug_stepout"), 0, this, SLOT(slotDebugStepOut()), ac, "debug_stepout"); + newaction->setToolTip(i18n("Executes the rest of the commands in the current function/file and pauses when it is done (when it reaches a higher level in the backtrace)")); + + newaction = new KAction(i18n("&Pause"), SmallIcon("debug_pause"), 0, this, SLOT(slotDebugPause()), ac, "debug_pause"); + newaction->setToolTip(i18n("Pauses the scripts if it is running or tracing. If a script is currently not being debugged, it will start in paused mode when started")); + newaction = new KAction(i18n("Kill"), SmallIcon("debug_kill"), 0, this, SLOT(slotDebugKill()), ac, "debug_kill"); + newaction->setToolTip(i18n("Kills the currently running script")); + + newaction = new KAction(i18n("Start Session"), SmallIcon("debug_connect"), 0, this, SLOT(slotDebugStartSession()), ac, "debug_connect"); + newaction->setToolTip(i18n("Starts the debugger internally (Makes debugging possible)")); + + newaction = new KAction(i18n("End Session"), SmallIcon("debug_disconnect"), 0, this, SLOT(slotDebugEndSession()), ac, "debug_disconnect"); + newaction->setToolTip(i18n("Stops the debugger internally (debugging not longer possible)")); + + // Variables + newaction = new KAction(i18n("Watch Variable"), SmallIcon("math_brace"), 0, this, SLOT(slotAddWatch()), ac, "debug_addwatch"); + newaction->setToolTip(i18n("Adds a variable to the watch list")); + + newaction = new KAction(i18n("Watch Variable"), SmallIcon("math_brace"), 0, this, SLOT(slotAddWatch()), ac, "debug_addwatchdialog"); + newaction->setToolTip(i18n("Adds a variable to the watch list")); + + newaction = new KAction(i18n("Set Value of Variable"), SmallIcon("edit"), 0, this, SLOT(slotVariableSet()), ac, "debug_variable_set"); + newaction->setToolTip(i18n("Changes the value of a variable")); + + newaction = new KAction(i18n("Set Value of Variable"), SmallIcon("edit"), 0, this, SLOT(slotVariableSet()), ac, "debug_variable_setdialog"); + newaction->setToolTip(i18n("Changes the value of a variable")); + + newaction = new KAction(i18n("Open Profiler Output"), SmallIcon("launch"), 0, this, SLOT(slotProfilerOpen()), ac, "debug_profiler_open"); + newaction->setToolTip(i18n("Opens the profiler output file")); + + enableAction("*", false); + +} + +void DebuggerManager::initClientActions() +{ + enableAction("*", false); + + if(m_client) + { + // Get actioncollection and add appropriate actions depending on capabilities of the debugger + if(m_client->supports(DebuggerClientCapabilities::LineBreakpoints)) + enableAction("debug_breakpoints_toggle", true); + if(m_client->supports(DebuggerClientCapabilities::LineBreakpoints)) + enableAction("debug_breakpoints_clear", true); + } +} + +DebuggerManager::~DebuggerManager() +{ + delete m_breakpointList; + m_breakpointList = 0L; + + if(m_client) + { + + disconnect(m_client, SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, SLOT(slotStatus(DebuggerUI::DebuggerStatus))); + + delete m_client; + m_client = 0L; + } + + delete m_debuggerui; + m_debuggerui = 0L; + delete m_interface; + m_interface = 0L; + delete m_pathmapper; + m_pathmapper = 0L; +} + +void DebuggerManager::enableAction(const QString& action, bool enable) +{ + if(action == "*") + { + // Enable/Disable all session related actions + connect/disconnect + enableAction("debug_request", enable); + enableAction("debug_run", enable); + enableAction("debug_trace", enable); + enableAction("debug_pause", enable); + enableAction("debug_kill", enable); + enableAction("debug_stepover", enable); + enableAction("debug_stepinto", enable); + enableAction("debug_stepout", enable); + enableAction("debug_skip", enable); + + enableAction("debug_connect", enable); + enableAction("debug_disconnect", enable); + + enableAction("debug_breakpoints_toggle", enable); + enableAction("debug_breakpoints_clear", enable); + + enableAction("debug_profiler_open", enable); + + } + else + { + // The action may or may not exist, depending on capabilities of the debugger plugin + KActionCollection *ac = quantaApp->actionCollection(); + if(ac && ac->action(action)) + ac->action(action)->setEnabled(enable); + } +} + +void DebuggerManager::slotRemoveVariable(DebuggerVariable* var) +{ + if(!m_client) + return; + + m_client->removeWatch(var); + +} + +void DebuggerManager::slotRemoveBreakpoint(DebuggerBreakpoint* bp) +{ + if(!m_client) + return; + m_breakpointList->remove(bp); + m_client->removeBreakpoint(bp); + +} + + +void DebuggerManager::slotAddWatch() +{ + kdDebug(24002) << "DebuggerManager::slotAddWatch() " << endl; + if(!m_client) + return; + + + QString watch = KInputDialog::getText(i18n("Add Watch"), i18n("Specify variable to watch:"), quantaApp->popupWord); + quantaApp->popupWord = ""; + if(!watch.isEmpty()) + { + DebuggerVariable *var = new DebuggerVariable(watch, "", DebuggerVariableTypes::Undefined); + m_debuggerui->addVariable(var); + m_client->addWatch(watch); + } +} + +void DebuggerManager::slotVariableSet() +{ + kdDebug(24002) << "DebuggerManager::slotVariableSet(" << quantaApp->popupWord << ") " << endl; + if(!m_client) + return; + + + DebuggerVariableSetS dlg; + dlg.lineVariable->setText(quantaApp->popupWord); + quantaApp->popupWord = ""; + if(dlg.exec() == QDialog::Accepted) + { + DebuggerVariable var; + var.setName(dlg.lineVariable->text()); + var.setValue(dlg.lineValue->text()); + m_client->variableSetValue(var); + } +} + +void DebuggerManager::slotConditionalBreakpoint() +{ + QString file; + + kdDebug(24002) << "DebuggerManager::slotConditionalBreakpoint() " << quantaApp->popupWord << endl; + if(!m_client) + return; + + Document *w = ViewManager::ref()->activeDocument(); + if (w) + file = w->url().prettyURL(0, KURL::StripFileProtocol); + + ConditionalBreakpointDialog dlg(quantaApp->popupWord, file, "", ""); + quantaApp->popupWord = ""; + if(dlg.exec() == QDialog::Accepted) + { + DebuggerBreakpoint * bp = dlg.breakpoint(); + if(bp) + { + m_client->addBreakpoint(bp); + m_breakpointList->add(bp); + } + } +} + +void DebuggerManager::slotDebugStartSession() +{ + if(!m_client) + return; + + m_client->startSession(); +} + +void DebuggerManager::slotDebugEndSession() +{ + if(!m_client) + return; + + m_client->endSession(); +} + +void DebuggerManager::slotDebugRequest() +{ + if(!m_client) + return; + + m_client->request(); +} + +void DebuggerManager::slotDebugTrace() +{ + if(!m_client) + return; + + m_client->trace(); +} + +void DebuggerManager::slotDebugRun() +{ + if(!m_client) + return; + + m_client->run(); + +} +void DebuggerManager::slotDebugSkip() +{ + if(!m_client) + return; + + m_client->skip(); + +} +void DebuggerManager::slotDebugStepOver() +{ + if(!m_client) + return; + + m_client->stepOver(); + +} +void DebuggerManager::slotDebugStepInto() +{ + if(!m_client) + return; + + m_client->stepInto(); + +} +void DebuggerManager::slotDebugPause() +{ + if(!m_client) + return; + + m_client->pause(); + +} +void DebuggerManager::slotDebugKill() +{ + if(!m_client) + return; + + m_client->kill(); + +} +void DebuggerManager::slotDebugStepOut() +{ + if(!m_client) + return; + + m_client->stepOut(); + +} + +void DebuggerManager::slotProfilerOpen( ) +{ + if(!m_client) + return; + + m_client->profilerOpen(); +} + +// A new file was opened, tell the debugger so it can tell us about breakpoints etc +void DebuggerManager::fileOpened(const QString& file) +{ + + // Set breakpoint markers if we have a bp in the file + m_breakpointList->rewind(); + DebuggerBreakpoint* bp; + while((bp = m_breakpointList->next())) + { + if(bp->filePath() == file) + { + setMark(bp->filePath(), bp->line(), true, KTextEditor::MarkInterface::markType02); + } + } + + //lets keep the eye on toggling bp's through the editor margin + QuantaView *view = ViewManager::ref()->isOpened(KURL::fromPathOrURL(file)); + if (view) + { + ::Document* qdoc = view->document(); + if(qdoc) + { + connectBreakpointSignals(qdoc); + } + } + + // Also, if we have a debug-session, let the debugger know... + if(m_client) + m_client->fileOpened(file); +} + +// Check with editors if breakpoints changed and send all breakpoint (again) to client +void DebuggerManager::refreshBreakpoints() +{ + // Resend bps + m_breakpointList->rewind(); + DebuggerBreakpoint* bp; + while((bp = m_breakpointList->next())) + { + m_client->addBreakpoint(bp); + } + +} + + +// The debug server told us we have a breakpoint, mark it in the file +void DebuggerManager::haveBreakpoint (const QString& file, int line) +{ + setMark(file, line, true, KTextEditor::MarkInterface::markType02); +} + +// The debug server told us we DONT have a breakpoint, remove it +void DebuggerManager::havenoBreakpoint (const QString& file, int line) +{ + DebuggerBreakpoint* br = new DebuggerBreakpoint(file, line); + m_breakpointList->remove(br); + setMark(file, line, false, KTextEditor::MarkInterface::markType02); + m_breakpointList->remove(br); +} + +// New current line +bool DebuggerManager::setActiveLine (const QString& file, int line ) +{ + //Get local filename + QString filename = file; + + // Remove old active line mark + setMark(m_currentFile, m_currentLine, false, KTextEditor::MarkInterface::markType05); + + // Update vars with active line + m_currentFile = filename; + m_currentLine = line; + + // No new current position + if(filename.isEmpty() || quantaApp->previewVisible()) + return true; + + // Find new position in editor + if(ViewManager::ref()->isOpened(filename) || QExtFileInfo::exists(filename, true, 0L)) + quantaApp->gotoFileAndLine(filename, line, 0); + else + { + showStatus(i18n("Unable to open file %1, check your basedirs and mappings.").arg(filename), true); + } + + // Add new active line mark + setMark(filename, line, true, KTextEditor::MarkInterface::markType05); + return true; +} + +// Set/clear a mark in a document +void DebuggerManager::setMark(const QString& filename, long line, bool set, int mark) +{ + if((!filename.isEmpty()) && ViewManager::ref()->isOpened(filename)) + { + ::Document* qdoc = ViewManager::ref()->isOpened(filename)->document(); + if(qdoc) + { + disconnectBreakpointSignals(qdoc); + + KTextEditor::Document* doc = qdoc->doc(); + if(doc) + { + KTextEditor::MarkInterface *markIf = dynamic_cast(doc); + if(markIf) + { + if(set) + markIf->addMark(line, mark); + else + markIf->removeMark(line, mark); + } + } + connectBreakpointSignals(qdoc); + } + } +} + +void DebuggerManager::connectBreakpointSignals(Document* qdoc) +{ + connect(qdoc, SIGNAL(breakpointMarked(Document*, int)), + this, SLOT(slotBreakpointMarked(Document*, int))); + + connect(qdoc, SIGNAL(breakpointUnmarked(Document*, int)), + this, SLOT(slotBreakpointUnmarked(Document*, int))); +} + +void DebuggerManager::disconnectBreakpointSignals(Document* qdoc) +{ + disconnect(qdoc, SIGNAL(breakpointMarked(Document*, int)), + this, SLOT(slotBreakpointMarked(Document*, int))); + + disconnect(qdoc, SIGNAL(breakpointUnmarked(Document*, int)), + this, SLOT(slotBreakpointUnmarked(Document*, int))); +} + +// Show a status message and optionally put it on the log +bool DebuggerManager::showStatus(const QString& a_message, bool log) +{ + QString message = a_message; + quantaApp->slotStatusMsg(m_client->getName() + ": " + message); + + if(log) + { + if(!message.endsWith("\n")) + message.append("\n"); + quantaApp->messageOutput()->showMessage(m_client->getName() + ": " + message); + } + return true; +} + + +void DebuggerManager::toggleBreakpoint () +{ + Document *w = ViewManager::ref()->activeDocument(); + if (w) + { + uint line, col; + w->viewCursorIf->cursorPositionReal(&line, &col); + + DebuggerBreakpoint* br = m_breakpointList->retrieve(w->url().prettyURL(0, KURL::StripFileProtocol), line); + + if(!br) + { + DebuggerBreakpoint* br = new DebuggerBreakpoint(w->url().prettyURL(0, KURL::StripFileProtocol), line); + m_breakpointList->add(br); +// setMark(w->url().prettyURL(0, KURL::StripFileProtocol), br->line(), true, KTextEditor::MarkInterface::markType02); // FIXME Is this really needed? + if(m_client && m_client->isActive()) + { + DebuggerBreakpoint tmpbp = *br; + m_client->addBreakpoint(br); + + } + else + // Trigger pathmapper to make sure we have a valid translation... + m_pathmapper->mapLocalPathToServer(w->url().prettyURL(0, KURL::StripFileProtocol)); + } + else + { + m_breakpointList->remove(br); +// setMark(w->url().prettyURL(0, KURL::StripFileProtocol), br->line(), false, KTextEditor::MarkInterface::markType02); // FIXME Is this really needed? + + if(m_client && m_client->isActive()) + { + m_client->removeBreakpoint(br); + } + } + } +} +void DebuggerManager::clearBreakpoints () +{ + m_breakpointList->clear(); +} + +void DebuggerManager::slotBreakpointMarked(Document* qdoc, int line) +{ + DebuggerBreakpoint* br = new DebuggerBreakpoint(qdoc->url().prettyURL(0, KURL::StripFileProtocol), line); + + m_breakpointList->add(br); + if(m_client && m_client->isActive()) + { + m_client->addBreakpoint(br); + } +} + +void DebuggerManager::slotBreakpointUnmarked(Document* qdoc, int line) +{ + QString filePath = qdoc->url().prettyURL(0, KURL::StripFileProtocol); + + DebuggerBreakpoint* br = m_breakpointList->retrieve(filePath, line); + + if (br) + { + if(m_client && m_client->isActive()) + { + m_client->removeBreakpoint(br); + } + + m_breakpointList->remove(br); + } +} + +void DebuggerManager::updateBreakpointKey( const DebuggerBreakpoint & bp, const QString & newkey ) +{ + m_breakpointList->updateBreakpointKey(bp, newkey); + + // Update UI + m_debuggerui->deleteBreakpoint(bp); + DebuggerBreakpoint bpnew(bp); + bpnew.setKey(newkey); + m_debuggerui->showBreakpoint(bpnew); + +} + +DebuggerBreakpoint * DebuggerManager::findDebuggerBreakpoint( const QString & key ) +{ + return m_breakpointList->findDebuggerBreakpoint(key); +} + +void DebuggerManager::saveProperties( ) +{ + + if (m_client) + { + QDomDocument *dom = Project::ref()->sessionDom(); + QDomNode projectNode = dom->firstChild().firstChild(); + QDomNode nodeDbg = projectNode.namedItem("debuggers"); + if(nodeDbg.isNull()) + { + nodeDbg = dom->createElement("debuggers"); + projectNode.appendChild(nodeDbg); + } + + // Save breakpoints + if(Project::ref()->debuggerPersistentBreakpoints()) + { + // (Re)create breakpoints section + QDomNode nodeBreakpoints = nodeDbg.namedItem("breakpoints"); + if(!nodeBreakpoints.isNull()) + nodeBreakpoints.parentNode().removeChild(nodeBreakpoints); + + if(m_breakpointList->count() > 0) + { + nodeBreakpoints = dom->createElement("breakpoints"); + nodeDbg.appendChild(nodeBreakpoints); + + + // Loop breakpoints and save 'em + m_breakpointList->rewind(); + DebuggerBreakpoint* bp; + while((bp = m_breakpointList->next())) + { + QDomElement child = dom->createElement("breakpoint"); + child.setAttribute("filepath", bp->filePath()); + child.setAttribute("class", bp->inClass()); + child.setAttribute("function", bp->inFunction()); + child.setAttribute("condition", bp->condition()); + child.setAttribute("line", QString::number(bp->line())); + if(bp->type() == DebuggerBreakpoint::ConditionalTrue) + child.setAttribute("type", "true"); + else if(bp->type() == DebuggerBreakpoint::ConditionalChange) + child.setAttribute("type", "change"); + else + child.setAttribute("type", "line"); + + nodeBreakpoints.appendChild(child); + } + } + } + + // Save Watches + if(Project::ref()->debuggerPersistentWatches()) + { + // (Re)create watches section + QDomNode nodeWatches = nodeDbg.namedItem("watches"); + if(!nodeWatches.isNull()) + nodeWatches.parentNode().removeChild(nodeWatches); + + if(m_debuggerui->watches()->first()) + { + nodeWatches = dom->createElement("watches"); + nodeDbg.appendChild(nodeWatches); + + // Loop watches and save 'em + for( DebuggerVariable *v = m_debuggerui->watches()->first(); v; v = m_debuggerui->watches()->next()) + { + QDomElement child = dom->createElement("watch"); + child.setAttribute("name", v->name()); + + nodeWatches.appendChild(child); + } + } + } + } +} + +void DebuggerManager::slotHandleEvent( const QString & event, const QString &, const QString & ) +{ + if(event == "before_project_close") + saveProperties(); +} + + + + +#include "debuggermanager.moc" diff --git a/quanta/components/debugger/debuggermanager.h b/quanta/components/debugger/debuggermanager.h new file mode 100644 index 00000000..f7584bdf --- /dev/null +++ b/quanta/components/debugger/debuggermanager.h @@ -0,0 +1,128 @@ +/*************************************************************************** + phpdebuggerinterface.h + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + Based on work by Mathieu Kooiman + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 PHPDEBUGGERINTERFACE_H +#define PHPDEBUGGERINTERFACE_H + +#include +#include + +class DebuggerClient; +class QuantaDebuggerInterface; +class DebuggerBreakpointList; +class DebuggerUI; +class DebuggerVariable; +class DebuggerBreakpoint; +class PathMapper; +class Document; + +class DebuggerManager : public QObject +{ + Q_OBJECT + private: + // client + DebuggerClient *m_client; + QuantaDebuggerInterface * m_interface; + DebuggerBreakpointList *m_breakpointList; + DebuggerUI * m_debuggerui; + PathMapper * m_pathmapper; + + // Internal help functions + void initActions(); + void initClientActions(); + void saveProperties(); + + void connectBreakpointSignals(Document*); + void disconnectBreakpointSignals(Document*); + + QString m_currentFile; + long m_currentLine; + + public: + DebuggerManager(QObject *myparent); + ~DebuggerManager(); + + // Access to memebers + DebuggerUI * UI() { return m_debuggerui; }; + DebuggerClient * client() { return m_client; }; + PathMapper * Mapper() { return m_pathmapper; }; + + // Breakpoints + void haveBreakpoint (const QString& file, int line); + void havenoBreakpoint (const QString& file, int line); + void refreshBreakpoints(); +// DebuggerBreakpoint *newDebuggerBreakpoint(); + DebuggerBreakpoint * findDebuggerBreakpoint(const QString& key); + void updateBreakpointKey(const DebuggerBreakpoint &bp, const QString& newkey); + + // Public help functions + bool showStatus(const QString& message, bool log); + bool setActiveLine (const QString& file, int line); + void setMark(const QString& filename, long line, bool set, int mark); + + void enableAction(const QString& action, bool enable); + void fileOpened(const QString& file); + + bool hasClient() { return m_client != 0; }; + + public slots: + + // Execution control slots + void slotDebugRequest(); + void slotDebugRun(); + void slotDebugTrace(); + void slotDebugSkip(); + void slotDebugStepOver(); + void slotDebugStepInto(); + void slotDebugStepOut(); + void slotDebugPause(); + void slotDebugKill(); + + // Breakpoint + void toggleBreakpoint(); + void clearBreakpoints(); + void slotConditionalBreakpoint(); + void slotRemoveBreakpoint(DebuggerBreakpoint* bp); + + // Watches + void slotAddWatch(); + void slotRemoveVariable(DebuggerVariable* var); + void slotVariableSet(); + + // Connection related slots + void slotDebugStartSession(); + void slotDebugEndSession(); + + // Profiler + void slotProfilerOpen(); + + // Initiation + void slotNewProjectLoaded(const QString &, const KURL &, const KURL &); + + // Event handling + void slotHandleEvent(const QString &, const QString &, const QString &); + + private slots: + void slotBreakpointMarked(Document*, int); + void slotBreakpointUnmarked(Document*, int); + + signals: + void hideSplash(); +}; + +#endif + diff --git a/quanta/components/debugger/debuggerui.cpp b/quanta/components/debugger/debuggerui.cpp new file mode 100644 index 00000000..c290bd8a --- /dev/null +++ b/quanta/components/debugger/debuggerui.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + debuggerui.cpp + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "debuggerui.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "variableslistview.h" +#include "debuggerbreakpointview.h" +#include "backtracelistview.h" +#include "debuggervariable.h" + +#include "quantacommon.h" +#include "quanta.h" +#include "resource.h" +#include "whtmlpart.h" + +DebuggerUI::DebuggerUI(QObject *parent, const char *name) + : QObject(parent, name), m_variablesListView(0) +{ + + // Variable watch tree + m_variablesListView = new VariablesListView(quantaApp->getMainDockWidget(), "debuggerVariables"); + m_variablesListView->setIcon(SmallIcon("math_brace")); + m_variablesListView->setCaption(i18n("Variables")); + m_variableListViewTVA = quantaApp->addToolWindow(m_variablesListView, quantaApp->prevDockPosition(m_variablesListView, KDockWidget::DockLeft), quantaApp->getMainDockWidget()); + + // Breakpointlist + m_debuggerBreakpointView = new DebuggerBreakpointView(quantaApp->getMainDockWidget(), "debuggerBreakpoints"); + m_debuggerBreakpointView->setIcon(SmallIcon("debug_breakpoint")); + m_debuggerBreakpointView->setCaption(i18n("Breakpoints")); + m_debuggerBreakpointViewTVA = quantaApp->addToolWindow(m_debuggerBreakpointView, quantaApp->prevDockPosition(m_debuggerBreakpointView, KDockWidget::DockBottom), quantaApp->getMainDockWidget()); + + // Backtrace + m_backtraceListview = new BacktraceListview(quantaApp->getMainDockWidget(), "debuggerBacktrace"); + m_backtraceListview->setIcon(SmallIcon("player_playlist")); + m_backtraceListview->setCaption(i18n("Backtrace")); + m_backtraceListviewTVA = quantaApp->addToolWindow(m_backtraceListview, quantaApp->prevDockPosition(m_backtraceListview, KDockWidget::DockBottom), quantaApp->getMainDockWidget()); + + // Debug HTML preview + m_preview = new WHTMLPart(quantaApp, "debug_output", true); + //m_preview->view()->resize(0, 0); + m_preview->view()->setIcon(UserIcon("debug_run")); + m_preview->view()->setCaption(i18n("Debug Output")); + m_previewTVA = quantaApp->addToolWindow(m_preview->view(), quantaApp->prevDockPosition(m_preview->view(), KDockWidget::DockBottom), quantaApp->getMainDockWidget()); + connect(m_preview, SIGNAL(openFile(const KURL&, const QString&, bool)), quantaApp, SLOT(slotFileOpen(const KURL&, const QString&, bool))); + + // Show debugger toolbar + quantaApp->toolBar("debugger_toolbar")->show(); + + connect(m_variablesListView, SIGNAL(removeVariable(DebuggerVariable* )), parent, SLOT(slotRemoveVariable(DebuggerVariable* ))); + + connect(m_debuggerBreakpointView, SIGNAL(removeBreakpoint(DebuggerBreakpoint* )), parent, SLOT(slotRemoveBreakpoint(DebuggerBreakpoint* ))); + showMenu(); +} + +DebuggerUI::~DebuggerUI() +{ + hideMenu(); + quantaApp->toolBar("debugger_toolbar")->hide(); + + // Remove Variable tree + quantaApp->deleteToolWindow(m_variableListViewTVA); + m_variableListViewTVA = 0L; + + // Remove breakpointlist + quantaApp->deleteToolWindow(m_debuggerBreakpointViewTVA); + m_debuggerBreakpointViewTVA = 0L; + + // Remove backtrace + quantaApp->deleteToolWindow(m_backtraceListviewTVA); + m_backtraceListviewTVA = 0L; + + // Remove output + quantaApp->deleteToolWindow(m_previewTVA); + m_previewTVA = 0L; +} + +void DebuggerUI::showMenu() +{ + QPopupMenu* debuggerMenu = (QPopupMenu*)(quantaApp->guiFactory())->container("debugger_menu", quantaApp); + if(debuggerMenu) + { + KMenuBar *mb = quantaApp->menuBar(); + mb->activateItemAt(-1); //needed as insertItem might crash if a menu is activated + m_debuggerMenuID = mb->insertItem(i18n("Deb&ug"), debuggerMenu, -1, 5); + } + else + m_debuggerMenuID = 0; + + // Status indicator + quantaApp->statusBar()->insertFixedItem(i18n("Debugger Inactive"), IDS_STATUS_DEBUGGER); + +} + +void DebuggerUI::hideMenu() +{ + if(m_debuggerMenuID != 0) + { + KMenuBar *mb = quantaApp->menuBar(); + mb->activateItemAt(-1); //needed as removeItem might crash if a menu is activated + mb->removeItem(m_debuggerMenuID); + } + m_debuggerMenuID = 0; + + // Status indicator + quantaApp->statusBar()->removeItem(IDS_STATUS_DEBUGGER); + +} + +void DebuggerUI::addVariable(DebuggerVariable* var) +{ + m_variablesListView->addVariable(var); +} + +void DebuggerUI::showBreakpoint(const DebuggerBreakpoint &bp) +{ + m_debuggerBreakpointView->showBreakpoint(bp); +} +void DebuggerUI::deleteBreakpoint(const DebuggerBreakpoint &bp) +{ + m_debuggerBreakpointView->deleteBreakpoint(bp); +} + +void DebuggerUI::sendRequest(const KURL &url) +{ + m_preview->openURL(url); +} + +void DebuggerUI::slotStatus( DebuggerStatus status ) +{ + switch(status) + { + case NoSession: + quantaApp->statusBar()->changeItem(i18n("No session"), IDS_STATUS_DEBUGGER); + break; + + case AwaitingConnection: + quantaApp->statusBar()->changeItem(i18n("Waiting"), IDS_STATUS_DEBUGGER); + break; + + case Connected: + quantaApp->statusBar()->changeItem(i18n("Connected"), IDS_STATUS_DEBUGGER); + break; + + case Paused: + quantaApp->statusBar()->changeItem(i18n("Paused"), IDS_STATUS_DEBUGGER); + break; + + case Running: + quantaApp->statusBar()->changeItem(i18n("Running"), IDS_STATUS_DEBUGGER); + break; + + case Tracing: + quantaApp->statusBar()->changeItem(i18n("Tracing"), IDS_STATUS_DEBUGGER); + break; + + case HaltedOnError: + quantaApp->statusBar()->changeItem(i18n("On error"), IDS_STATUS_DEBUGGER); + break; + + case HaltedOnBreakpoint: + quantaApp->statusBar()->changeItem(i18n("On breakpoint"), IDS_STATUS_DEBUGGER); + break; + + default: + quantaApp->statusBar()->changeItem("", IDS_STATUS_DEBUGGER); + } +} + +void DebuggerUI::backtraceClear( ) +{ + if(m_backtraceListview) + m_backtraceListview->clear(); +} + +void DebuggerUI::backtraceShow( long level, BacktraceType type, const QString & filename, long line, const QString & func ) +{ + if(m_backtraceListview) + m_backtraceListview->backtraceShow(level, type, filename, line, func); +} + + +#include "debuggerui.moc" diff --git a/quanta/components/debugger/debuggerui.h b/quanta/components/debugger/debuggerui.h new file mode 100644 index 00000000..a86e4706 --- /dev/null +++ b/quanta/components/debugger/debuggerui.h @@ -0,0 +1,90 @@ +/*************************************************************************** + debuggerui.h + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERUI_H +#define DEBUGGERUI_H + +#include +#include +#include +#include "backtracelistview.h" + +class VariablesListView; +class DebuggerBreakpointView; +class BacktraceListview; +class DebuggerBreakpoint; +class DebuggerVariable; +class WHTMLPart; +class KURL; + +class DebuggerUI : public QObject +{ + Q_OBJECT + + public: + enum DebuggerStatus + { + NoSession = 0, + AwaitingConnection, + Connected, + Paused, + Running, + Tracing, + HaltedOnError, + HaltedOnBreakpoint + }; + + DebuggerUI(QObject *parent = 0, const char *name = 0); + ~DebuggerUI(); + + // Watches + void addVariable(DebuggerVariable* var); + void showBreakpoint(const DebuggerBreakpoint& bp); + void deleteBreakpoint(const DebuggerBreakpoint& bp); + void parsePHPVariables(const QString &); + void sendRequest(const KURL &url); + VariablesListView* watches() { return m_variablesListView; }; + + void showMenu(); + void hideMenu(); + + void backtraceClear(); + void backtraceShow(long level, BacktraceType type, const QString &filename, long line, const QString& func); + + private: + VariablesListView* m_variablesListView; + KMdiToolViewAccessor* m_variableListViewTVA; + KMdiToolViewAccessor* m_previewTVA; + + DebuggerBreakpointView* m_debuggerBreakpointView; + KMdiToolViewAccessor* m_debuggerBreakpointViewTVA; + + BacktraceListview* m_backtraceListview; + KMdiToolViewAccessor* m_backtraceListviewTVA; + + int m_debuggerMenuID; + + WHTMLPart *m_preview; + + public slots: + // Status indication + void slotStatus(DebuggerUI::DebuggerStatus status); + +}; + +#endif diff --git a/quanta/components/debugger/debuggervariable.cpp b/quanta/components/debugger/debuggervariable.cpp new file mode 100644 index 00000000..b6a4f76a --- /dev/null +++ b/quanta/components/debugger/debuggervariable.cpp @@ -0,0 +1,283 @@ +/*************************************************************************** + debuggervariable.cpp + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "debuggervariable.h" +#include +#include + +DebuggerVariable::DebuggerVariable() + : m_isReference(false) + , m_size(0) + , m_type(DebuggerVariableTypes::Undefined) + , m_item(NULL) +{} + +DebuggerVariable::DebuggerVariable(const QString& name) + : m_isReference(false) + , m_size(0) + , m_type(DebuggerVariableTypes::Undefined) + , m_item(NULL) +{ + m_name = name; +} + +DebuggerVariable::DebuggerVariable(const QString& name, const QString& value, int type) + : m_isReference(false) + , m_size(0) + , m_item(NULL) +{ + m_name = name; + m_value = value; + m_type = type; + if(type == DebuggerVariableTypes::String) + m_size = value.length(); +} + +DebuggerVariable::DebuggerVariable(const QString& name, const QString& value, int type, int size) + : m_isReference(false) + , m_item(NULL) +{ + m_name = name; + m_value = value; + m_type = type; + m_size = size; +} + +DebuggerVariable::DebuggerVariable(const QString& name, const ValueList_t& values, int type) + : m_isReference(false) + , m_item(NULL) +{ + m_name = name; + m_valueList = values; + m_type = type; + m_size = values.count(); +} + +DebuggerVariable::DebuggerVariable(DebuggerVariable* v, bool copyitem ) +{ + m_name = v->name(); + m_size = v->size(); + m_value = v->value(); + m_type = v->type(); + m_isReference = v->isReference(); + if(copyitem) + { + m_item = v->item(); + v->setItem(NULL); + } + else + m_item = NULL; + + // We cant just assign m_valuelist to v->values(), it would make a shallow copy... + for(DebuggerVariable * v2 = v->values().first(); v2; v2 = v->values().next()) + m_valueList.append(new DebuggerVariable(v2, copyitem)); +} + + +void DebuggerVariable::setName(const QString& name) +{ + m_name = name; +} +QString DebuggerVariable::name() const +{ + return m_name; +} +void DebuggerVariable::setValue(const QString& value) +{ + m_value = value; +} + +QString DebuggerVariable::value() const +{ + if(isScalar()) + return m_value; + else + return i18n("Non scalar value"); +} + +bool DebuggerVariable::isScalar() const +{ + switch(m_type) + { + case DebuggerVariableTypes::Reference: + case DebuggerVariableTypes::Resource: + case DebuggerVariableTypes::String: + case DebuggerVariableTypes::Integer: + case DebuggerVariableTypes::Float: + case DebuggerVariableTypes::Boolean: + case DebuggerVariableTypes::Undefined: + case DebuggerVariableTypes::Error: + return true; + } + return false; +} + +void DebuggerVariable::setValues(const ValueList_t& valueList) +{ + m_valueList = valueList; +} + +ValueList_t DebuggerVariable::values() const +{ + return m_valueList; +} + +void DebuggerVariable::setType(int type) +{ + m_type = type; +} + +int DebuggerVariable::type() const +{ + return m_type; +} + +const QString DebuggerVariable::typeName() const +{ + switch(m_type) + { + case DebuggerVariableTypes::Array: + return i18n("Array"); + case DebuggerVariableTypes::Object: + return i18n("Object"); + case DebuggerVariableTypes::Reference: + return i18n("Reference"); + case DebuggerVariableTypes::Resource: + return i18n("Resource"); + case DebuggerVariableTypes::String: + return i18n("String"); + case DebuggerVariableTypes::Integer: + return i18n("Integer"); + case DebuggerVariableTypes::Float: + return i18n("Float"); + case DebuggerVariableTypes::Boolean: + return i18n("Boolean"); + case DebuggerVariableTypes::Undefined: + return i18n("Undefined"); + case DebuggerVariableTypes::Error: + return i18n("Error"); + default: + return i18n("Unknown"); + } +} + + +void DebuggerVariable::setSize(long size) +{ + m_size = size; +} + +long DebuggerVariable::size() const +{ + return m_size; +} + +QString DebuggerVariable::sizeName() const +{ + switch(m_type) + { + case DebuggerVariableTypes::Reference: + case DebuggerVariableTypes::Resource: + case DebuggerVariableTypes::Integer: + case DebuggerVariableTypes::Float: + case DebuggerVariableTypes::Boolean: + case DebuggerVariableTypes::Undefined: + case DebuggerVariableTypes::Error: + return ""; + } + return QString::number(m_size); +} + +void DebuggerVariable::setReference(bool ref) +{ + m_isReference = ref; +} +bool DebuggerVariable::isReference() const +{ + return m_isReference; +} + + +DebuggerVariable::~DebuggerVariable() +{ + DebuggerVariable * v; + while((v = m_valueList.first())) + { + m_valueList.remove(v); + delete v; + } + // If this variable is shown in the treeview, remove it + if(m_item) + delete m_item; + +} + + +void DebuggerVariable::deleteChild( DebuggerVariable * child ) +{ + + for(DebuggerVariable *v = m_valueList.first(); v; v = m_valueList.next()) + { + if(v->name() == child->name()) + { + m_valueList.remove(v); + delete v; + return; + } + } +} + +DebuggerVariable* DebuggerVariable::findItem( QListViewItem * item, bool traverse ) +{ + if(item == m_item) + return this; + + if(!traverse) + return NULL; + + for(DebuggerVariable * v = m_valueList.first(); v; v = m_valueList.next()) + { + DebuggerVariable * v2 = v->findItem(item, true); + if(v2) + return v2; + } + return NULL; +} + +void DebuggerVariable::copy( DebuggerVariable * v, bool copychildren ) +{ + m_name = v->name(); + m_size = (v->isScalar() || copychildren ? v->size() : m_valueList.count()); + m_value = v->value(); + m_type = v->type(); + m_isReference = v->isReference(); + + // We cant just assign m_valuelist to v->values(), it would make a shallow copy... +// + if(copychildren) + { + m_valueList.clear(); + for(DebuggerVariable * v2 = v->values().first(); v2; v2 = v->values().next()) + m_valueList.append(new DebuggerVariable(v2, true)); + } +} + +void DebuggerVariable::append( DebuggerVariable * v ) +{ + m_valueList.append(v); +} + diff --git a/quanta/components/debugger/debuggervariable.h b/quanta/components/debugger/debuggervariable.h new file mode 100644 index 00000000..3c83de4b --- /dev/null +++ b/quanta/components/debugger/debuggervariable.h @@ -0,0 +1,103 @@ +/*************************************************************************** + debuggervariable.h + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERVARIABLE_H +#define DEBUGGERVARIABLE_H + +#include +#include +#include + +namespace DebuggerVariableTypes +{ + + enum VarType { + Object, + Resource, + Reference, + Array, + String, + Integer, + Float, + Boolean, + Error, + Undefined + }; +} + +class DebuggerVariable; +typedef QPtrList ValueList_t; + +class DebuggerVariable +{ + public: + DebuggerVariable(); + DebuggerVariable(DebuggerVariable* var, bool copyitem = false); + DebuggerVariable(const QString& name); + DebuggerVariable(const QString& name, const QString& value, int type); + DebuggerVariable(const QString& name, const QString& value, int type, int size); + DebuggerVariable(const QString& name, const ValueList_t& values, int type); + virtual ~DebuggerVariable(); + + DebuggerVariable* findItem(QListViewItem *item, bool traverse = false); + + virtual void setName(const QString& name); + virtual QString name() const; + + virtual void setValue(const QString& value); + virtual QString value() const; + + virtual void setValues(const ValueList_t& valueList); + virtual ValueList_t values() const; + + virtual void setType(int type); + virtual int type() const; + virtual const QString typeName() const ; + virtual bool isScalar() const; + + virtual void setSize(long size); + virtual long size() const; + virtual QString sizeName() const; + + virtual void setReference(bool ref); + virtual bool isReference() const; + + virtual void touch() { m_touched = true;}; + virtual bool touched() const { return m_touched;}; + + virtual void setItem(KListViewItem* item) { m_item = item;}; + virtual KListViewItem* item() const{ return m_item;}; + + virtual void copy(DebuggerVariable* v, bool copychldren = true); + virtual void append(DebuggerVariable* v); + virtual void deleteChild(DebuggerVariable *child); + + + private: + ValueList_t m_valueList; + + QString m_name; + QString m_value; + bool m_isReference; + long m_size; + int m_type; + long m_touched; + + KListViewItem* m_item; +}; +#endif diff --git a/quanta/components/debugger/debuggervariablesets.ui b/quanta/components/debugger/debuggervariablesets.ui new file mode 100644 index 00000000..70440ff4 --- /dev/null +++ b/quanta/components/debugger/debuggervariablesets.ui @@ -0,0 +1,185 @@ + +DebuggerVariableSetS + + + DebuggerVariableSetS + + + + 0 + 0 + 414 + 129 + + + + Set Value of Variable + + + true + + + + unnamed + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + &Cancel + + + + + + true + + + + + + + lineVariable + + + + + + + + lblVariable + + + + 5 + 5 + 0 + 0 + + + + Variable: + + + + + lblValue + + + + 5 + 5 + 0 + 0 + + + + New value: + + + AlignTop + + + + + spacer8 + + + Vertical + + + Expanding + + + + 30 + 20 + + + + + + lineValue + + + + 7 + 7 + 0 + 0 + + + + + + + + buttonOk + clicked() + DebuggerVariableSetS + accept() + + + buttonCancel + clicked() + DebuggerVariableSetS + reject() + + + + lineVariable + lineValue + buttonOk + buttonCancel + + + diff --git a/quanta/components/debugger/gubed/Makefile.am b/quanta/components/debugger/gubed/Makefile.am new file mode 100644 index 00000000..755a7409 --- /dev/null +++ b/quanta/components/debugger/gubed/Makefile.am @@ -0,0 +1,18 @@ +METASOURCES = AUTO + +kde_module_LTLIBRARIES = quantadebuggergubed.la + +quantadebuggergubed_la_SOURCES = gubedsettingss.ui quantadebuggergubed.cpp gubedsettings.cpp +quantadebuggergubed_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +quantadebuggergubed_la_LIBADD = ../interfaces/libdebuggerinterface.la $(LIB_KPARTS) +kde_services_DATA = quantadebuggergubed.desktop + +INCLUDES = -I$(top_srcdir)/quanta/components/debugger \ + -I$(top_srcdir)/quanta/components/debugger/interfaces \ + -I$(top_srcdir)/quanta/components/debugger/gubed \ + -I$(top_srcdir)/quanta/project \ + -I$(top_srcdir)/quanta/utility \ + $(all_includes) + + +noinst_HEADERS = gubedsettings.h diff --git a/quanta/components/debugger/gubed/gubedsettings.cpp b/quanta/components/debugger/gubed/gubedsettings.cpp new file mode 100644 index 00000000..f728d884 --- /dev/null +++ b/quanta/components/debugger/gubed/gubedsettings.cpp @@ -0,0 +1,41 @@ +/*************************************************************************** + gubedsettings.cpp + ------------------- + begin : 2004-04-05 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "qlineedit.h" +#include "gubedsettings.h" +#include + +GubedSettings::GubedSettings(const QString &protocolversion) + : GubedSettingsS(0, "GubedSettings", false, 0) +{ + textAbout->setText(textAbout->text().replace("%PROTOCOLVERSION%", protocolversion)); +} + +GubedSettings::~GubedSettings() +{ +} + +void GubedSettings::slotUseProxyToggle( bool useproxy) +{ + lineServerHost->setEnabled(useproxy); + lineServerPort->setEnabled(useproxy); + lineServerListenPort->setEnabled(!useproxy); +} + + +#include "gubedsettings.moc" + diff --git a/quanta/components/debugger/gubed/gubedsettings.h b/quanta/components/debugger/gubed/gubedsettings.h new file mode 100644 index 00000000..dc070f32 --- /dev/null +++ b/quanta/components/debugger/gubed/gubedsettings.h @@ -0,0 +1,36 @@ +/*************************************************************************** + gubedsettings.h + ------------------- + begin : 2004-04-05 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 GUBEDSETTINGS_H +#define GUBEDSETTINGS_H + +#include "gubedsettingss.h" + +class GubedSettings : public GubedSettingsS +{ + Q_OBJECT + + public slots: + virtual void slotUseProxyToggle( bool useproxy); + + public: + GubedSettings(const QString &protocolversion); + ~GubedSettings(); + +}; + +#endif + diff --git a/quanta/components/debugger/gubed/gubedsettingss.ui b/quanta/components/debugger/gubed/gubedsettingss.ui new file mode 100644 index 00000000..12125c93 --- /dev/null +++ b/quanta/components/debugger/gubed/gubedsettingss.ui @@ -0,0 +1,762 @@ + +GubedSettingsS + + + GubedSettingsS + + + + 0 + 0 + 659 + 527 + + + + Gubed Settings + + + true + + + + unnamed + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + Ca&ncel + + + true + + + + + + + tabWidget2 + + + + 5 + 5 + 1 + 1 + + + + + tab + + + &General + + + + unnamed + + + + spacer4 + + + Vertical + + + Expanding + + + + 21 + 40 + + + + + + groupBox1 + + + Directory Mapping + + + + unnamed + + + + lblDebuggerServerBasedir + + + + 5 + 5 + 0 + 0 + + + + Server basedir: + + + + + lblDebuggerLocalBasedir + + + + 5 + 5 + 0 + 0 + + + + Local basedir: + + + + + lineServerBasedir + + + + + lineLocalBasedir + + + + + + + + + + groupBox2 + + + Connection Settings + + + + unnamed + + + + lineServerListenPort + + + + 5 + 0 + 0 + 0 + + + + + + lineServerPort + + + false + + + + 5 + 0 + 0 + 0 + + + + + + lineServerHost + + + false + + + + + checkUseProxy + + + + + + + + lblDebuggerUseProxe + + + + 5 + 5 + 0 + 0 + + + + Use proxy + + + + + lblDebuggerServerHost + + + + 5 + 5 + 0 + 0 + + + + Proxy host: + + + + + lblDebuggerServerPort + + + + 5 + 5 + 0 + 0 + + + + Proxy port: + + + + + lblDebuggerServerListenPort + + + + 5 + 5 + 0 + 0 + + + + Listen port: + + + + + + + groupBox3 + + + Mode + + + + unnamed + + + + lineStartSession + + + See "What's This?" for available variables + + + %afn - Filename of the current script +%afd - Absolute directory of the current script +%afp - Absolute path (directory + filename) of the current script + +%rfpd - Directory of the current script relative to project root +%rfpp - Path of the current script relative to project root + +%rfdd - Directory of the current script relative to document root +%rfdp - Path of the current script relative to document root + +%apd - Project root +%add - Document root of current script + + + + + optAddInclude + + + false + + + &Add include + + + + + optStartSession + + + Start session: + + + true + + + + + + + + + tab + + + Deb&ug Behavior + + + + unnamed + + + + groupBox4 + + + Error Handling + + + + unnamed + + + + checkBreakOnUserError + + + + 7 + 0 + 0 + 0 + + + + User errors + + + + + lblBreakOn + + + Break on: + + + AlignTop + + + + + checkBreakOnUserWarning + + + + 7 + 0 + 0 + 0 + + + + User warnings + + + + + checkBreakOnUserNotice + + + + 7 + 0 + 0 + 0 + + + + User notices + + + + + checkBreakOnNotice + + + + 7 + 0 + 0 + 0 + + + + Notices + + + + + checkBreakOnWarning + + + + 7 + 0 + 0 + 0 + + + + W&arnings + + + + + + + spacer4_3 + + + Vertical + + + Expanding + + + + 21 + 50 + + + + + + groupBox5 + + + Execution + + + + unnamed + + + + lblDelayFast + + + + 4 + 5 + 0 + 0 + + + + + 9 + + + + Fast + + + + + sliderDisplayDelay + + + + 0 + 27 + + + + 200 + + + Horizontal + + + Below + + + + + lblDelaySlow + + + + 4 + 5 + 0 + 0 + + + + + 9 + + + + Slow + + + AlignVCenter|AlignRight + + + + + + Pause + + + image0 + + + + + Trace + + + image1 + + + + + Run + + + image2 + + + + comboDefaultExecutionState + + + + + lblDefaultExecutionMode + + + Default mode: + + + AlignVCenter + + + + + lblDisplayDelay + + + Run speed: + + + AlignVCenter + + + + + + + + + TabPage + + + A&bout + + + + unnamed + + + + textLabel1 + + + + 5 + 4 + 0 + 0 + + + + <h4>Gubed PHP Debugger Plugin for Quanta +</h4> + + + + + pixmapLabel1 + + + + 0 + 0 + 0 + 0 + + + + image3 + + + false + + + AlignCenter + + + + + textAbout + + + true + + + <html><head><meta name="qrichtext" content="1" /></head><body style="font-size:10pt;font-family:Bitstream Vera Sans"> +<p><span style="font-weight:600">About</span></p> +<p>Gubed is a PHP debugger available for free through GPL. This plugin integrates Gubed with Quanta. </p> +<p>In order to use this plugin for PHP debugging, you need to get the Quanta package from the Gubed project page, <a href="http://sourceforge.net/projects/gubed">http://sourceforge.net/projects/gubed</a>, at SourceForge </p> +<p>For more info about Gubed, please visit the Gubed website at <a href="http://gubed.sf.net">http://gubed.sf.net</a> </p> +<p><span style="font-weight:600">Technical Details</span></p> +<p>This version of the debugger supports the %PROTOCOLVERSION% version of the Gubed protocol. </p> +</body></html> + + + + + + + + + + 89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff610000027f49444154388d7d93df4b53611cc69ff73de7ccb375dcdad46d2e3269036d21c4420a0b898484e82a08a2a02238a41741dd77e14dff4074d521efbae8a61b2f6a892062604e53117165e28f864dd73adb999e3cdb79cfe9c25a9c4dfa5e3e3ccfe7fdfee02538a412830b226075c3b662804d006b9567a5d4b4d2a7d77a494d5002c81370c20075797dc7fd157804139f77445846a14898fe9a67ead38f4aff661d2031b81006a1e3a16053c7ddcb3e5c3cc5c1ebe1000046c5c6a7af3a86c776b1b2bef3c3cdb2373ebcb83a5e052406e725103a9388473a1e5d13d1e8e60f9b0c1566e1655245727a3b2f19cb5d13c3b7bfff71da43a16073c7bd4b024667b56aa0b7cb0b009858fca75deff1622367357d59d58764597e481203332238317be74ad8d7798ca2ffacbf6a4eceaa00e0d0dea554ac6feb50deaabbc15f635d3c806e9728f9fc6e865cc172b49c2b9875633c1bf34033fca00db6a495a33d3c805840a2c8692638426a00953a40a9dc0000a0820842f9180f80941987cd3c0717ef04bc598ac02354f0b80642c8c1f6096cca03d66a51b791ce37d7bd06007a45a80b7304d8370db82c3d4379564a31a350a404a0f45086a3dc0283c83358fbea5e80a5e7e8b4d2a713a60f53238b36afe630c75b54c45b5487d6eed3408d2c04333712e437b608009c93937e2634a5cec79ba3019febbf1dfc2c9631b594cb448cd19b216e2d55ddda0579245a165adf9f89f94e76b649203517b16d1be9cd5dccafa8997065f241982c4f2a8aa2395cbdf75fb5eac289218fe7c8adf6904b3ada7870b242c9c07ab6bc67e8ea48c89c7a1ee2d6161545d1809adf0800b22cbbbe99a7231a17ed21948f11d894587a26c0d273417e630b405e5194f25fff6f6493fb9b9d8e82910000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c949444154388ded93db0d83300c45af5137ea06190226610a260943d8137426f707a33c0c49a4f6a7ea91f261149f5c2207f873409dfb74d43301c006e8d66856557701408cb1ea9d3c0933b71266ccf35cc95df1284484655932f9b09888ce05a0ba965bf12b045cddf995a824139becc99cd5656211c9928b48fd67a5d4634df631b38610e848af2202ab5df19d7ced9ff736c56c6b3a82aa7a5bf74aadd79acf65b5e13d9416da432a7e8c9e60f35b9c5a7d1b16b7e6d7f8c893f6e84a1c63c4beefdfcaf0ebbc010507b65c1e0ebcf80000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000ac49444154388ded94c10dc33008453f5637ea061ec24cd2293289976083ce440f6d2262b012da5b95277188133f7f4560e0e2039dfc4eb39e621f164097894455c30280debbdb539c0180881c25dcd15a73f2509c8588c0cc3b795a4c445b0170bf65e596158f821969f19af4e8b02bf1f7e2b3890bf09eb8f145660223b63eb6a267ad00e209b47d6cfb39143f824be42e825aab5b4f27b6f2993483db2c223a4aa3db6b0633ff14e80f79015c6574466adcb13f0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af400000779494441545885b5566b6c54c715fe66ee6beededd8df7858dedc5181b87c501b2b20954e0d44a698df3a022a8addaa424229512f58168d52a951a5a4ad2a2d21f55da8aa6ed8f0ab595528ad434a452aa483c6a6a648bc486605b1830c602d65e83d7f6ee7dedde7ba73f1c6ffc0253851ce9fc9973bef9be3973667408e71cf7c39e6f6808d7aa6af2c1254bb6088a12bb383939f4565fdfdb1d0303dd77c389f783bca2a222f06a4dcdcf1f59ba744b2c1cae56348dfa54d53c75e5ca04804f57c02bab567dfe8fcb96fdf4b1d2d2cf4014411c07c8e711571435ca5862313cfd24e46b2391ea164d3bb891b1f5300cc0b2a6dcb6e127040151acf9d404fc301edffc7a34fab746e061d53044aeeb80ae835b16609a7800404010d6eddfbf9fdc7701d5d5d5be0d94ee7b08781886011806609a806d03f93ce03850008464397ce8d0a192fb2ae05b3535f17d9ef7c61724e9739a61487c62023c9b856b1828982690cf83e7f3a08e8387a251616c6c6ccdddf6fbbf9b30e179df7854559f22ba0e18060cd745976de3a4aea32049485a163657566289e761453008d7756b00fce7130b7876dd3aadceb6bffa4224b2376c9ac4721c9cb52cfcc034718173b8d389a914b49e1ebc9048e0f1ba3a445475755d5d9ddcdfdf9fff44021ee47ccbd668f4fb61cf23b02c9c721cbc66db38b7c047a63b0edee8e9c1bbd7afc3f5bcd2542aa50158500099fe09abaaaa986d5981e19191d19909cf3535b1e58ef3d88e48e4cd959406dc4c061de9349ebe7c19939e772fda6f88a2f862a150f8d742c162139aba1e7864d5aaaf555454046626c481af3cb17cf9c195a150804812061c07bf4ca7e7913f110a61776525d6068310c9ac9717f03cafec4eea8a15282b2bf3fd7af7ee5f8418db98ba79f3a8373969fa3cefd1e668f4e912d7257c7c1c855c0e3b4f9dc2dbc3c370a7719284ef9497e3bb555520aa0a5bd3d036398903bdbd18989c0493e561c375bf39323efe8f8504147ba0a5a5c5ba363232fcd4934f3664cbcaeadd4cc6f3150a3e55d70972394092f07e368b77d3e92239003c575e8ee7e371109f0f600c4c55b1251c46653c8ecba689db9c6b6f767545ef5481e2151c3e7cd83bd5dddd233246c2e1b01a0b87359fdf4f88a200aa8aebae8b83bdbd30dda97e9708c1b6a54bf1e3356b100e8741fc7e104d03340dc4e7c3ea8a0a6c5bbb161b57aef42f2929a9bd938059afe06c5fdf602e9f475014c1651928140045015c171f6432e81afdb83fab0301bc944840f0f9004a0159062409600c843178b28cace741515512d4b4ea7b121089c52e5e1a1e2e34545549b06d10d705cfe701cef1a70f3f442a972be67e3b9944d38a150021532e4920b20c5d149d6bba7ee92f1d1dbffd7b4f4f7b694949f5f0f8f81717bd02003872e48895b5ac61c8f2d4891405600c19cfc3e9c1c1625e5855b17df56ac88140b1f444d3005545c7c848fb5bfdfd7bcecbf2efaf8d8e76e735ed9d1b636357366cd8a02c5a81fafa7a7eb9aded82ab2871c1e7030070d7c5b18b1791b5ac2900a5f87a4303969495019cc32c1470cb30703d93c1c9c1c1ecabc78fbf03a01e40a320083200ce394f7677776f6c6a6a3addd6d6e6de51c0d48a3868791e3445013c0fa6aee3fc8d1bc57089cf87c6152bc05515574647f1873367d03b328281b131a47339e6baee5e00f2477b172b5c28148c73e7cef50348dd5580e1ba972c4a2d8d31064a713b9d465fea634c65248235757538d8de8ed7df7b0fb7757d265cfac8e719e7bcd1b6ed658b0ac864b3a39e24198431c601e89e875b1313c5786928047f2884df9d3c3997fcae4608494992746beefa3c01bae35cd33d6f027e7f988822263c0f59db2ec663b118fcb118a8380b5a007013408a103200a0c039df0960fa4fe684902ec7716cccb1790389c3792697cf67c118c0180a82006fc6cf2733063918c48bdbb7a32410e000fa28a5bf92657917636c672814da2d08c23f679003c030a5b40780b6a880f6f6f68c6e59d789aa82f8fd100301104128c65d4a612b0ad624127fddd6dc5cd3d9d959efbaeecbb66d1f374df3523e9f0fb9aefbd2ccea504aff0c20c5390fcde59b7705dddddd7a369b4d83524092e00f87a130568ca7c7c7f1dfdede2bff3e73e66713845c5bbf7efdac81c0308c6739e71b672cdd1404e1382124cf39f7cfe503e77c96b7b6b60a070e1cf89e61189ee7797c6868886fddba9503e000b8200819bfa6eddeb46993388d696969115455ada794be06c09bce05c029a53f8946a31a632c298ae297e6f2cd13c039c78e1d3b969d3871e2835c2ee7e57239be67cf1e3e63538710d24b29dd4b297d4610846728a53f22849c063039939c1072d5eff72febeaea0263ac5610845d73b9161cc98e1e3d3ad4dadadadadcdcfce5cd9b377f361e8fe7013c0ee0010002e73cc139dfbf1076da08211db22cbf9ccd66870080523ace399f3fa22f5481696f6c6c9492c96469229188504a7f03c09879c23b392164485194e6dada5a797aaff2f27246297da5b3b3932c7a050b793c1ef70b82b08b10d20720b700b10ee012a5745f2010a89a8bb76d1bc160b0f2c2850bb3041447b27bb14422215fbd7ab5d1719c759cf346ce790c534f7994527a561084f3b158ecfd63c78e19c964f29ef6fc1f4f14b29abe15e4b80000000049454e44ae426082 + + + + + buttonOk + clicked() + GubedSettingsS + accept() + + + buttonCancel + clicked() + GubedSettingsS + reject() + + + checkUseProxy + toggled(bool) + GubedSettingsS + slotUseProxyToggle(bool) + + + + tabWidget2 + lineLocalBasedir + lineServerBasedir + checkUseProxy + lineServerHost + lineServerPort + lineServerListenPort + optStartSession + lineStartSession + optAddInclude + checkBreakOnNotice + checkBreakOnWarning + checkBreakOnUserNotice + checkBreakOnUserWarning + checkBreakOnUserError + comboDefaultExecutionState + sliderDisplayDelay + buttonOk + buttonCancel + + + slotUseProxyToggle( bool ) + + + + ktextbrowser.h + + diff --git a/quanta/components/debugger/gubed/quantadebuggergubed.cpp b/quanta/components/debugger/gubed/quantadebuggergubed.cpp new file mode 100644 index 00000000..be703e73 --- /dev/null +++ b/quanta/components/debugger/gubed/quantadebuggergubed.cpp @@ -0,0 +1,1247 @@ +/*************************************************************************** + quantadebuggergubed.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "debuggerclient.h" +#include "quantadebuggergubed.h" +#include "debuggerinterface.h" +#include "debuggerbreakpoint.h" +#include "gubedsettings.h" +#include "debuggervariable.h" +#include "variableslistview.h" +#include "pathmapper.h" + +#include "debuggerui.h" + + +K_EXPORT_COMPONENT_FACTORY( quantadebuggergubed, + KGenericFactory("quantadebuggergubed")) + +const char QuantaDebuggerGubed::protocolversion[] = "0.0.12"; + +QuantaDebuggerGubed::QuantaDebuggerGubed (QObject *parent, const char* name, const QStringList&) + : DebuggerClient (parent, name) +{ + // Create a socket object and set up its signals + m_socket = NULL; + m_server = NULL; + m_errormask = 1794; + m_defaultExecutionState = Pause; + setExecutionState(m_defaultExecutionState); + + emit updateStatus(DebuggerUI::NoSession); + m_datalen = -1; +} + +QuantaDebuggerGubed::~QuantaDebuggerGubed () +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + + if(m_socket) + { + sendCommand("die", (char*)0L); + m_socket->flush(); + m_socket->close(); + delete m_socket; + m_socket = NULL; + } + if(m_server) + { + m_server->close(); + delete m_server; + m_server = NULL; + } + emit updateStatus(DebuggerUI::NoSession); +} + +// Try to make a connection to the gubed server +void QuantaDebuggerGubed::startSession() +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + + // Set default execution state + setExecutionState(m_defaultExecutionState); + + if(m_useproxy) + { + if(!m_socket) + { + m_socket = new KNetwork::KStreamSocket(m_serverHost, m_serverPort); + + connect(m_socket, SIGNAL(gotError(int)), this, SLOT(slotError(int))); + connect(m_socket, SIGNAL(connected(const KResolverEntry &)), this, SLOT(slotConnected(const KResolverEntry &))); + connect(m_socket, SIGNAL(closed()), this, SLOT(slotConnectionClosed())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + + m_socket->connect(); + debuggerInterface()->enableAction("debug_connect", true); + debuggerInterface()->enableAction("debug_disconnect", false); + debuggerInterface()->enableAction("debug_request", false); + kdDebug(24002) << k_funcinfo << ", proxy:" << m_serverHost << ", " << m_serverPort.toUInt() << endl; + + emit updateStatus(DebuggerUI::AwaitingConnection); + } + } + else + { + if(!m_server) + { + m_server = new KNetwork::KServerSocket(m_listenPort); + + m_server->setAddressReuseable(true); + connect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + + if(m_server->listen()) + { + emit updateStatus(DebuggerUI::AwaitingConnection); + debuggerInterface()->enableAction("debug_connect", false); + debuggerInterface()->enableAction("debug_disconnect", true); + debuggerInterface()->enableAction("debug_request", true); + } + else + { + emit updateStatus(DebuggerUI::NoSession); + delete m_server; + m_server = NULL; + debuggerInterface()->enableAction("debug_connect", true); + debuggerInterface()->enableAction("debug_disconnect", false); + debuggerInterface()->enableAction("debug_request", false); + } + } + } + +} + + +void QuantaDebuggerGubed::endSession() +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + + // Close the socket + if(m_socket) + { + sendCommand("die", (char*)0L); + m_socket->flush(); + m_socket->close(); + + m_socket->deleteLater(); + m_socket = NULL; + } + + // Close the server + if(m_server) + { + m_server->close(); + delete m_server; + m_server = NULL; + } + + // Fake a connection closed signal + slotConnectionClosed(); + debuggerInterface()->enableAction("debug_request", false); + debuggerInterface()->enableAction("debug_run", false); + debuggerInterface()->enableAction("debug_leap", false); + debuggerInterface()->enableAction("debug_pause", false); + + emit updateStatus(DebuggerUI::NoSession); +} + +// Change executionstate of the script +void QuantaDebuggerGubed::setExecutionState(State newstate) +{ + if(newstate == Pause) + { + sendCommand("pause", (char*)0L); + sendCommand("sendactiveline", (char*)0L); + if(isActive()) + emit updateStatus(DebuggerUI::Paused); + } + else if(newstate == Run) + { + if(m_executionState == Pause) + sendCommand("next", (char*)0L); + + sendCommand("run", (char*)0L); + if(isActive()) + emit updateStatus(DebuggerUI::Running); + } + else if(newstate == Trace) + { + if(m_executionState == Pause) + sendCommand("next", (char*)0L); + + sendCommand("trace", (char*)0L); + if(isActive()) + emit updateStatus(DebuggerUI::Tracing); + } + + m_executionState = newstate; + + if(debuggerInterface()) { + debuggerInterface()->enableAction("debug_trace", m_executionState != Trace); + debuggerInterface()->enableAction("debug_run", m_executionState != Run); + debuggerInterface()->enableAction("debug_pause", m_executionState != Pause); + } + + kdDebug(24002) << k_funcinfo << ", " << m_executionState << endl; + +} + +// Return capabilities of gubed +const uint QuantaDebuggerGubed::supports(DebuggerClientCapabilities::Capabilities cap) +{ + switch(cap) + { + case DebuggerClientCapabilities::LineBreakpoints: + case DebuggerClientCapabilities::ConditionalBreakpoints: + case DebuggerClientCapabilities::StartSession: + case DebuggerClientCapabilities::EndSession: + case DebuggerClientCapabilities::Kill: + case DebuggerClientCapabilities::Pause: + case DebuggerClientCapabilities::Run: + case DebuggerClientCapabilities::Trace: + case DebuggerClientCapabilities::Skip: + case DebuggerClientCapabilities::StepOut: + case DebuggerClientCapabilities::StepInto: + case DebuggerClientCapabilities::StepOver: + case DebuggerClientCapabilities::Watches: + case DebuggerClientCapabilities::VariableSetValue: + return true; + + default: + return false; + } +} + +// Socket errors +void QuantaDebuggerGubed::slotError(int) +{ + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + if(m_socket) + { + if(m_socket->error() == KNetwork::KSocketBase::RemotelyDisconnected) + { + slotConnectionClosed(); + return; + } + + if(m_socket->error()) + { + kdDebug(24002) << k_funcinfo << ", " << m_socket->errorString() << endl; + debuggerInterface()->showStatus(m_socket->errorString(), false); + } + } + + if(m_server && m_server->error()) + { + kdDebug(24002) << k_funcinfo << ", " << m_server->errorString() << endl; + debuggerInterface()->showStatus(m_server->errorString(), false); + } + +} + +// slotReadyAccept +void QuantaDebuggerGubed::slotReadyAccept() +{ + + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + if(!m_socket) + { + + // Perhaps this shouldnt be disconnected - instead check if connections are available at disconnect? + disconnect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + + m_socket = (KNetwork::KStreamSocket *)m_server->accept(); // KSocketServer returns a KStreamSocket (!) + if(m_socket) + { + kdDebug(24002) << k_funcinfo << ", ready" << endl; + m_socket->enableRead(true); + + connect(m_socket, SIGNAL(gotError(int)), this, SLOT(slotError(int))); + connect(m_socket, SIGNAL(connected(const KResolverEntry &)), this, SLOT(slotConnected(const KResolverEntry &))); + connect(m_socket, SIGNAL(closed()), this, SLOT(slotConnectionClosed())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + connected(); + + emit updateStatus(DebuggerUI::Connected); + } + else + { + kdDebug(24002) << k_funcinfo << ", " << m_server->errorString() << endl; + } + } + +} + +// Connection established +void QuantaDebuggerGubed::slotConnected(const KNetwork::KResolverEntry &) +{ + emit updateStatus(DebuggerUI::Connected); + connected(); +} + +void QuantaDebuggerGubed::connected() +{ + kdDebug(24002) << k_funcinfo << endl; + + sendCommand("wait", (char*)0L); + debuggerInterface()->enableAction("debug_connect", false); + debuggerInterface()->enableAction("debug_disconnect", true); + debuggerInterface()->enableAction("debug_request", false); + + m_active = true; +} + +// Connectio closed +void QuantaDebuggerGubed::slotConnectionClosed() +{ + kdDebug(24002) << k_funcinfo << ", m_server: " << m_server << ", m_socket" << m_socket << endl; + + // Check if we have more data to read + slotReadyRead(); + kdDebug(24002) << k_funcinfo << "buffer: " << m_buffer << endl; + + if(m_socket) + { + m_socket->deleteLater(); + m_socket = NULL; + } + + if(m_server) + connect(m_server, SIGNAL(readyAccept()), this, SLOT(slotReadyAccept())); + + // Disable all session related actions and enable connection action + debuggerInterface()->enableAction("*", false); + debuggerInterface()->enableAction("debug_connect", m_useproxy == 1 || m_server == NULL); + debuggerInterface()->enableAction("debug_disconnect", m_useproxy == 0 && m_server != NULL); + setExecutionState(m_defaultExecutionState); + + debuggerInterface()->enableAction("debug_request", true); + debuggerInterface()->enableAction("debug_breakpoints_toggle", true); + debuggerInterface()->enableAction("debug_breakpoints_clear", true); + + debuggerInterface()->setActiveLine("", 0); + + emit updateStatus(DebuggerUI::AwaitingConnection); + m_active = false; +} + +// Data from socket +void QuantaDebuggerGubed::slotReadyRead() +{ + + // Data from gubed + while(m_socket && (m_socket->bytesAvailable() > 0 || m_buffer.length() >= (unsigned long)m_datalen)) + { + int bytes; + QString data; + + if(m_socket && m_socket->bytesAvailable() > 0) + { + // Read all available bytes from socket and append them to the buffer + bytes = m_socket->bytesAvailable(); + char* buffer = new char[bytes + 1]; + m_socket->readBlock(buffer, bytes); + buffer[bytes] = 0; + m_buffer += buffer; + delete[] buffer; + } + + while(1) + { + // If datalen == -1, we didnt read the command yet, otherwise were reading data. + if(m_datalen == -1) + { + bytes = m_buffer.find(";"); + if(bytes < 0) + break; + + data = m_buffer.left(bytes); + m_buffer.remove(0, bytes + 1); + bytes = data.find(":"); + m_command = data.left(bytes); + data.remove(0, bytes + 1); + m_datalen = data.toLong(); + } + if(m_datalen != -1 && (long)m_buffer.length() >= m_datalen) + { + data = m_buffer.left(m_datalen); + m_buffer.remove(0, m_datalen); + m_datalen = -1; + processCommand(data); + } + else + break; + } + } +} + +// Process a gubed command +void QuantaDebuggerGubed::processCommand(const QString& datas) +{ + kdDebug(24002) << k_funcinfo << ", " << m_command << " : " << datas.left(50) << endl; + StringMap args = parseArgs(datas); + + // See what command we got and act accordingly.. + if(m_command == "commandme") + { + //sendCommand("sendactiveline", (char*)0L); + debuggerInterface()->setActiveLine(mapServerPathToLocal(args["filename"]), args["line"].toLong()); + sendWatches(); + if(m_executionState == Trace) + sendCommand("wait", (char*)0L); + + if(m_executionState != Pause) + sendCommand("next", (char*)0L); + } + // Send run mode to script + else if(m_command == "getrunmode") + { + debuggingState(true); + sendCommand("setdisplaydelay", "newdelay", QString::number(m_displaydelay).ascii(), (char*)0L); + if(m_executionState == Pause) + sendCommand("pause", (char*)0L); + else if(m_executionState == Run) + sendCommand("run", (char*)0L); + else if(m_executionState == Trace) + sendCommand("trace", (char*)0L); + + sendCommand("seterrormask", "errormask", QString::number(m_errormask).ascii(), (char*)0L); + } + // Just some status info, display on status line + else if(m_command == "status") + { + long argcnt = args["args"].toLong(); + QString msg = i18n(args["message"]); // How will we get these messages throught to the translators? + for(int cnt = 1; cnt <= argcnt; cnt++) + msg.replace("%" + QString("%1").arg(cnt) + "%", args[QString("arg%1").arg(cnt)]); + + debuggerInterface()->showStatus(msg, false); + } + // New current line + else if(m_command == "setactiveline") + { + debuggerInterface()->setActiveLine(mapServerPathToLocal(args["filename"]), args["line"].toLong()); + } + // Script requests breakpointlist + else if(m_command == "sendbreakpoints") + { + sendBreakpoints(); + } + // Parsing failed + else if(m_command == "parsefailed") + { + debuggerInterface()->showStatus(i18n("Syntax or parse error in %1)").arg(args["filenme"]), true); + return; + } + // A debugging session is running + else if(m_command == "debuggingon") + { + debuggingState(true); + } + // No session is running + else if(m_command == "debuggingoff") + { + debuggingState(false); + } + // We stumbled upon an error + else if(m_command == "error") + { + // Put the line number first so double clicking will jump to the corrrect line + debuggerInterface()->showStatus(i18n("Error occurred: Line %1, Code %2 (%3) in %4").arg(args["line"]).arg(args["errnum"]).arg(args["errmsg"]).arg(args["filename"]), true); + + // Filter to get error code only and match it with out mask + long error = args["errnum"].toLong(); + if(m_errormask & error) + setExecutionState(Pause); + else if(m_executionState == Trace) + setExecutionState(Trace); + else if(m_executionState == Run) + setExecutionState(Run); + else + setExecutionState(Pause); + + emit updateStatus(DebuggerUI::HaltedOnError); + } + // We came across a hard coded breakpoint + else if(m_command == "forcebreak") + { + setExecutionState(Pause); + emit updateStatus(DebuggerUI::HaltedOnBreakpoint); + debuggerInterface()->showStatus(i18n("Breakpoint reached"), true); + } + // A conditional breakpoint was fulfilled + else if(m_command == "conditionalbreak") + { + setExecutionState(Pause); + emit updateStatus(DebuggerUI::HaltedOnBreakpoint); + debuggerInterface()->showStatus(i18n("Conditional breakpoint fulfilled"), true); + } + // There is a breakpoint set in this file/line + else if(m_command == "removebreakpoint") + { + debuggerInterface()->havenoBreakpoint(mapServerPathToLocal(args["filename"]), args["line"].toLong()); + } + // We're about to debug a file.. + else if(m_command == "initialize") + { + debuggerInterface()->showStatus(i18n("Established connection to %1").arg(args["filename"]), false); + sendCommand("sendprotocolversion", (char*)0L); + + debuggerInterface()->setActiveLine(mapServerPathToLocal(args["filename"]), 0); + sendCommand("havesource", (char*)0L); + debuggingState(true); + } + else if(m_command == "sendingwatches") + { + //debuggerInterface()->preWatchUpdate(); + } + // Show the contents of a watched variable + else if(m_command == "watch") + { + showWatch(args["variable"]); + } + // Show the contents of a variable + else if(m_command == "variable") + { + showWatch(args["variable"]); + } + // Show the contents of a variable + else if(m_command == "showcondition") + { + showCondition(args); + } + else if(m_command == "sentwatches") + { + //debuggerInterface()->postWatchUpdate(); + } + // Reached en of an include + else if(m_command == "end") + { + //debuggerInterface()->showStatus(i18n("At end of include %1").arg(data), true); + return; + } + // Check protocol version + else if(m_command == "protocolversion") + { + if(args["version"] != protocolversion) + { + debuggerInterface()->showStatus(i18n("The script being debugged does not communicate with the correct protocol version"), true); + sendCommand("die", (char*)0L); + } + return; + } + // Instructions we currently ignore + else if(m_command == "sourcesent" + || m_command == "addsourceline" + ) + {} + else + // Unimplemented command - log to debug output + kdDebug(24002) << "QuantaDebuggerGubed::slotReadyRead Unknown: " << m_command << ":" << datas << endl; +} + +// Turn on/off actions related to a debugging session +void QuantaDebuggerGubed::debuggingState(bool enable) +{ + debuggerInterface()->enableAction("debug_kill", enable); + debuggerInterface()->enableAction("debug_stepout", enable); + debuggerInterface()->enableAction("debug_stepinto", enable); + debuggerInterface()->enableAction("debug_stepover", enable); + debuggerInterface()->enableAction("debug_skip", enable); +} + +void QuantaDebuggerGubed::sendBreakpoints() +{ + debuggerInterface()->refreshBreakpoints(); +} +void QuantaDebuggerGubed::sendWatches() +{ + for(QValueList::iterator it = m_watchlist.begin(); it != m_watchlist.end(); ++it) + sendCommand("getwatch", "variable", (*it).ascii(), (char*)0L); + sendCommand("sentwatches", "key", (char*)0L, (char*)0L); +} + +// Send a command to gubed +bool QuantaDebuggerGubed::sendCommand(const QString& command, StringMap args) +{ + + kdDebug(24002) << k_lineinfo << ", command " << command << " with data: " << phpSerialize(args) << endl; + if(!m_socket || m_socket->state() != KNetwork::KClientSocketBase::Connected) + return false; + + QString buffer = phpSerialize(args); + + buffer = QString(command + ":%1;" + buffer).arg(buffer.length()); + m_socket->writeBlock(buffer, buffer.length()); + return true; +} + +// Send a command to gubed +bool QuantaDebuggerGubed::sendCommand(const QString& command, char * firstarg, ...) +{ + StringMap ca; + char *next; + + va_list l_Arg; + va_start(l_Arg, firstarg); + + next = firstarg; + while(next) + { + ca[(QString)next] = (QString)va_arg(l_Arg, char*); +// kdDebug(24002) << k_lineinfo << " Added arg/valuepair " << next << ", " << ca[next].left(30) << endl; + next = va_arg(l_Arg, char*); + } + + va_end(l_Arg); + sendCommand(command, ca); + return true; +} + +// Return name of debugger +QString QuantaDebuggerGubed::getName() +{ + return "Gubed"; // no i18n on the name +} + +void QuantaDebuggerGubed::showWatch(const QString& data) +{ + debuggerInterface()->showVariable(parsePHPVariables(data)); +} + +// Send HTTP Request +void QuantaDebuggerGubed::request() +{ + QString request; + request = debuggerInterface()->activeFileParts(m_startsession); + + //if(request.startsWith(m_localBasedir, false)) + // request.remove(0, m_localBasedir.length()); + + //request = m_startsession + request; + kdDebug(24002) << k_funcinfo << ", request: " << request << endl; + debuggerInterface()->sendRequest(request); +} + + +// Run boy, run (and show whats happening) +void QuantaDebuggerGubed::trace() +{ + setExecutionState(Trace); +} + +// Go as fast as possible and dont update current line or watches +void QuantaDebuggerGubed::run() +{ + setExecutionState(Run); +} + +// Step into function +void QuantaDebuggerGubed::stepInto() +{ + setExecutionState(Pause); + sendCommand("next", (char*)0L); +} + +// Step over function +void QuantaDebuggerGubed::stepOver() +{ + setExecutionState(Pause); + sendCommand("stepover", (char*)0L); +} + +// Step out of function +void QuantaDebuggerGubed::stepOut() +{ + setExecutionState(Pause); + sendCommand("stepout", (char*)0L); +} + +// Skip next function +void QuantaDebuggerGubed::skip() +{ + sendCommand("skip", (char*)0L); +} + +// Kill the running script +void QuantaDebuggerGubed::kill() +{ + sendCommand("die", (char*)0L); +} + +// Pause execution +void QuantaDebuggerGubed::pause() +{ + setExecutionState(Pause); +} + + +// Add a breakpoint +void QuantaDebuggerGubed::addBreakpoint (DebuggerBreakpoint* breakpoint) +{ + QString type; + if(breakpoint->type() == DebuggerBreakpoint::LineBreakpoint) + type = "line"; + else if(breakpoint->type() == DebuggerBreakpoint::ConditionalTrue) + type = "true"; + else + type = "change"; + + sendCommand("breakpoint", + "type", type.ascii(), + "filename", mapLocalPathToServer(breakpoint->filePath()).ascii(), + "class", breakpoint->inClass().ascii(), + "function", breakpoint->inFunction().ascii(), + "expression", breakpoint->condition().ascii(), + "line", QString::number(breakpoint->line()).ascii(), + (char *)0L); +} + +// QString QuantaDebuggerGubed::bpToGubed(DebuggerBreakpoint* breakpoint) +// { +// return QString("^" + mapLocalPathToServer(breakpoint->filePath()) + +// "^" + breakpoint->inClass() + +// "^" + breakpoint->inFunction() + +// "^" + (breakpoint->type() == DebuggerBreakpoint::ConditionalTrue ? "true" : "change") + +// "^" + breakpoint->condition()); +// } + +// Clear a breakpoint +void QuantaDebuggerGubed::removeBreakpoint(DebuggerBreakpoint* breakpoint) +{ + QString type; + if(breakpoint->type() == DebuggerBreakpoint::LineBreakpoint) + type = "line"; + else if(breakpoint->type() == DebuggerBreakpoint::ConditionalTrue) + type = "true"; + else + type = "change"; + + sendCommand("removebreakpoint", + "type", type.ascii(), + "filename", mapLocalPathToServer(breakpoint->filePath()).ascii(), + "class", breakpoint->inClass().ascii(), + "function", breakpoint->inFunction().ascii(), + "expression", breakpoint->condition().ascii(), + "line", QString::number(breakpoint->line()).ascii(), + (char*)0L); +} + +// A file was opened... +void QuantaDebuggerGubed::fileOpened(const QString&) +{ + sendCommand("reinitialize", (char*)0L); +} + +// Watch a variable +void QuantaDebuggerGubed::addWatch(const QString &variable) +{ + if(m_watchlist.find(variable) == m_watchlist.end()) + m_watchlist.append(variable); + sendCommand("getwatch", "variable", variable.ascii(), (char*)0L); +} +// Remove watch +void QuantaDebuggerGubed::removeWatch(DebuggerVariable *variable) +{ + if(m_watchlist.find(variable->name()) != m_watchlist.end()) + m_watchlist.remove(m_watchlist.find(variable->name())); + //sendCommand("unwatchvariable", var->name()); +} + +// Show conditional breakpoint state +void QuantaDebuggerGubed::showCondition(const StringMap &args) +{ + + DebuggerBreakpoint *bp = debuggerInterface()->newDebuggerBreakpoint(); + bp->setType(args["type"] == "true" ? DebuggerBreakpoint::ConditionalTrue : DebuggerBreakpoint::ConditionalChange); + bp->setCondition(args["expression"]); + bp->setFilePath(mapServerPathToLocal(args["filename"])); + bp->setClass(args["class"]); + bp->setFunction(args["function"]); + bp->setValue(args["value"]); + + bp->setState(DebuggerBreakpoint::Undefined); + + debuggerInterface()->showBreakpoint(*bp); +} + +// Read configuration +void QuantaDebuggerGubed::readConfig(QDomNode node) +{ + // Server + QDomNode valuenode = node.namedItem("serverhost"); + m_serverHost = valuenode.firstChild().nodeValue(); + if(m_serverHost.isEmpty()) + m_serverHost = "localhost"; + + valuenode = node.namedItem("serverport"); + m_serverPort = valuenode.firstChild().nodeValue(); + if(m_serverPort.isEmpty()) + m_serverPort = "8026"; + + valuenode = node.namedItem("localbasedir"); + m_localBasedir = valuenode.firstChild().nodeValue(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setLocalBasedir(m_localBasedir); + + valuenode = node.namedItem("serverbasedir"); + m_serverBasedir = valuenode.firstChild().nodeValue(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setServerBasedir(m_serverBasedir); + + valuenode = node.namedItem("listenport"); + m_listenPort = valuenode.firstChild().nodeValue(); + if(m_listenPort.isEmpty()) + m_listenPort = "8016"; + + valuenode = node.namedItem("startsession"); + m_startsession = valuenode.firstChild().nodeValue(); + if(m_startsession.isEmpty()) + m_startsession = "http://localhost/Gubed/StartSession.php?gbdScript=/%rfpp"; + + valuenode = node.namedItem("defaultexecutionstate"); + if(valuenode.firstChild().nodeValue().isEmpty()) + m_defaultExecutionState = Pause; + else + m_defaultExecutionState = (State)valuenode.firstChild().nodeValue().toUInt(); + + valuenode = node.namedItem("useproxy"); + m_useproxy = valuenode.firstChild().nodeValue() == "1"; + + valuenode = node.namedItem("displaydelay"); + m_displaydelay = valuenode.firstChild().nodeValue().toLong(); + + valuenode = node.namedItem("errormask"); + m_errormask = valuenode.firstChild().nodeValue().toLong(); + kdDebug(24002) << k_funcinfo << ", m_errormask = " << m_errormask << endl; +} + + +// Show configuration +void QuantaDebuggerGubed::showConfig(QDomNode node) +{ + GubedSettings set(protocolversion); + + readConfig(node); + + set.lineServerHost->setText(m_serverHost); + set.lineServerPort->setText(m_serverPort); + set.lineLocalBasedir->setText(m_localBasedir); + set.lineServerBasedir->setText(m_serverBasedir); + set.lineServerListenPort->setText(m_listenPort); + set.checkUseProxy->setChecked(m_useproxy); + set.sliderDisplayDelay->setValue(m_displaydelay); + set.lineStartSession->setText(m_startsession); + set.comboDefaultExecutionState->setCurrentItem((int)m_defaultExecutionState); + + set.checkBreakOnNotice->setChecked(QuantaDebuggerGubed::Notice & m_errormask); + set.checkBreakOnWarning->setChecked(QuantaDebuggerGubed::Warning & m_errormask); + set.checkBreakOnUserNotice->setChecked(QuantaDebuggerGubed::User_Notice & m_errormask); + set.checkBreakOnUserWarning->setChecked(QuantaDebuggerGubed::User_Warning & m_errormask); + set.checkBreakOnUserError->setChecked(QuantaDebuggerGubed::User_Error & m_errormask); + + if(set.exec() == QDialog::Accepted ) + { + QDomElement el; + + el = node.namedItem("serverhost").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("serverhost"); + node.appendChild( el ); + m_serverHost = set.lineServerHost->text(); + el.appendChild(node.ownerDocument().createTextNode(m_serverHost)); + + el = node.namedItem("serverport").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("serverport"); + node.appendChild( el ); + m_serverPort = set.lineServerPort->text(); + el.appendChild( node.ownerDocument().createTextNode(m_serverPort) ); + + el = node.namedItem("localbasedir").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("localbasedir"); + node.appendChild( el ); + m_localBasedir = set.lineLocalBasedir->text(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setLocalBasedir(m_localBasedir); + el.appendChild( node.ownerDocument().createTextNode(m_localBasedir) ); + + el = node.namedItem("serverbasedir").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("serverbasedir"); + node.appendChild( el ); + m_serverBasedir = set.lineServerBasedir->text(); + if(debuggerInterface()) + debuggerInterface()->Mapper()->setServerBasedir(m_serverBasedir); + el.appendChild( node.ownerDocument().createTextNode(m_serverBasedir) ); + + el = node.namedItem("useproxy").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("useproxy"); + node.appendChild( el ); + m_useproxy = set.checkUseProxy->isChecked(); + el.appendChild( node.ownerDocument().createTextNode(m_useproxy ? "1" : "0") ); + + el = node.namedItem("listenport").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("listenport"); + node.appendChild( el ); + m_listenPort = set.lineServerListenPort->text(); + el.appendChild( node.ownerDocument().createTextNode(m_listenPort) ); + + el = node.namedItem("startsession").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("startsession"); + node.appendChild( el ); + m_startsession = set.lineStartSession->text(); + el.appendChild(node.ownerDocument().createTextNode(m_startsession)); + + el = node.namedItem("defaultexecutionstate").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("defaultexecutionstate"); + node.appendChild( el ); + m_defaultExecutionState = (State)set.comboDefaultExecutionState->currentItem(); + el.appendChild(node.ownerDocument().createTextNode(QString::number(m_defaultExecutionState))); + + + el = node.namedItem("displaydelay").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("displaydelay"); + node.appendChild( el ); + m_displaydelay = set.sliderDisplayDelay->value(); + el.appendChild( node.ownerDocument().createTextNode(QString::number(m_displaydelay))); + + el = node.namedItem("errormask").toElement(); + if (!el.isNull()) + el.parentNode().removeChild(el); + el = node.ownerDocument().createElement("errormask"); + node.appendChild( el ); + m_errormask = (set.checkBreakOnNotice->isChecked() ? QuantaDebuggerGubed::Notice : 0) + + (set.checkBreakOnWarning->isChecked() ? QuantaDebuggerGubed::Warning : 0) + + (set.checkBreakOnUserNotice->isChecked() ? QuantaDebuggerGubed::User_Notice : 0) + + (set.checkBreakOnUserWarning->isChecked() ? QuantaDebuggerGubed::User_Warning : 0) + + (set.checkBreakOnUserError->isChecked() ? QuantaDebuggerGubed::User_Error : 0); + kdDebug(24002) << k_funcinfo << ", m_errormask = " << m_errormask << endl; + el.appendChild( node.ownerDocument().createTextNode(QString::number(m_errormask))); + + } +} + +// Map a server filepath to a local one using project settings +QString QuantaDebuggerGubed::mapServerPathToLocal(const QString& serverpath) +{ + // Translate filename from server to local + return debuggerInterface()->Mapper()->mapServerPathToLocal(serverpath); +} + +// Map a local filepath to a server one using project settings +QString QuantaDebuggerGubed::mapLocalPathToServer(const QString& localpath) +{ + // Translate filename from local to server + return debuggerInterface()->Mapper()->mapLocalPathToServer(localpath); +} + +void QuantaDebuggerGubed::variableSetValue(const DebuggerVariable &variable) +{ + sendCommand("setvariable", + "variable", variable.name().ascii(), + "value", variable.value().ascii(), + (char*)0L); +} + +QString QuantaDebuggerGubed::phpSerialize(StringMap args) +{ + StringMap::Iterator it; + // a:2:{s:4:"name";s:7:"Jessica";s:3:"age";s:2:"26";s:4:"test";i:1;} + QString ret = QString("a:%1:{").arg(args.size()); + for( it = args.begin(); it != args.end(); ++it ) + { + bool isNumber; + + it.data().toInt(&isNumber); + if(isNumber && !it.data().isEmpty()) + ret += QString("s:%1:\"%2\";i:%3;") + .arg(it.key().length()) + .arg(it.key()) + .arg(it.data()); + else + ret += QString("s:%1:\"%2\";s:%3:\"%4\";") + .arg(it.key().length()) + .arg(it.key()) + .arg(it.data().length()) + .arg(it.data()); + + } + + ret += "}"; + return ret; +} + + +StringMap QuantaDebuggerGubed::parseArgs(const QString &args) +{ + StringMap ca; + long cnt, length; + + // a:2:{s:4:"name";s:7:"Jessica";s:3:"age";s:2:"26";s:4:"test";i:1;} + + // No args + if(args.isEmpty() || args == "a:0:{}") + return ca; + + // Make sure we have a good string + if(!args.startsWith("a:")) + { + kdDebug(24002) << k_funcinfo << "An error occurred in the communication link, data received was:" << args << endl; + return ca; + } + + cnt = args.mid(2, args.find("{") - 3).toLong(); + QString data = args.mid(args.find("{") + 1); + + QString tmp, func; + while(cnt > 0) + { + tmp = data.left(data.find("\"")); + length = tmp.mid(2, tmp.length() - 3).toLong(); + + func = data.mid(tmp.length() + 1, length); + data = data.mid( tmp.length() + length + 3); + + if(data.left(1) == "i") + { + // Integer data + tmp = data.mid(data.find(":") + 1); + tmp = tmp.left(tmp.find(";")); + ca[func] = tmp; + data = data.mid(tmp.length() + 3); +// kdDebug(24002) << k_funcinfo << "**i " << func << ": " << ca[func] << endl; + } + else + { + // String data + tmp = data.left(data.find("\"")); + length = tmp.mid(2, tmp.length() - 3).toLong(); + + ca[func] = data.mid(tmp.length() + 1, length); + data = data.mid( tmp.length() + length + 3); +// kdDebug(24002) << k_funcinfo << "**s " << func << ": " << ca[func] << endl; + } + + cnt--; + } + + return ca; +} + +DebuggerVariable* QuantaDebuggerGubed::parsePHPVariables(const QString &varstring) +{ + QString str = varstring; + DebuggerVariable* var = parsePHPVariables(str); + return var; +} + +DebuggerVariable* QuantaDebuggerGubed::parsePHPVariables(QString &str) +{ + QString key, data; + QString tempstring; + int length; + DebuggerVariable* debuggervar = NULL; + + // get type of key + QString type = str.left(1); + str.remove(0, 2); + + // Strings + if(type == "s") + { + // Get length of key + tempstring = str.left(str.find(':')); + str.remove(0, str.find(':') + 1); + length = tempstring.toUInt(); + + key = str.left(length + 1); + key.remove(0, 1); // remove starting quote + str.remove(0, length + 3); + } + else if(type == "i") + { + key = str.left(str.find(';')); + str.remove(0, str.find(';') + 1); + + } + + // Get type of data + type = str.left(1); + str.remove(0, 2); + + if(type == "i") + { + /* Example: + s:4:"$row";i:6; + */ + data = str.left(str.find(';')); + str.remove(0, str.find(';') + 1); + debuggervar = debuggerInterface()->newDebuggerVariable(key, data, DebuggerVariableTypes::Integer); + + } + else if(type == "b") + { + /* Example: + s:8:"$boolvar";b:1; + */ + data = str.left(str.find(';')); + data = (data == "0" ? i18n("False"): i18n("True")); + str.remove(0, str.find(';') + 1); + debuggervar = debuggerInterface()->newDebuggerVariable(key, data, DebuggerVariableTypes::Boolean); + } + else if(type == "N") + { + /* Example: + s:6:"return";N; + */ + debuggervar = debuggerInterface()->newDebuggerVariable(key, i18n(""), DebuggerVariableTypes::Undefined); + } + else if(type == "s") + { + /* Example: + s:7:"$strvar";s:16:"This is a string"; + */ + + // Get length of string + tempstring = str.left(str.find(':')); + str.remove(0, str.find(':') + 1); + length = tempstring.toUInt(); + + data = str.left(length + 1); + data.remove(0, 1); // remove starting quote + str.remove(0, length + 3); + debuggervar = debuggerInterface()->newDebuggerVariable(key, data, DebuggerVariableTypes::String); + debuggervar->setSize(length); + } + else if(type == "a") + { + /* Example: + s:6:"$array";a:5:{s:11:"Ingredients";a:3:{i:0;s:8:"potatoes";i:1;s:4:"salt";i:2;s:6:"pepper";}s:6:"Guests";a:4:{i:0;s:5:"Fiona";i:1;s:4:"Tori";i:2;s:4:"Neil";i:3;s:4:"Nick";}s:4:"Dogs";a:4:{i:0;s:5:"Kitty";i:1;s:5:"Tessy";i:2;s:5:"Fanny";i:3;s:5:"Cosmo";}s:7:"Numbers";a:6:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:9;i:4;i:8;i:5;i:7;}s:6:"Letter";s:1:"L";} + */ + + // Get length of array + tempstring = str.left(str.find(':')); + str.remove(0, str.find(':') + 2); + length = tempstring.toUInt(); + + QPtrList vars ; + while(length > 0) + { + //kdDebug(24002) << "VariablesListView::parsePHPVariables: length " << length << ", \"" << str << "\"" << endl; + + length --; + DebuggerVariable* var = parsePHPVariables(str); + if(var) + vars.append(var); + + } + str.remove(0, 1); + debuggervar = debuggerInterface()->newDebuggerVariable(key, vars, DebuggerVariableTypes::Array); + } + else if(type == "O") + { + /* Example: + + */ + + // Get length of array + tempstring = str.left(str.find(':')); + str.remove(0, str.find(':') + 2); + tempstring = str.mid(str.find(':') + 1); + tempstring = tempstring.left(tempstring.find(':')); + length = tempstring.toUInt(); + + str.remove(0, str.find('{') + 1); + + QPtrList vars ; + while(length > 0) + { + //kdDebug(24002) << "VariablesListView::parsePHPVariables: length " << length << ", \"" << str << "\"" << endl; + + length --; + DebuggerVariable* var = parsePHPVariables(str); + if(var) + vars.append(var); + + } + str.remove(0, 1); + debuggervar = debuggerInterface()->newDebuggerVariable(key, vars, DebuggerVariableTypes::Object); + } + else if(type == "d") + { + /* Example: + s:9:"$floatvar";d:12.5600000000000004973799150320701301097869873046875;" + */ + data = str.left(str.find(';')); + str.remove(0, str.find(';') + 1); + debuggervar = debuggerInterface()->newDebuggerVariable(key, data, DebuggerVariableTypes::Float); + + } + else if(type == "-") + { + debuggervar = debuggerInterface()->newDebuggerVariable(key, i18n(""), DebuggerVariableTypes::Undefined); + } + else if(type == "!") + { + debuggervar = debuggerInterface()->newDebuggerVariable(key, i18n(""), DebuggerVariableTypes::Error); + } + else + { + kdDebug(24002) << "VariablesListView::parsePHPVariables: Unknown variable type " << type << ", " << str << endl; + debuggervar = debuggerInterface()->newDebuggerVariable(key, i18n(""), DebuggerVariableTypes::Error); + } + + return debuggervar; + +} + + +#include "quantadebuggergubed.moc" diff --git a/quanta/components/debugger/gubed/quantadebuggergubed.desktop b/quanta/components/debugger/gubed/quantadebuggergubed.desktop new file mode 100644 index 00000000..d2020cb7 --- /dev/null +++ b/quanta/components/debugger/gubed/quantadebuggergubed.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Type=Service +Name=Gubed +Name[ne]=ग्युब्ड +Name[ta]=குபெட் +Comment=Quanta debugger plugin to interact with the Gubed PHP debugger, see http://gubed.sf.net +Comment[bg]=Приставка на Quanta за връзка с дебъгера Gubed PHP, http://gubed.sf.net +Comment[ca]=Connector de depuració pel Quanta que interactua amb el depurador Gubed PHP, consulteu http://gubed.sf.net +Comment[cs]=Ladicí modul Quanty s Gubed PHP debuggerem, viz http://gubed.sf.net +Comment[da]=Quanta fejlretter-plugin til at virke sammen med Gubed PHP fejlretter, se http://gubed.sf.net +Comment[de]=Debug-Komponente von Quanta für die Unterstützung des Gubed PHP-Debuggers. Näheres siehe http://gubed.sf.net +Comment[el]=Αποσφαλματωτής Quanta σε συνεργασία με το αποσφαλματωτή Gubed PHP, δείτε http://gubed.sf.net +Comment[es]=Accesorio de depuración de Quanta, para interactuar con el depurador de PHP Gubed. Vea http://gubed.sf.net +Comment[et]=Quanta siluriplugin koostööks PHP siluriga Gubed (vaata http://gubed.sf.net) +Comment[eu]=Gubed PHP araztailearekin lan egiteko Quanta araztailearen plugina, ikusi http://gubed.sf.net +Comment[fa]=وصلۀ اشکال‌زدای Quanta برای تعامل با اشکال‌زدای Gubed PHP، http://gubed.sf.net را ببینید +Comment[fi]=Gubed PHP debuggerin plugin Quantan debuggeriin (katso http://gubed.sf.net) +Comment[fr]=Module de débogage de Quanta pour interagir avec le débogueur PHP Gubed ; consulter http://gubed.sf.net. +Comment[gl]=Plugin de depuración de Quanta para interactuar co depurador de PHP Gubed, vexa tamén http://gubed.sf.net +Comment[hu]=Quanta-nyomkövető (bővítőmodulként) a Gubed PHP-nyomkövetőhöz, lásd: http://gubed.sf.net +Comment[is]=Quanta aflúsunaríforrit til samskipta við Gubed PHP aflúsarann. Sjá http://gubed.sf.net +Comment[it]=Plugin debugger di Quanta per interagire con il debugger PHP Gubed, vedi http://gubed.sf.net +Comment[ja]=Gubed PHP デバッガと対話する Quanta デバッガ。詳細は http://gubed.sf.net +Comment[ka]=Quanta-ს განბზიკვის მოდული Gubed PHP განბზიკავთან დასაკავშირებლად, იხილეთ http://gubed.sf.net +Comment[lt]=Quanta derintuvės priedas skirtas dirbti su Gubed PHP derintuve, žr.http://gubed.sf.net +Comment[ms]=Plug masuk penyah-ralat Quanta untuk berinteraksi dengan penyah-ralat Gubed PHP, lihat http://gubed.sf.net +Comment[nds]=Fehlersöök-Moduul för Quanta för't Tosamenwarken mit den PHP-Fehlersöker "Gubed", kiek op http://gubed.sf.net +Comment[ne]=ग्युब्ड पीएचपी त्रुटिमोचकसँग अन्तर्क्रिया गर्नका लागि क्वान्टा त्रुटिमोचक प्लगइन, http://gubed.sf.net हेर्नुहोस् +Comment[nl]=Quanta debugger plugin om te communiceren met de Gubed PHP debugger, zie http://gubed.sf.net +Comment[pl]=Wtyczka debuggera Quanty współpracująca z debuggerem PHP Gubed , patrz http://gubed.sf.net +Comment[pt]='Plugin' de Depuração do Quanta para interagir com o depurador de PHP Gubed, veja http://gubed.sf.net +Comment[pt_BR]=Plugin do debugger do Quanta para interagir com o debugger PHP Gubed, olhe http://gubed.sf.net +Comment[ru]=Модуль отладчика Quanta для связи с Gubed, отладчиком PHP, см. http://gubed.sf.net +Comment[sk]=Quanta debuger modul pre interakciu s Gubed PHP debugerom, pozrihttp://gubed.sf.net +Comment[sl]=Vstavek razhroščevanja v Quanti, ki sodeluje z razhroščevalnikom Gubed PHP, glejte http://gubed.sf.net +Comment[sr]=Исправљачки прикључак Quanta-е за интеракцију са исправљачем PHP-а Gubed, погледајте http://gubed.sf.net +Comment[sr@Latn]=Ispravljački priključak Quanta-e za interakciju sa ispravljačem PHP-a Gubed, pogledajte http://gubed.sf.net +Comment[sv]=Quanta-insticksprogram för felsökning som fungerar med PHP-felsökaren Gubed, se http://gubed.sf.net +Comment[ta]=குவாண்டா வழுநீக்கி உள்ளீடு குபெட்PHP வழுநீக்கியோடு தொடர்புக் கொண்டிருக்கிறது, பார்க்கவும் http://gubed.sf.net +Comment[tg]=Модули ғалатёби Quanta барои алоқаи аз Gubed, ғалатёби PHP, нишон кунед http://gubed.sf.net +Comment[tr]=Gubed PHP hata ayıklayıcısıyla iletişim kurmayı sağlayan Quanta hata ayıklama eklentisi, http://gubed.sf.net adresini ziyaret edin +Comment[uk]=Втулок зневадження Quanta для зв'язку зі зневаджувачем PHP -- Gubed, див. http://gubed.sf.net +Comment[zh_CN]=与 Gubed PHP 调试器交互 Quanta 调试器插件,见 http://gubed.sf.net +Comment[zh_HK]=Quanta 對於 Gubed PHP 除錯器的通訊外掛程式, 請參閱 http://gubed.sf.net +Comment[zh_TW]=Quanta 對於 Gubed PHP 除錯器的通訊外掛程式, 請參閱 http://gubed.sf.net +Icon=kdbg +ServiceTypes=Quanta/Debugger +X-KDE-Library=quantadebuggergubed diff --git a/quanta/components/debugger/gubed/quantadebuggergubed.h b/quanta/components/debugger/gubed/quantadebuggergubed.h new file mode 100644 index 00000000..62acac0b --- /dev/null +++ b/quanta/components/debugger/gubed/quantadebuggergubed.h @@ -0,0 +1,153 @@ +/*************************************************************************** + phpdebuggubed.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 QUANTADEBUGGERGUBED_H +#define QUANTADEBUGGERGUBED_H + +#include +#include +#include +#include +#include + +#include "debuggerclient.h" + +typedef QValueList WatchList; +typedef QMap StringMap; + +class QuantaDebuggerGubed : public DebuggerClient +{ + Q_OBJECT + + public: + QuantaDebuggerGubed(QObject *parent, const char* name, const QStringList&); + ~QuantaDebuggerGubed(); + + // Execution states + enum State + { + Pause = 0, + Trace, + Run + }; + // Error codes + enum Errors + { + Warning = 2, + Notice = 8, + User_Error = 256, + User_Warning = 512, + User_Notice = 1024 + }; + + // Protocol version + static const char protocolversion[]; + + // Manager interaction + const uint supports(DebuggerClientCapabilities::Capabilities); + + // Execution control + void request(); + void trace(); + void run(); + void skip(); + void stepInto(); + void stepOver(); + void stepOut(); + void pause(); + void kill(); + void setExecutionState(State newstate); + + // Connection + void startSession(); + void endSession(); + + // Return name of debugger + QString getName(); + + // New file opened in quanta + void fileOpened(const QString& file); + + // Settings + void readConfig(QDomNode node); + void showConfig(QDomNode node); + + // Breakpoints + void addBreakpoint(DebuggerBreakpoint* breakpoint); + void removeBreakpoint(DebuggerBreakpoint* breakpoint); + void showCondition(const StringMap &args); + + // Variables + void addWatch(const QString &variable); + void removeWatch(DebuggerVariable *var); + void variableSetValue(const DebuggerVariable &variable); + + private: + KNetwork::KStreamSocket *m_socket; + KNetwork::KServerSocket *m_server; + QString m_command, m_buffer; + long m_datalen; + + QString m_serverBasedir; + QString m_localBasedir; + QString m_serverPort; + QString m_serverHost; + QString m_startsession; + QString m_listenPort; + bool m_useproxy; + State m_executionState, m_defaultExecutionState; + long m_errormask; + long m_displaydelay; + + WatchList m_watchlist; + +// bool sendCommand(const QString&, const QString&); + bool sendCommand(const QString& command, StringMap args); + bool sendCommand(const QString& command, char * firstarg, ...); + + void processCommand(const QString&); + void sendWatches(); + void sendBreakpoints(); + void debuggingState(bool enable); + void connected(); + + QString mapServerPathToLocal(const QString& serverpath); + QString mapLocalPathToServer(const QString& localpath); + QString bpToGubed(DebuggerBreakpoint* breakpoint); + + // Communication helpers + QString phpSerialize(StringMap args); + StringMap parseArgs(const QString &args); + + // Variables + DebuggerVariable* parsePHPVariables(const QString &varstring); + DebuggerVariable* parsePHPVariables(QString &str); + void showWatch(const QString& data); + + + public slots: + // Socket slots + void slotConnected(const KNetwork::KResolverEntry &); + void slotConnectionClosed(); + void slotError(int error); + void slotReadyRead(); + void slotReadyAccept(); + + signals: + void updateStatus(DebuggerUI::DebuggerStatus); +}; + +#endif diff --git a/quanta/components/debugger/interfaces/Makefile.am b/quanta/components/debugger/interfaces/Makefile.am new file mode 100644 index 00000000..dba1986b --- /dev/null +++ b/quanta/components/debugger/interfaces/Makefile.am @@ -0,0 +1,17 @@ + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdebuggerinterface.la +libdebuggerinterface_la_LDFLAGS = $(all_libraries) +libdebuggerinterface_la_SOURCES = debuggerinterface.cpp debuggerclient.cpp + + +# Definition of the service type +kde_servicetypes_DATA = quantadebugger.desktop + + +INCLUDES = -I$(top_srcdir)/quanta/components/debugger \ + -I$(top_srcdir)/quanta/components/debugger/interfaces \ + -I$(top_srcdir)/quanta/project \ + -I$(top_srcdir)/utility \ + $(all_includes) diff --git a/quanta/components/debugger/interfaces/debuggerclient.cpp b/quanta/components/debugger/interfaces/debuggerclient.cpp new file mode 100644 index 00000000..8c3196d9 --- /dev/null +++ b/quanta/components/debugger/interfaces/debuggerclient.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + debuggerclient.cpp + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + Based on work by Mathieu Kooiman + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "debuggerclient.h" +#include "debuggerinterface.h" +#include +#include +#include + + +// CTor +DebuggerClient::DebuggerClient(QObject *parent, const char* name) + : QObject(parent, name) +{ + m_active = false; +} + + +DebuggerInterface* DebuggerClient::debuggerInterface() +{ + return static_cast( parent()->child( 0, "DebuggerInterface" ) ); +} + +// Active state of session +bool DebuggerClient::isActive() +{ + return m_active; +} + +void DebuggerClient::unSupportedAction(const QString &action) +{ + KMessageBox::error(NULL, i18n("The current debugger, %1, does not support the \"%2\" instruction.").arg(this->getName()).arg(action), i18n("Unsupported Debugger Function")); + +} + +// Unimplemented defaults - Pause execution +void DebuggerClient::pause() +{ + unSupportedAction(i18n("Pause")); +} + +// Unimplemented defaults - Send Request +void DebuggerClient::request() +{ + unSupportedAction(i18n("Send HTTP Request")); +} + +// Unimplemented defaults - step over +void DebuggerClient::stepOver() +{ + unSupportedAction(i18n("Step Over")); + +} + +// Unimplemented defaults - step out +void DebuggerClient::stepOut() +{ + unSupportedAction(i18n("Step Out")); + +} + +// Unimplemented defaults - trace +void DebuggerClient::trace() +{ + unSupportedAction(i18n("Trace")); +} +// Unimplemented defaults - Run +void DebuggerClient::run() +{ + unSupportedAction(i18n("Run")); +} +// Unimplemented defaults - skip +void DebuggerClient::skip() +{ + unSupportedAction(i18n("Skip")); +} +// Unimplemented defaults - stepInto +void DebuggerClient::stepInto() +{ + unSupportedAction(i18n("Step Into")); +} +// Unimplemented defaults - kill +void DebuggerClient::kill() +{ + unSupportedAction(i18n("Kill")); + +} + +// Unimplemented defaults +void DebuggerClient::profilerOpen( ) +{ + unSupportedAction(i18n("Open Profiler Output")); +} + +// Unimplemented defaults +void DebuggerClient::fileOpened(const QString&) +{ + return; +} + +// Unimplemented defaults +void DebuggerClient::addBreakpoint(DebuggerBreakpoint*) +{ + unSupportedAction(i18n("Set Breakpoint")); + +} + +// Unimplemented defaults +void DebuggerClient::removeBreakpoint(DebuggerBreakpoint*) +{ + unSupportedAction(i18n("Remove Breakpoint")); +} + + +// Unimplemented defaults +void DebuggerClient::showConfig(QDomNode) +{ + KMessageBox::error(NULL, i18n("%1 does not have any specific settings.").arg(this->getName()), i18n("Settings")); +} + +// Unimplemented defaults +void DebuggerClient::readConfig(QDomNode) +{ + +} + +// Unimplemented defaults: add watch +void DebuggerClient::addWatch(const QString &) +{ + KMessageBox::error(NULL, i18n("%1 does not support watches.").arg(this->getName()), i18n("Unsupported Debugger Function")); +} + +// Unimplemented defaults: Remove watch +void DebuggerClient::removeWatch(DebuggerVariable *) +{ + // Giving an error seems pointless, since you shouldnt be able to add a watch in the first place... + KMessageBox::error(NULL, i18n("%1 does not support watches.").arg(this->getName()), i18n("Unsupported Debugger Function")); +} + +// Unimplemented defaults: set value of varialbe +void DebuggerClient::variableSetValue(const DebuggerVariable &) +{ + KMessageBox::error(NULL, i18n("%1 does not support setting the value of variables.").arg(this->getName()), i18n("Unsupported Debugger Function")); +} + +#include "debuggerclient.moc" diff --git a/quanta/components/debugger/interfaces/debuggerclient.h b/quanta/components/debugger/interfaces/debuggerclient.h new file mode 100644 index 00000000..d50526cc --- /dev/null +++ b/quanta/components/debugger/interfaces/debuggerclient.h @@ -0,0 +1,115 @@ +/*************************************************************************** + phpdebugsocket.h + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + Based on work by Mathieu Kooiman + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 _DEBUGGERCLIENT_H +#define _DEBUGGERCLIENT_H + +#include +#include +#include +#include + +#include "debuggerui.h" + +class DebuggerInterface; +class DebuggerBreakpoint; +class DebuggerVariable; + +namespace DebuggerClientCapabilities +{ + enum Capabilities + { + // Session related + StartSession = 1000, + EndSession, + + // Breakpoint related + LineBreakpoints = 2000, + ConditionalBreakpoints, + + // Variable related + Watches = 4000, + VariableSetValue, + + // Execution related + Run = 5000, + Trace, + Pause, + Kill, + StepInto, + StepOver, + StepOut, + Skip, + + // Profiler related + ProfilerOpen = 6000 + }; +} + +class DebuggerClient : public QObject +{ + Q_OBJECT + + private: + protected: + DebuggerClient(QObject *parent, const char* name); + + bool m_active; + + public: + virtual const uint supports(DebuggerClientCapabilities::Capabilities) = 0; + virtual void startSession() = 0; + virtual void endSession() = 0; + virtual QString getName() = 0; + + // Execution control + virtual void request(); + virtual void run(); + virtual void trace(); + virtual void skip(); + virtual void stepOver(); + virtual void stepInto(); + virtual void stepOut(); + virtual void kill(); + virtual void pause(); + + // Settings + virtual void readConfig(QDomNode node); + virtual void showConfig(QDomNode node); + + // Profiler + virtual void profilerOpen(); + + // Misc + virtual void fileOpened(const QString& file); + virtual void addBreakpoint(DebuggerBreakpoint* breakpoint); + virtual void removeBreakpoint(DebuggerBreakpoint* breakpoint); + virtual void addWatch(const QString &); + virtual void removeWatch(DebuggerVariable*); + virtual void variableSetValue(const DebuggerVariable &variable); + + void unSupportedAction(const QString &action); + + bool isActive(); + DebuggerInterface *debuggerInterface(); + + signals: + void updateStatus(DebuggerUI::DebuggerStatus); + +}; + +#endif diff --git a/quanta/components/debugger/interfaces/debuggerinterface.cpp b/quanta/components/debugger/interfaces/debuggerinterface.cpp new file mode 100644 index 00000000..5481180c --- /dev/null +++ b/quanta/components/debugger/interfaces/debuggerinterface.cpp @@ -0,0 +1,26 @@ +/*************************************************************************** + debuggerinterface.cpp + --------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "debuggerinterface.h" + +DebuggerInterface::DebuggerInterface (QObject *parent, const char* name) + : QObject(parent, name) +{ +} + + +#include "debuggerinterface.moc" diff --git a/quanta/components/debugger/interfaces/debuggerinterface.h b/quanta/components/debugger/interfaces/debuggerinterface.h new file mode 100644 index 00000000..8c527979 --- /dev/null +++ b/quanta/components/debugger/interfaces/debuggerinterface.h @@ -0,0 +1,80 @@ +/*************************************************************************** + debuggerinterface.h + ------------------- + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 DEBUGGERINTERFACE_H +#define DEBUGGERINTERFACE_H + +#include +#include +#include + +#include "debuggervariable.h" +#include "debuggerbreakpoint.h" +#include "backtracelistview.h" + +class PathMapper; + +class DebuggerInterface : public QObject +{ + Q_OBJECT + + private: + + + public: + DebuggerInterface(QObject *parent, const char* name); + + // Breakpoints + virtual void haveBreakpoint (const QString& file, int line) = 0; + virtual void havenoBreakpoint (const QString& file, int line) = 0; + + // Public help functions + virtual bool showStatus(const QString& message, bool log) = 0; + virtual bool setActiveLine (const QString& file, int line) = 0; + + virtual void enableAction(const QString& action, bool enable) = 0; + virtual void fileOpened(const QString& file) = 0; + virtual void sendRequest(const KURL &url) = 0; + virtual const QString activeFileParts(const QString & str) = 0; + + // Watch handling + //virtual void preWatchUpdate() = 0; + //virtual void postWatchUpdate() = 0; + + virtual DebuggerVariable* newDebuggerVariable(const QString& name, const QString& value, int type) = 0; + virtual DebuggerVariable* newDebuggerVariable(const QString& name, const ValueList_t& values, int type) = 0; + virtual void showVariable(DebuggerVariable*) = 0; + + // Backtrace + virtual void backtraceClear() = 0; + virtual void backtraceShow(long level, BacktraceType type, const QString &filename, long line, const QString& func) = 0; + + + // Breakpoints + virtual void showBreakpoint(const DebuggerBreakpoint &bp) = 0; + virtual void refreshBreakpoints() = 0; + virtual DebuggerBreakpoint * newDebuggerBreakpoint() = 0; + virtual DebuggerBreakpoint * findDebuggerBreakpoint(const QString& key) = 0; + virtual void updateBreakpointKey(const DebuggerBreakpoint &bp, const QString& newkey) = 0; + + // Path mapping + virtual PathMapper* Mapper() = 0; +}; + +#endif + + diff --git a/quanta/components/debugger/interfaces/quantadebugger.desktop b/quanta/components/debugger/interfaces/quantadebugger.desktop new file mode 100644 index 00000000..56d05e04 --- /dev/null +++ b/quanta/components/debugger/interfaces/quantadebugger.desktop @@ -0,0 +1,45 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Quanta/Debugger +Comment=A Quanta Debugger plugin +Comment[bg]=Приставка на Quanta за дебъгване +Comment[br]=Ul lugent dizraener Quanta +Comment[ca]=Un connector de depuració pel Quanta +Comment[cs]=Ladicí modul Quanty +Comment[da]=Et Quanta fejlretter-plugin +Comment[de]=Eine Quanta Debugger-Komponente +Comment[el]=Πρόσθετο αποσφαλματωτή Quanta +Comment[es]=Un accesorio para un depurador de Quanta +Comment[et]=Quanta siluriplugin +Comment[eu]=Quanta araztailearen plugina +Comment[fa]=وصلۀ اشکال‌زدای Quanta +Comment[fi]=Quantan debuggerin plugin +Comment[fr]=Un module de débogage pour Quanta +Comment[ga]=Breiseán dífhabhtóra Quanta +Comment[gl]=Un plugin para o depurador de Quanta +Comment[hu]=Quanta nyomkövető-modul +Comment[is]=Quanta aflúsunaríforrit +Comment[it]=Un plugin debugger di Quanta +Comment[ja]=Quanta デバッガプラグイン +Comment[ka]=Quanta-ს განბზიკვის მოდული +Comment[lt]=Quanta derintuvės priedas +Comment[ms]=Plug masuk penyah-ralat Quanta +Comment[nds]=En Fehlersöök-Komponent för Quanta +Comment[ne]=एउटा क्वान्टा त्रुटिमोचक प्लगइन +Comment[nl]=Een Quanta debugger-plugin +Comment[pl]=Wtyczka debuggera Quanty +Comment[pt]=Um 'plugin' de depuração para o Quanta +Comment[pt_BR]=Um plugin do Debugger do Quanta +Comment[ru]=Модуль отладки Quanta +Comment[sk]=Quanta debuger modul +Comment[sl]=Vstavek razhroščevanja v Quanti +Comment[sr]=Исправљачки прикључак Quanta-е +Comment[sr@Latn]=Ispravljački priključak Quanta-e +Comment[sv]=Ett Quanta-insticksprogram för felsökning +Comment[ta]=குவாண்டா வழுநீக்கி சொருகு +Comment[tg]=Модули ғалатёби Quanta +Comment[tr]=Bir Quanta Hata Ayıklayıcı eklentisi +Comment[uk]=Втулок зневадження Quanta +Comment[zh_CN]=Quanta 调试器插件 +Comment[zh_HK]=一個 Quanta 除錯器的外掛程式 +Comment[zh_TW]=一個 Quanta 除錯器的外掛程式 diff --git a/quanta/components/debugger/pathmapper.cpp b/quanta/components/debugger/pathmapper.cpp new file mode 100644 index 00000000..194355d7 --- /dev/null +++ b/quanta/components/debugger/pathmapper.cpp @@ -0,0 +1,228 @@ +/*************************************************************************** + pathmapper.h + ------------------------ + begin : 2004-10-10 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "pathmapper.h" +#include "pathmapperdialog.h" + +#include "quantacommon.h" +#include "project.h" + +#include +#include +#include +#include +#include + +PathMapper::PathMapper(QObject *parent, const char *name) + : QObject(parent, name) +{ + +} + +PathMapper::PathMapper() +{ + +} + +QString PathMapper::translate(const QString & path, const QString & from, const QString &to) +{ + QString translated = path; + + // Check if this dir is matched by the maps + if(path.startsWith(from, false)) + { + translated.remove(0, from.length()); + translated = to + translated; + } + + return translated; +} + +QString PathMapper::mapLocalPathToServer(const QString &localpath) +{ + if(localpath.isEmpty()) + return localpath; + + if(m_localBasedir == "/" && m_serverBasedir == "/") + return localpath; + + QString newpath = translate(localpath, m_localBasedir, m_serverBasedir); + + // If no translation occurred, check and see if some of the other translations does + if(newpath == localpath) + { + for (unsigned int cnt = 0; cnt < m_serverlist.count(); cnt++ ) + { + // If the entire filename matches, count it as a match even if there is no difference + if(m_locallist[cnt] == localpath) + return localpath; + + // If both are slashes, count it as a local project + if(m_locallist[cnt] == "/" && m_serverlist[cnt] == "/") + return localpath; + + // Check if it translates into something + newpath = translate(localpath, m_locallist[cnt], m_serverlist[cnt]); + if(newpath != localpath) + { + addHistory(localpath, newpath, true); + return newpath; + } + } + + // No translation found -> show dialog + PathMapperDialog pmdlg(localpath, PathMapperDialog::LocalToServer); + for (unsigned int cnt = 0; cnt < m_serverlist.count(); cnt++ ) + pmdlg.addHistory(m_serverlist[cnt], m_locallist[cnt]); + + if(pmdlg.exec() == QDialog::Accepted ) + { + newpath = translate(localpath, pmdlg.localPath(), pmdlg.serverPath()); + addHistory(pmdlg.localPath(), pmdlg.serverPath(), newpath != localpath); + + return newpath; + } + return localpath; + } + return newpath; +} + +QString PathMapper::mapServerPathToLocal(const QString &serverpath) +{ + QString newpath; + if(serverpath.isEmpty()) + return serverpath; + + newpath = translate(serverpath, m_serverBasedir, m_localBasedir); + + // Check if this dir is matched by the basedirs + if(QExtFileInfo::exists(newpath, true, 0L)) + return newpath; + + // Check if any previous mappings fit... + for (unsigned int cnt = 0; cnt < m_serverlist.count(); cnt++ ) + { + newpath = translate(serverpath, m_serverlist[cnt], m_locallist[cnt]); + if(QExtFileInfo::exists(newpath, true, 0L)) + return newpath; + } + + // If the basedirs didnt match, check if the file exists, + // otherwise scan through the mapping history or show the + // mapping dialog + if(!QExtFileInfo::exists(serverpath, true, 0L)) + { + PathMapperDialog pmdlg(serverpath, PathMapperDialog::ServerToLocal); + for (unsigned int cnt = 0; cnt < m_serverlist.count(); cnt++ ) + pmdlg.addHistory(m_serverlist[cnt], m_locallist[cnt]); + + if(pmdlg.exec() == QDialog::Accepted ) + { + addHistory(pmdlg.localPath(), pmdlg.serverPath(), true); + newpath = translate(serverpath, pmdlg.localPath(), pmdlg.serverPath()); + return newpath; + } + } + + return serverpath; +} + +void PathMapper::setLocalBasedir(const QString &localpath) +{ + m_localBasedir = localpath; +} +void PathMapper::setServerBasedir(const QString &serverpath) +{ + m_serverBasedir = serverpath; +} + +QDomNode PathMapper::pathMapperNode() +{ + QDomNode nodeThisDbg; + QDomDocument *dom = Project::ref()->sessionDom(); + QDomNode projectNode = dom->firstChild().firstChild(); + QDomNode nodeDbg = projectNode.namedItem("debuggers"); + if(nodeDbg.isNull()) + { + nodeDbg = dom->createElement("debuggers"); + projectNode.appendChild(nodeDbg); + } + + // Find the pathmapper section + nodeThisDbg = nodeDbg.namedItem("pathmapper"); + if(nodeThisDbg.isNull()) + { + nodeThisDbg = dom->createElement("pathmapper"); + nodeDbg.appendChild(nodeThisDbg); + } + + return nodeThisDbg; +} + +void PathMapper::addHistory(const QString &localpath, const QString &serverpath, bool saveinproject) +{ + bool exists = false; + for (unsigned int cnt = 0; cnt < m_serverlist.count() && !exists; cnt++ ) + if(m_serverlist[cnt] == serverpath && m_locallist[cnt] == localpath) + exists = true; + + if(!exists) + { + if(saveinproject) + { + QDomNode node = pathMapperNode(); + QDomNode newnode = Project::ref()->dom()->createElement("mapping"); + + QDomAttr serverattr = Project::ref()->dom()->createAttribute("serverpath"); + serverattr.setValue(serverpath); + QDomAttr localattr = Project::ref()->dom()->createAttribute("localpath"); + localattr.setValue(localpath); + + newnode.attributes().setNamedItem(serverattr); + newnode.attributes().setNamedItem(localattr); + + node = node.namedItem("mappings"); + node.insertAfter(newnode, node.lastChild()); + } + + m_serverlist.append(serverpath); + m_locallist.append(localpath); + } + +} + +void PathMapper::readConfig() +{ + QDomNode node = pathMapperNode(); + + // Server + QDomNode valuenode = node.namedItem("mappings"); + QDomNode child = valuenode.firstChild(); + QString serverpath, localpath; + while(!child.isNull()) + { + serverpath = child.attributes().namedItem("serverpath").nodeValue(); + localpath = child.attributes().namedItem("localpath").nodeValue(); + kdDebug(24002) << "PathMapper::readConfig " << serverpath << ", " << localpath << endl; + + m_serverlist.append(serverpath); + m_locallist.append(localpath); + child = child.nextSibling(); + } +} + +#include "pathmapper.moc" diff --git a/quanta/components/debugger/pathmapper.h b/quanta/components/debugger/pathmapper.h new file mode 100644 index 00000000..b93b48cb --- /dev/null +++ b/quanta/components/debugger/pathmapper.h @@ -0,0 +1,55 @@ +/*************************************************************************** + pathmapper.h + ------------------------ + begin : 2004-10-10 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 PATHMAPPER_H +#define PATHMAPPER_H + +#include +#include +#include + +class KURL; + +class PathMapper : public QObject +{ + Q_OBJECT + + public: + PathMapper(QObject *parent = 0, const char *name = 0); + PathMapper(); + virtual QString mapLocalPathToServer(const QString &localpath); + virtual QString mapServerPathToLocal(const QString &serverpath); + + virtual void setLocalBasedir(const QString &localpath); + virtual void setServerBasedir(const QString &serverpath); + + void readConfig(); + + private: + QDomNode pathMapperNode(); + QString translate(const QString & path, const QString & from, const QString &to); + void addHistory(const QString &localpath, const QString &serverpath, bool saveinproject); + + QString m_localBasedir; + QString m_serverBasedir; + + QStringList m_serverlist; + QStringList m_locallist; +}; + +#endif diff --git a/quanta/components/debugger/pathmapperdialog.cpp b/quanta/components/debugger/pathmapperdialog.cpp new file mode 100644 index 00000000..8cfb949e --- /dev/null +++ b/quanta/components/debugger/pathmapperdialog.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** + pathmapperdialog.cpp + -------------------- + begin : 2005-01-08 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 "pathmapperdialog.h" +#include +#include +#include +#include +#include + +PathMapperDialog::PathMapperDialog(const QString& path, const PathMapperDialog::Direction direction) + : PathMapperDialogS(0, "PathMapperDialog", false, 0) +{ + m_direction = direction; + m_path = path; + linePath->setText(path); + + if(m_direction == LocalToServer) + ledTranslationExists->hide(); + + connect(listHistory, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); + connect(lineLocalPath, SIGNAL(textChanged(const QString&)), this, SLOT(slotPathsChanged())); + connect(lineServerPath, SIGNAL(textChanged(const QString&)), this, SLOT(slotPathsChanged())); +} + +PathMapperDialog::~PathMapperDialog() +{ +} + +void PathMapperDialog::addHistory(const QString &serverdir, const QString &localdir) +{ + new QListViewItem(listHistory, localdir, serverdir); +} + +void PathMapperDialog::slotSelectionChanged() +{ + lineLocalPath->setText(listHistory->currentItem()->text(0)); + lineServerPath->setText(listHistory->currentItem()->text(1)); +} + +void PathMapperDialog::slotPathsChanged() +{ + QString translated, from, to; + if(m_direction == ServerToLocal) + { + from = lineServerPath->text(); + to = lineLocalPath->text(); + } + else + { + to = lineServerPath->text(); + from = lineLocalPath->text(); + } + + translated = m_path; + + // Check if this dir is matched by the maps + if(m_path.startsWith(from, false)) + { + translated.remove(0, from.length()); + translated = to + translated; + } + + // Indicate wether local file exists + if(m_direction == ServerToLocal) + { + if(QExtFileInfo::exists(translated, true, this)) + ledTranslationExists->setColor(Qt::green); + else + ledTranslationExists->setColor(Qt::red); + ledTranslationExists->on(); + } + + lineTranslated->setText(translated); +} + +QString PathMapperDialog::serverPath() +{ + return lineServerPath->text(); +} + +QString PathMapperDialog::localPath() +{ + return lineLocalPath->text(); +} + +#include "pathmapperdialog.moc" + diff --git a/quanta/components/debugger/pathmapperdialog.h b/quanta/components/debugger/pathmapperdialog.h new file mode 100644 index 00000000..786de8ea --- /dev/null +++ b/quanta/components/debugger/pathmapperdialog.h @@ -0,0 +1,52 @@ +/*************************************************************************** + pathmapperdialog.h + ------------------ + begin : 2004-04-05 + copyright : (C) 2004 Linus McCabe + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 PATHMAPPERDIALOG_H +#define PATHMAPPERDIALOG_H + +#include "pathmapperdialogs.h" + +class PathMapperDialog : public PathMapperDialogS +{ + Q_OBJECT + + public: + enum Direction + { + ServerToLocal = 0, + LocalToServer + }; + + PathMapperDialog(const QString& path, const PathMapperDialog::Direction direction); + ~PathMapperDialog(); + + void addHistory(const QString &serverdir, const QString &localdir); + + QString serverPath(); + QString localPath(); + + public slots: + void slotSelectionChanged(); + void slotPathsChanged(); + + private: + QString m_path; + Direction m_direction; + +}; + +#endif // PATHMAPPERDIALOG_H + diff --git a/quanta/components/debugger/pathmapperdialogs.ui b/quanta/components/debugger/pathmapperdialogs.ui new file mode 100644 index 00000000..fc7486d4 --- /dev/null +++ b/quanta/components/debugger/pathmapperdialogs.ui @@ -0,0 +1,345 @@ + +PathMapperDialogS + + + PathMapperDialogS + + + + 0 + 0 + 590 + 519 + + + + Directory Mapping + + + true + + + + unnamed + + + + groupBox6 + + + Directory Mapping + + + + unnamed + + + + lblDebuggerLocalBasedir + + + + 5 + 5 + 0 + 0 + + + + Local basedir: + + + + + lblDebuggerServerBasedir + + + + 5 + 5 + 0 + 0 + + + + Server basedir: + + + + + lineLocalPath + + + This is where the local part of path is specified. If a file is located on the computer running Quanta at "/home/user/htdocs/project/file.php" and that file is located on the server as "/var/www/project/file.php", local basedir should be "/home/user/htdocs/" and server basedir should be "/var/www/". +The quanta will know that files starting with "/home/user/project/" on the local computer, will start with "/var/www/" on the remote computer. + + + + + lineServerPath + + + This is where the server part of path is specified. If a file is located on the computer running Quanta at "/home/user/htdocs/project/file.php" and that file is located on the server as "/var/www/project/file.php", local basedir should be "/home/user/htdocs/" and server basedir should be "/var/www/". +The quanta will know that files starting with "/home/user/project/" on the local computer, will start with "/var/www/" on the remote computer. + + + + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + &Cancel + + + + + + true + + + + + + + groupBox7 + + + Previous Mappings + + + + unnamed + + + + + Local Directory + + + true + + + true + + + + + Server Directory + + + true + + + true + + + + listHistory + + + StyledPanel + + + Manual + + + true + + + AllColumns + + + This is a list of previously used mappings. Click on one to use it + + + + + + + groupBox8 + + + Sample + + + + unnamed + + + + lblTranslates + + + + 5 + 5 + 0 + 0 + + + + Translates to: + + + + + lblOriginal + + + + 5 + 5 + 0 + 0 + + + + Original path: + + + + + ledTranslationExists + + + + 22 + 22 + + + + + 22 + 22 + + + + On + + + Circular + + + Raised + + + Indicates whether the translated path exists on disk or not + + + This indicator tells you whether the translated path exists on local disk or not. + + + + + lineTranslated + + + false + + + + 0 + 0 + 0 + + + + This field shows what the "original path" above will look like after translation. + + + + + linePath + + + false + + + + 0 + 0 + 0 + + + + This field shows the path currently needing to be translated. + + + + + + + + + + + buttonOk + clicked() + PathMapperDialogS + accept() + + + buttonCancel + clicked() + PathMapperDialogS + reject() + + + + slotHistoryclicked() + + + + kled.h + + diff --git a/quanta/components/debugger/quantadebuggerinterface.cpp b/quanta/components/debugger/quantadebuggerinterface.cpp new file mode 100644 index 00000000..bd9ba2e1 --- /dev/null +++ b/quanta/components/debugger/quantadebuggerinterface.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + debugmanager.cpp + ------------------ + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 +#include +#include +#include +#include + +#include "debuggerinterface.h" +#include "quantadebuggerinterface.h" +#include "debuggermanager.h" +#include "debuggerui.h" +#include "pathmapper.h" +#include "project.h" +#include "viewmanager.h" +#include "document.h" + +class DebuggerBreakpoint; + +QuantaDebuggerInterface::QuantaDebuggerInterface (QObject *myparent, const char* name) + : DebuggerInterface(myparent, name) +{ + m_manager = static_cast(parent()); +} + +QuantaDebuggerInterface::~QuantaDebuggerInterface () +{} + +void QuantaDebuggerInterface::haveBreakpoint (const QString& file, int line) +{ + return m_manager->haveBreakpoint(file, line); +} + +void QuantaDebuggerInterface::havenoBreakpoint (const QString& file, int line) +{ + return m_manager->havenoBreakpoint(file, line); +} + +// Public help functions +bool QuantaDebuggerInterface::showStatus(const QString& message, bool log) +{ + return m_manager->showStatus(message, log); +} + +bool QuantaDebuggerInterface::setActiveLine(const QString& file, int line) +{ + return m_manager->setActiveLine(file, line); +} + +void QuantaDebuggerInterface::enableAction(const QString& action, bool enable) +{ + m_manager->enableAction(action, enable); +} + +void QuantaDebuggerInterface::fileOpened(const QString& file) +{ + m_manager->fileOpened(file); +} + +void QuantaDebuggerInterface::sendRequest(const KURL &url) +{ + m_manager->UI()->sendRequest(url); +} + +const QString QuantaDebuggerInterface::activeFileParts(const QString & str) +{ + QString newstr = str; + + // a/r = absolute/relative + // f/p/d = file/project/docroot + // n/d/p = name/dir/path + + // Filename, filedir and filepath + newstr.replace("%afn", ViewManager::ref()->activeDocument()->url().fileName()); + newstr.replace("%afd", ViewManager::ref()->activeDocument()->url().directory()); + newstr.replace("%afp", ViewManager::ref()->activeDocument()->url().path()); + + // filedir and filepath relative to project root + newstr.replace("%rfpp", KURL::relativePath(Project::ref()->projectBaseURL().path(), ViewManager::ref()->activeDocument()->url().path())); + newstr.replace("%rfpd", KURL::relativePath(Project::ref()->projectBaseURL().path(), ViewManager::ref()->activeDocument()->url().directory())); + + // filedir and filepath relative to document root + newstr.replace("%rfdp", KURL::relativePath(Project::ref()->documentFolderForURL(ViewManager::ref()->activeDocument()->url()).directory(), ViewManager::ref()->activeDocument()->url().path())); + newstr.replace("%rfdd", KURL::relativePath(Project::ref()->documentFolderForURL(ViewManager::ref()->activeDocument()->url()).directory(), ViewManager::ref()->activeDocument()->url().directory())); + + newstr.replace("%apd", Project::ref()->projectBaseURL().path()); + newstr.replace("%add", Project::ref()->documentFolderForURL(ViewManager::ref()->activeDocument()->url()).directory()); + + kdDebug(24002) << k_funcinfo << ", BaseURL " << Project::ref()->projectBaseURL().path() << ", active doc : " << ViewManager::ref()->activeDocument()->url().path() << ", documentFolderForURL" << Project::ref()->documentFolderForURL(ViewManager::ref()->activeDocument()->url()) << ", newstr" << newstr << endl; + + return newstr; +} + +void QuantaDebuggerInterface::showVariable(DebuggerVariable* var) +{ + m_manager->UI()->addVariable(var); +} + +DebuggerVariable *QuantaDebuggerInterface::newDebuggerVariable(const QString& name, const QString& value, int type) +{ + return new DebuggerVariable(name, value, type); +} + +DebuggerVariable *QuantaDebuggerInterface::newDebuggerVariable(const QString& name, const ValueList_t& values, int type) +{ + return new DebuggerVariable(name, values, type); +} + +void QuantaDebuggerInterface::showBreakpoint(const DebuggerBreakpoint &bp) +{ + m_manager->UI()->showBreakpoint(bp); +} + +void QuantaDebuggerInterface::refreshBreakpoints() +{ + m_manager->refreshBreakpoints(); +} + +DebuggerBreakpoint *QuantaDebuggerInterface::newDebuggerBreakpoint() +{ + return new DebuggerBreakpoint(); +} + +DebuggerBreakpoint *QuantaDebuggerInterface::findDebuggerBreakpoint(const QString& key) +{ + return m_manager->findDebuggerBreakpoint(key); +} + +/* +void QuantaDebuggerInterface::preWatchUpdate() +{ + m_manager->UI()->preWatchUpdate(); +} + +void QuantaDebuggerInterface::postWatchUpdate() +{ + m_manager->UI()->postWatchUpdate(); +}*/ + +// Path mapping +PathMapper* QuantaDebuggerInterface::Mapper() +{ + return m_manager->Mapper(); +} + +void QuantaDebuggerInterface::updateBreakpointKey( const DebuggerBreakpoint & bp, const QString & newkey ) +{ + m_manager->updateBreakpointKey(bp, newkey); +} + +void QuantaDebuggerInterface::backtraceClear( ) +{ + m_manager->UI()->backtraceClear(); +} + +void QuantaDebuggerInterface::backtraceShow( long level, BacktraceType type, const QString & filename, long line, const QString & func ) +{ + m_manager->UI()->backtraceShow(level, type, filename, line, func); +} + +#include "quantadebuggerinterface.moc" diff --git a/quanta/components/debugger/quantadebuggerinterface.h b/quanta/components/debugger/quantadebuggerinterface.h new file mode 100644 index 00000000..44be8f4a --- /dev/null +++ b/quanta/components/debugger/quantadebuggerinterface.h @@ -0,0 +1,75 @@ +/*************************************************************************** + debugmanager.h + ------------------ + begin : 2004-03-12 + copyright : (C) 2004 Linus McCabe + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 MYDEBUGMANAGER_H +#define MYDEBUGMANAGER_H + +#include +#include +#include "debuggerinterface.h" +#include "debuggervariable.h" + +class DebuggerManager; + +class QuantaDebuggerInterface : public DebuggerInterface +{ + Q_OBJECT + + private: + DebuggerManager *m_manager; + + public: + QuantaDebuggerInterface(QObject *myparent, const char* name); + ~QuantaDebuggerInterface(); + + // Breakpoints + void haveBreakpoint (const QString& file, int line) ; + void havenoBreakpoint (const QString& file, int line) ; + void refreshBreakpoints(); + + // Public help functions + bool showStatus(const QString& message, bool log); + bool setActiveLine (const QString& file, int line) ; + + void enableAction(const QString& action, bool enable); + void fileOpened(const QString& file) ; + void sendRequest(const KURL &url); + virtual const QString activeFileParts(const QString & str); + + // Watches handling + //void preWatchUpdate(); + //void postWatchUpdate(); + DebuggerVariable* newDebuggerVariable(const QString& name, const QString& value, int type); + DebuggerVariable* newDebuggerVariable(const QString& name, const ValueList_t& values, int type); + void showVariable(DebuggerVariable*); + + // Breakpoints + void showBreakpoint(const DebuggerBreakpoint &bp); + DebuggerBreakpoint * newDebuggerBreakpoint(); + DebuggerBreakpoint * findDebuggerBreakpoint(const QString& key); + void updateBreakpointKey(const DebuggerBreakpoint &bp, const QString& newkey); + + // Backtrace + void backtraceClear(); + void backtraceShow(long level, BacktraceType type, const QString &filename, long line, const QString& func); + + // Path mapping + PathMapper* Mapper(); +}; + +#endif + diff --git a/quanta/components/debugger/variableslistview.cpp b/quanta/components/debugger/variableslistview.cpp new file mode 100644 index 00000000..c9d77de3 --- /dev/null +++ b/quanta/components/debugger/variableslistview.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + variableslistview.cpp + ----------------------- + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// KDE Includes +#include +#include +#include +#include +#include +#include + +// Quanta includes +#include "variableslistview.h" +#include "debuggervariable.h" +#include "resource.h" +#include "quanta.h" +#include "messageoutput.h" +#include "debuggerclient.h" +#include "debuggermanager.h" + +namespace VariablesListViewColumns +{ + // The enums must correspond to the order of the columns + // If you change here, change the column adding + enum Columns + { + Name = 0, + Status, + Value, + Type, + Size + + }; +} + +VariablesListView::VariablesListView(QWidget *parent, const char *name) + : KListView(parent, name) +{ + // If you change here, change the VariablesListViewColumns enums above + addColumn(i18n("Name")); + addColumn(QString::null); + addColumn(i18n("Value")); + addColumn(i18n("Type")); + addColumn(i18n("Size")); + setRootIsDecorated(true); + setSorting(-1); // No sorting + + m_variablePopup = new KPopupMenu(this); + m_variablePopup->insertItem(SmallIcon("editdelete"), i18n("&Remove"), this, SLOT(slotRemoveSelected()), 0, removeWatch); + + if(quantaApp->debugger()->client()->supports(DebuggerClientCapabilities::VariableSetValue)) + m_variablePopup->insertItem(SmallIcon("edit"), i18n("&Set Value"), this, SLOT(slotVariableSetValue()), 0, setValue); + + m_variablePopup->insertItem(SmallIcon("viewmag"), i18n("&Dump in Messages Log"), this, SLOT(slotVariableDump()), 0, dumpValue); + + m_variablePopup->insertItem(SmallIcon("editcopy"), i18n("&Copy to Clipboard"), this, SLOT(slotVariableCopyToClipboard()), 0, copyValue); + + connect(this, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ), this, SLOT(slotVariableContextMenu(KListView *, QListViewItem *, const QPoint &))); +} + + +VariablesListView::~VariablesListView() +{} + +DebuggerVariable* VariablesListView::selected(bool traverse) +{ + if(!selectedItem()) + return NULL; + + DebuggerVariable* v, *found; + for( v = m_variablesList.first(); v; v = m_variablesList.next()) + { + found = v->findItem(selectedItem(), traverse); + if(found) + return found; + } + + return NULL; +} + +void VariablesListView::slotRemoveSelected() +{ + DebuggerVariable* v = selected(); + + if(!v) + return; + + emit removeVariable(v); + m_variablesList.remove(v); + delete v; +} + +void VariablesListView::keyPressEvent(QKeyEvent *e) +{ + if(e->key() != Qt::Key_Delete) + { + e->ignore(); + return; + } + + DebuggerVariable* v = selected(); + + if(!v) + return; + + emit removeVariable(v); + m_variablesList.remove(v); + delete v; +} + +void VariablesListView::addVariable(DebuggerVariable* variable) +{ + if(!variable) + { + kdDebug(24002) << k_funcinfo << " Tried to show NULL variable!" << endl; + return; + } + + // Find the old variable in the tree if it is there + for(DebuggerVariable* v = m_variablesList.first(); v; v = m_variablesList.next()) + { + if(v->name() == variable->name()) + { + replaceVariable(v, variable); + return; + } + } + + // Insert the new variable + DebuggerVariable *newvar = new DebuggerVariable(variable); + m_variablesList.append(newvar); + + KListViewItem * item = new KListViewItem(this); + insertItem(item); + newvar->setItem(item); + replaceVariable(newvar, variable); +} + +void VariablesListView::clear() +{ + KListView::clear(); + m_variablesList.clear(); +} + +void VariablesListView::replaceVariable(DebuggerVariable* oldvar, DebuggerVariable* newvar) +{ + KListViewItem * item; + + // Remove children that doesen't exist anymore + QPtrList oldlist = oldvar->values(); + for(DebuggerVariable* oldchild = oldlist.last(); oldchild; oldchild = oldlist.prev()) + { + bool found = false; + QPtrList newlist = newvar->values(); + for(DebuggerVariable* newchild = newlist.last(); newchild; newchild = newlist.prev()) + { + if(newchild->name() == oldchild->name()) + { + found = true; + break; + } + } + if(!found) + oldvar->deleteChild(oldchild); + } + + // Update and add children + QPtrList newlist = newvar->values(); + for(DebuggerVariable* newchild = newlist.last(); newchild; newchild = newlist.prev()) + { + bool found = false; + QPtrList oldlist = oldvar->values(); + for(DebuggerVariable* oldchild = oldlist.last(); oldchild; oldchild = oldlist.prev()) + { + if(newchild->name() == oldchild->name()) + { + found = true; + replaceVariable( oldchild, newchild); + break; + } + } + if(!found) + { + DebuggerVariable* child = new DebuggerVariable(); + item = new KListViewItem(oldvar->item()); + child->setItem(item); + replaceVariable( child, newchild); + oldvar->append(child); + } + } + + item = oldvar->item(); + + if(oldvar->value() != newvar->value()) + item->setPixmap(VariablesListViewColumns::Status, SmallIcon("ok")); + else + item->setPixmap(VariablesListViewColumns::Status, KPixmap()); + + oldvar->copy(newvar, false); + + item->setText(VariablesListViewColumns::Name, oldvar->name()); + item->setText(VariablesListViewColumns::Type, oldvar->typeName()); + item->setText(VariablesListViewColumns::Size, oldvar->sizeName()); + item->setText(VariablesListViewColumns::Value, (newvar->isScalar() ? oldvar->value() : QString())); + +} + +void VariablesListView::slotVariableContextMenu(KListView *, QListViewItem *, const QPoint& point) +{ + if(!selectedItem()) + return; + + m_variablePopup->setItemEnabled(removeWatch, selected()); + if(quantaApp->debugger()->client()->supports(DebuggerClientCapabilities::VariableSetValue)) + m_variablePopup->setItemEnabled(setValue, selected()); + + DebuggerVariable *v = selected(true); + m_variablePopup->setItemEnabled(dumpValue, v && v->isScalar()); + m_variablePopup->setItemEnabled(copyValue, v && v->isScalar()); + + m_variablePopup->popup(point); +} + +void VariablesListView::slotVariableSetValue() +{ + if(!selected()) + return; + + DebuggerVariable v(selected()); + + QString newvalue; + switch(v.type()) + { + case DebuggerVariableTypes::String: + newvalue = "\"" + v.value() + "\""; + break; + + case DebuggerVariableTypes::Float: + case DebuggerVariableTypes::Boolean: + case DebuggerVariableTypes::Integer: + //case DebuggerVariableTypes::Array: + newvalue = v.value(); + break; + + default: + newvalue = ""; + } + newvalue = KInputDialog::getMultiLineText(i18n("Set Variable"), i18n("New value:"), newvalue, 0, this); + if(newvalue.isNull()) + return; + + v.setValue(newvalue); + quantaApp->debugger()->client()->variableSetValue(v); + +} + +void VariablesListView::slotVariableDump( ) +{ + DebuggerVariable *v = selected(true); + if(!v) + return; + + quantaApp->messageOutput()->showMessage(i18n("Contents of variable %1:\n>>>\n").arg(v->name())); + quantaApp->messageOutput()->showMessage(v->value()); + quantaApp->messageOutput()->showMessage("<<<\n"); +} + +void VariablesListView::slotVariableCopyToClipboard( ) +{ + DebuggerVariable *v = selected(true); + if(!v) + return; + QApplication::clipboard()->setText(v->value()); +} + +#include "variableslistview.moc" diff --git a/quanta/components/debugger/variableslistview.h b/quanta/components/debugger/variableslistview.h new file mode 100644 index 00000000..41de5328 --- /dev/null +++ b/quanta/components/debugger/variableslistview.h @@ -0,0 +1,71 @@ +/*************************************************************************** + variablelistview.h + ------------------------ + begin : 2004-04-04 + copyright : (C) 2004 Thiago Silva + + ***************************************************************************/ + +/**************************************************************************** + * * + * 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 VARIABLESLISTVIEW_H +#define VARIABLESLISTVIEW_H + +#include +#include +#include + +class DebuggerVariable; + +class VariablesListView : public KListView +{ + Q_OBJECT + + enum menuitems + { + setValue = 1, + dumpValue, + copyValue, + removeWatch + }; + + public: + VariablesListView(QWidget *parent = 0, const char *name = 0); + ~VariablesListView(); + + void addVariable(DebuggerVariable* variable); + DebuggerVariable* selected(bool traverse = false); + + DebuggerVariable* first() { return m_variablesList.first(); } + DebuggerVariable* next() { return m_variablesList.next(); } + + void clear(); + + public slots: + void slotRemoveSelected(); + void slotVariableSetValue(); + void slotVariableDump(); + void slotVariableCopyToClipboard(); + void slotVariableContextMenu(KListView *list, QListViewItem * item, const QPoint& point); + + signals: + void valueChanged(DebuggerVariable*); + void removeVariable(DebuggerVariable*); + + private: + void keyPressEvent(QKeyEvent *e); + void replaceVariable(DebuggerVariable* oldvar, DebuggerVariable* newvar); + + QPtrList m_variablesList; + KPopupMenu *m_variablePopup; +}; + +#endif -- cgit v1.2.3