/*************************************************************************** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ************************************************************************** // ************************************************************************** // ************************************************************************** // Implements a floating toolbar for the debugger. // Unfortunately, I couldn't get the KToolBar 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 KToolBar, 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 kdevelop. 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 KToolBar floating style. class DbgMoveHandle : public TQFrame { public: DbgMoveHandle(DbgToolBar *tqparent=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 *tqparent, const char * name, WFlags f) : TQFrame(tqparent, name, f), toolBar_(tqparent), 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() == Qt::RightButton) { KPopupMenu *menu = new KPopupMenu(this); menu->insertTitle(i18n("Debug Toolbar")); menu->insertItem(i18n("Dock to Panel"), tqparent(), TQT_SLOT(slotDock())); menu->insertItem(i18n("Dock to Panel && Iconify KDevelop"), tqparent(), TQT_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(tqcolorGroup().background())); tqrepaint(); } } // ************************************************************************** void DbgMoveHandle::mouseReleaseEvent(TQMouseEvent *e) { TQFrame::mouseReleaseEvent(e); moving_ = false; offset_ = TQPoint(0,0); setFrameStyle(TQFrame::Panel|TQFrame::Raised); TQApplication::restoreOverrideCursor(); setPalette(TQPalette(tqcolorGroup().background())); tqrepaint(); } // ************************************************************************** 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 *tqparent, const char *name=0); virtual ~DbgButton() {}; void drawButtonLabel(TQPainter *painter); TQSize tqsizeHint() const; private: TQPixmap pixmap_; }; // ************************************************************************** DbgButton::DbgButton(const TQPixmap& pixmap, const TQString& text, DbgToolBar* tqparent, const char* name) : TQPushButton(tqparent, 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(tqcolorGroup().text()); painter->drawText(height()+2, 0, width()-(height()+2), height(), AlignLeft|AlignVCenter, text()); } } // ************************************************************************** TQSize DbgButton::tqsizeHint() const { if (text().isEmpty()) return pixmap_.size(); else return TQPushButton::tqsizeHint(); } // ************************************************************************** // ************************************************************************** // ************************************************************************** DbgDocker::DbgDocker(TQWidget* tqparent, DbgToolBar* toolBar, const TQPixmap& pixmap) : KSystemTray(tqparent, "DbgDocker"), toolBar_(toolBar) { setPixmap(pixmap); TQToolTip::add( this, i18n("KDevelop ruby debugger: Click to execute one line of code (\"step\")") ); } // ************************************************************************** void DbgDocker::mousePressEvent(TQMouseEvent *e) { if (!TQT_TQRECT_OBJECT(rect()).contains( e->pos())) return; switch (e->button()) { case Qt::LeftButton: { // Not really a click, but it'll hold for the time being !!! emit clicked(); break; } case Qt::RightButton: { KPopupMenu* menu = new KPopupMenu(this); menu->insertTitle(i18n("Debug Toolbar")); menu->insertItem(i18n("Activate"), toolBar_, TQT_SLOT(slotUndock())); menu->insertItem(i18n("Activate (KDevelop gets focus)"), toolBar_, TQT_SLOT(slotActivateAndUndock())); menu->popup(e->globalPos()); break; } default: break; } } // ************************************************************************** // ************************************************************************** // ************************************************************************** DbgToolBar::DbgToolBar(RubyDebuggerPart* part, TQWidget* tqparent, 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(tqparent)) { winModule_ = new KWinModule(TQT_TQOBJECT(this)); docker_ = new DbgDocker(tqparent, this, BarIcon("dbgnext")); connect(docker_, TQT_SIGNAL(clicked()), part_, TQT_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(TQ_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("player_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("kdevelop"), TQString(), this); connect(bRun, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotRun())); connect(bInterrupt, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotPause())); connect(bNext, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotStepOver())); connect(bStep, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotStepInto())); connect(bFinish, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotStepOut())); connect(bRunTo, TQT_SIGNAL(clicked()), part_, TQT_SLOT(slotRunToCursor())); connect(bKDevFocus_, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotKdevFocus())); connect(bPrevFocus_, TQT_SIGNAL(clicked()), this, TQT_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 KDevelop") ); TQToolTip::add( bPrevFocus_, i18n("Set focus on window that had focus when KDevelop 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 KDevelop.") ); TQWhatsThis::add( bPrevFocus_, i18n("Set focus on window that had focus when KDevelop 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->tqsizeHint().width(), bFinish->tqsizeHint().width()); // w = TQMAX(w, bInterrupt->tqsizeHint().width()); // w = TQMAX(w, bView->tqsizeHint().width()); // they should have the same height, so don't be too fussy // int h = bFinish->tqsizeHint().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 kdevelop 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() != tqtopLevelWidget()->winId()) activeWindow_ = winModule_->activeWindow(); KWin::activateWindow(tqtopLevelWidget()->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::slotDbgtqStatus(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(tqcolorGroup().mid())); bKDevFocus_->setPalette(TQPalette(tqcolorGroup().background())); } else { bPrevFocus_->setPalette(TQPalette(tqcolorGroup().background())); bKDevFocus_->setPalette(TQPalette(tqcolorGroup().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(tqtopLevelWidget()->winId()); slotUndock(); } } // ************************************************************************** #include "dbgtoolbar.moc"