You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/languages/ruby/debugger/dbgtoolbar.cpp

484 lines
17 KiB

/***************************************************************************
begin : Thu Dec 23 1999
copyright : (C) 1999 by John Birch
email : jbb@kdevelop.org
Adapted for ruby debugging
--------------------------
begin : Mon Nov 1 2004
copyright : (C) 2004 by Richard Dale
email : Richard_Dale@tipitina.demon.co.uk
***************************************************************************/
/***************************************************************************
* *
* 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 "dbgtoolbar.h"
#include "debuggerpart.h"
#include "dbgcontroller.h"
#include <kdockwindow.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <kstandarddirs.h>
#include <twin.h>
#include <twinmodule.h>
#include <tqapplication.h>
#include <tqcursor.h>
#include <tqframe.h>
#include <tqlayout.h>
#include <tqpainter.h>
#include <tqpushbutton.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
// **************************************************************************
// **************************************************************************
// **************************************************************************
// Implements a floating toolbar for the debugger.
// Unfortunately, I couldn't get the TDEToolBar to work nicely when it
// was floating, so I was forced to write these classes. I'm not sure whether
// I didn't try hard enough or ... and I've forgotten what the problems were
// now.
// The problem with using this is that it will not dock as a normal toolbar.
// I'm not convince that this is a real problem though.
// So, if you can get it to work as a TDEToolBar, and it works well when the
// app is running, then all these classes can be removed.
// This code is very specific to the internal debugger in tdevelop.
namespace RDBDebugger
{
// **************************************************************************
// **************************************************************************
// **************************************************************************
// This just allows the user to click on the toolbar and drag it somewhere else.
// I would have preferred to use normal decoration on the toolbar and removed
// the iconify, close, etc buttons from the window title but again I kept running
// into problems. Instead, I used no decoration and this class. Also this looks
// similar to the TDEToolBar floating style.
class DbgMoveHandle : public TQFrame
{
public:
DbgMoveHandle(DbgToolBar *parent=0, const char * name=0, WFlags f=0);
virtual ~DbgMoveHandle();
virtual void mousePressEvent(TQMouseEvent *e);
virtual void mouseReleaseEvent(TQMouseEvent *e);
virtual void mouseMoveEvent(TQMouseEvent *e);
private:
DbgToolBar* toolBar_;
TQPoint offset_;
bool moving_;
};
// **************************************************************************
DbgMoveHandle::DbgMoveHandle(DbgToolBar *parent, const char * name, WFlags f)
: TQFrame(parent, name, f),
toolBar_(parent),
offset_(TQPoint(0,0)),
moving_(false)
{
setFrameStyle(TQFrame::Panel|TQFrame::Raised);
setFixedHeight(12);
}
// **************************************************************************
DbgMoveHandle::~DbgMoveHandle()
{
}
// **************************************************************************
void DbgMoveHandle::mousePressEvent(TQMouseEvent *e)
{
TQFrame::mousePressEvent(e);
if (moving_)
return;
if (e->button() == TQt::RightButton) {
TDEPopupMenu *menu = new TDEPopupMenu(this);
menu->insertTitle(i18n("Debug Toolbar"));
menu->insertItem(i18n("Dock to Panel"),
parent(), TQ_SLOT(slotDock()));
menu->insertItem(i18n("Dock to Panel && Iconify TDevelop"),
parent(), TQ_SLOT(slotIconifyAndDock()));
menu->popup(e->globalPos());
} else {
moving_ = true;
offset_ = parentWidget()->pos() - e->globalPos();
setFrameStyle(TQFrame::Panel|TQFrame::Sunken);
TQApplication::setOverrideCursor(TQCursor(sizeAllCursor));
setPalette(TQPalette(colorGroup().background()));
repaint();
}
}
// **************************************************************************
void DbgMoveHandle::mouseReleaseEvent(TQMouseEvent *e)
{
TQFrame::mouseReleaseEvent(e);
moving_ = false;
offset_ = TQPoint(0,0);
setFrameStyle(TQFrame::Panel|TQFrame::Raised);
TQApplication::restoreOverrideCursor();
setPalette(TQPalette(colorGroup().background()));
repaint();
}
// **************************************************************************
void DbgMoveHandle::mouseMoveEvent(TQMouseEvent *e)
{
TQFrame::mouseMoveEvent(e);
if (!moving_)
return;
toolBar_->move(e->globalPos() + offset_);
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
// This class adds text _and_ a pixmap to a button. Why doesn't TQPushButton
// support that? It only allowed text _or_ pixmap.
class DbgButton : public TQPushButton
{
public:
DbgButton(const TQPixmap &pixmap, const TQString &text,
DbgToolBar *parent, const char *name=0);
virtual ~DbgButton() {};
void drawButtonLabel(TQPainter *painter);
TQSize sizeHint() const;
private:
TQPixmap pixmap_;
};
// **************************************************************************
DbgButton::DbgButton(const TQPixmap& pixmap, const TQString& text,
DbgToolBar* parent, const char* name)
: TQPushButton(parent, name),
pixmap_(pixmap)
{
setText(text);
}
// **************************************************************************
void DbgButton::drawButtonLabel(TQPainter *painter)
{
// We always have a pixmap (today...)
// Centre it if there's no text
bool hasText = !text().isEmpty();
int x = ((hasText ? height() : width()) - pixmap_.width()) / 2;
int y = (height() - pixmap_.height()) / 2;
painter->drawPixmap(x, y, pixmap_);
if (hasText) {
painter->setPen(colorGroup().text());
painter->drawText(height()+2, 0, width()-(height()+2), height(), AlignLeft|AlignVCenter, text());
}
}
// **************************************************************************
TQSize DbgButton::sizeHint() const
{
if (text().isEmpty())
return pixmap_.size();
else
return TQPushButton::sizeHint();
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
DbgDocker::DbgDocker(TQWidget* parent, DbgToolBar* toolBar, const TQPixmap& pixmap) :
KSystemTray(parent, "DbgDocker"),
toolBar_(toolBar)
{
setPixmap(pixmap);
TQToolTip::add( this, i18n("TDevelop ruby debugger: Click to execute one line of code (\"step\")") );
}
// **************************************************************************
void DbgDocker::mousePressEvent(TQMouseEvent *e)
{
if (!rect().contains( e->pos()))
return;
switch (e->button()) {
case TQt::LeftButton:
{
// Not really a click, but it'll hold for the time being !!!
emit clicked();
break;
}
case TQt::RightButton:
{
TDEPopupMenu* menu = new TDEPopupMenu(this);
menu->insertTitle(i18n("Debug Toolbar"));
menu->insertItem(i18n("Activate"), toolBar_, TQ_SLOT(slotUndock()));
menu->insertItem(i18n("Activate (TDevelop gets focus)"), toolBar_, TQ_SLOT(slotActivateAndUndock()));
menu->popup(e->globalPos());
break;
}
default:
break;
}
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
DbgToolBar::DbgToolBar(RubyDebuggerPart* part,
TQWidget* parent, const char* name)
: TQFrame(0, name),
part_(part),
activeWindow_(0),
winModule_(0),
bKDevFocus_(0),
bPrevFocus_(0),
appIsActive_(false),
docked_(false),
docker_(0),
dockWindow_(new KSystemTray(parent))
{
winModule_ = new KWinModule(this);
docker_ = new DbgDocker(parent, this, BarIcon("dbgnext"));
connect(docker_, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotStepOver()));
// Must have noFocus set so that we can see what window was active.
// see slotDbgKdevFocus() for more comments
// I do not want the user to be able to "close" this widget. If we have any
// decoration then they can and that is bad.
// This widget is closed when the debugger finishes i.e. they press "Stop"
// Do we need NoFocus???
KWin::setState(winId(), NET::StaysOnTop | NET::Modal | NET::SkipTaskbar);
// KWin::setType(winId(), NET::Override); // So it has no decoration
KWin::setType(winId(), NET::Dock);
setFocusPolicy(TQWidget::NoFocus);
setFrameStyle( TQFrame::Box | TQFrame::Plain );
setLineWidth(4);
setMidLineWidth(0);
TQBoxLayout* topLayout = new TQVBoxLayout(this);
TQBoxLayout* nextLayout = new TQHBoxLayout();
TQBoxLayout* stepLayout = new TQHBoxLayout();
TQBoxLayout* focusLayout = new TQHBoxLayout();
DbgMoveHandle* moveHandle= new DbgMoveHandle(this);
TQPushButton* bRun = new DbgButton(BarIcon("dbgrun"), i18n("Run"), this);
TQPushButton* bInterrupt = new DbgButton(BarIcon("media-playback-pause"), i18n("Interrupt"), this);
TQPushButton* bNext = new DbgButton(BarIcon("dbgnext"), i18n("Step Over"), this);
TQPushButton* bStep = new DbgButton(BarIcon("dbgstep"), i18n("Step Into"), this);
TQPushButton* bFinish = new DbgButton(BarIcon("dbgstepout"), i18n("Step Out"), this);
TQPushButton* bRunTo = new DbgButton(BarIcon("dbgrunto"), i18n("Run to Cursor"), this);
bPrevFocus_ = new DbgButton(BarIcon("dbgmemview"), TQString(), this);
bKDevFocus_ = new DbgButton(BarIcon("tdevelop"), TQString(), this);
connect(bRun, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotRun()));
connect(bInterrupt, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotPause()));
connect(bNext, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotStepOver()));
connect(bStep, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotStepInto()));
connect(bFinish, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotStepOut()));
connect(bRunTo, TQ_SIGNAL(clicked()), part_, TQ_SLOT(slotRunToCursor()));
connect(bKDevFocus_, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotKdevFocus()));
connect(bPrevFocus_, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotPrevFocus()));
TQToolTip::add( bRun, i18n("Continue with application execution, may start the application") );
TQToolTip::add( bInterrupt, i18n("Interrupt the application execution") );
TQToolTip::add( bNext, i18n("Execute one line of code, but run through methods") );
TQToolTip::add( bStep, i18n("Execute one line of code, stepping into methods if appropriate") );
TQToolTip::add( bFinish, i18n("Execute to end of current stack frame") );
TQToolTip::add( bRunTo, i18n("Continues execution until the cursor position is reached.") );
TQToolTip::add( bKDevFocus_, i18n("Set focus on TDevelop") );
TQToolTip::add( bPrevFocus_, i18n("Set focus on window that had focus when TDevelop got focus") );
TQWhatsThis::add( bRun, i18n("Continue with application execution. May start the application.") );
TQWhatsThis::add( bInterrupt, i18n("Interrupt the application execution.") );
TQWhatsThis::add( bNext, i18n("Execute one line of code, but run through methods.") );
TQWhatsThis::add( bStep, i18n("Execute one line of code, stepping into methods if appropriate.") );
TQWhatsThis::add( bFinish, i18n("Execute to end of current stack frame.") );
TQWhatsThis::add( bRunTo, i18n("Continues execution until the cursor position is reached.") );
TQWhatsThis::add( bKDevFocus_, i18n("Set focus on TDevelop.") );
TQWhatsThis::add( bPrevFocus_, i18n("Set focus on window that had focus when TDevelop got focus.") );
topLayout->addWidget(moveHandle);
topLayout->addWidget(bRun);
topLayout->addLayout(nextLayout);
topLayout->addLayout(stepLayout);
topLayout->addWidget(bFinish);
topLayout->addWidget(bRunTo);
topLayout->addWidget(bInterrupt);
topLayout->addLayout(focusLayout);
focusLayout->addWidget(bKDevFocus_);
focusLayout->addWidget(bPrevFocus_);
stepLayout->addWidget(bStep);
nextLayout->addWidget(bNext);
// int w = TQMAX(bRun->sizeHint().width(), bFinish->sizeHint().width());
// w = TQMAX(w, bInterrupt->sizeHint().width());
// w = TQMAX(w, bView->sizeHint().width());
// they should have the same height, so don't be too fussy
// int h = bFinish->sizeHint().height();
//
// bNext->setMinimumHeight(h);
// bNexti->setMinimumHeight(h);
// bStep->setMinimumHeight(h);
// bStepi->setMinimumHeight(h);
// bKDevFocus_->setMinimumHeight(h);
// bPrevFocus_->setMinimumHeight(h);
// setMinimumSize(w+10, h*7);
// setMaximumSize(w+10, h*7);
setAppIndicator(appIsActive_);
topLayout->activate();
}
// **************************************************************************
DbgToolBar::~DbgToolBar()
{
slotUndock();
}
// **************************************************************************
void DbgToolBar::slotKdevFocus()
{
// I really want to be able to set the focus on the _application_ being debugged
// but this is the best compromise I can come up with. All we do is save the
// window that had focus when they switch to the tdevelop window. To do this
// the toolbar _cannot_ accept focus.
// If anyone has a way of determining what window the app is _actually_ running on
// then please fix and send a patch.
if (winModule_->activeWindow() != topLevelWidget()->winId())
activeWindow_ = winModule_->activeWindow();
KWin::activateWindow(topLevelWidget()->winId());
}
// **************************************************************************
void DbgToolBar::slotPrevFocus()
{
KWin::activateWindow(activeWindow_);
}
// **************************************************************************
// If the app is active then the app button is highlighted, otherwise
// kdev button is highlighted.
void DbgToolBar::slotDbgStatus(const TQString&, int state)
{
bool appIndicator = state & s_appBusy;
if (appIndicator != appIsActive_) {
setAppIndicator(appIndicator);
appIsActive_ = appIndicator;
}
}
// **************************************************************************
void DbgToolBar::setAppIndicator(bool appIndicator)
{
if (appIndicator) {
bPrevFocus_->setPalette(TQPalette(colorGroup().mid()));
bKDevFocus_->setPalette(TQPalette(colorGroup().background()));
} else {
bPrevFocus_->setPalette(TQPalette(colorGroup().background()));
bKDevFocus_->setPalette(TQPalette(colorGroup().mid()));
}
}
// **************************************************************************
void DbgToolBar::slotDock()
{
if (docked_)
return;
// Q_ASSERT(!docker_);
hide();
docker_->show();
docked_ = true;
}
// **************************************************************************
void DbgToolBar::slotIconifyAndDock()
{
if (docked_)
return;
// KWin::iconifyWindow(ckDevelop_->winId(), true);
slotDock();
}
// **************************************************************************
void DbgToolBar::slotUndock()
{
if (!docked_)
return;
show();
docker_->hide();
docked_ = false;
}
// **************************************************************************
void DbgToolBar::slotActivateAndUndock()
{
if (!docked_)
return;
KWin::activateWindow(topLevelWidget()->winId());
slotUndock();
}
}
// **************************************************************************
#include "dbgtoolbar.moc"