Changed encoding to UTF-8.
[kdbg.git] / kdbg / winstack.cpp
blob15ab2a6e47e94a6ed782c135c00731cb3cbf5b4f
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include "winstack.h"
7 #include "commandids.h"
8 #include "sourcewnd.h"
9 #include <qbrush.h>
10 #include <qfileinfo.h>
11 #include <qlistbox.h>
12 #include <kapp.h>
13 #if QT_VERSION >= 200
14 #include <klocale.h> /* i18n */
15 #else
16 #include <ctype.h>
17 #endif
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 #include "mydebug.h"
25 WinStack::WinStack(QWidget* parent, const char* name) :
26 QWidget(parent, name),
27 m_activeWindow(0),
28 m_windowMenu(0),
29 m_itemMore(0),
30 m_pcLine(-1),
31 m_valueTip(this),
32 m_tipLocation(1,1,10,10),
33 m_tabWidth(0)
35 // Call menu implementation helper
36 initMenu();
38 connect(&m_findDlg.m_buttonForward,
39 SIGNAL(clicked()), SLOT(slotFindForward()));
40 connect(&m_findDlg.m_buttonBackward,
41 SIGNAL(clicked()), SLOT(slotFindBackward()));
43 connect(this, SIGNAL(setTabWidth(int)), this, SLOT(slotSetTabWidth(int)));
45 // Check for right click event.
46 connect(this, SIGNAL(clickedRight(const QPoint &)),
47 SLOT(slotWidgetRightClick(const QPoint &)));
50 WinStack::~WinStack()
54 // All menu initializations.
55 void WinStack::initMenu()
57 // Init float popup menu.
58 m_menuFloat.insertItem(i18n("&Open Source..."), ID_FILE_OPEN);
59 m_menuFloat.insertSeparator();
60 m_menuFloat.insertItem(i18n("Step &into"), ID_PROGRAM_STEP);
61 m_menuFloat.insertItem(i18n("Step &over"), ID_PROGRAM_NEXT);
62 m_menuFloat.insertItem(i18n("Step o&ut"), ID_PROGRAM_FINISH);
63 m_menuFloat.insertItem(i18n("Run to &cursor"), ID_PROGRAM_UNTIL);
64 m_menuFloat.insertSeparator();
65 m_menuFloat.insertItem(i18n("Set/Clear &breakpoint"), ID_BRKPT_SET);
67 // Init float file popup.
68 m_menuFileFloat.insertItem(i18n("&Open Source..."), ID_FILE_OPEN);
69 m_menuFileFloat.insertSeparator();
70 m_menuFileFloat.insertItem(i18n("&Executable..."), ID_FILE_EXECUTABLE);
71 m_menuFileFloat.insertItem(i18n("&Core dump..."), ID_FILE_COREFILE);
74 void WinStack::setWindowMenu(QPopupMenu* menu)
76 m_windowMenu = menu;
77 if (menu == 0) {
78 return;
81 // find entry More...
82 m_itemMore = menu->indexOf(ID_WINDOW_MORE);
83 // must contain item More...
84 ASSERT(m_itemMore >= 0);
86 m_textMore = menu->text(ID_WINDOW_MORE);
87 menu->removeItemAt(m_itemMore);
90 void WinStack::menuCallback(int item)
92 TRACE("menu item=" + QString().setNum(item));
93 // check for window
94 if ((item & ~ID_WINDOW_INDEX_MASK) == ID_WINDOW_MORE) {
95 selectWindow(item & ID_WINDOW_INDEX_MASK);
96 return;
99 switch (item) {
100 case ID_FILE_RELOAD:
101 if (m_activeWindow != 0) {
102 TRACE("reloading one file");
103 m_activeWindow->reloadFile();
105 break;
106 case ID_VIEW_FINDDLG:
107 if (m_findDlg.isVisible()) {
108 m_findDlg.done(0);
109 } else {
110 m_findDlg.show();
112 case ID_BRKPT_SET:
113 case ID_BRKPT_TEMP:
115 QString file;
116 int lineNo;
117 DbgAddr address;
118 if (activeLine(file, lineNo, address))
119 emit toggleBreak(file, lineNo, address, item == ID_BRKPT_TEMP);
121 break;
122 case ID_BRKPT_ENABLE:
124 QString file;
125 int lineNo;
126 DbgAddr address;
127 if (activeLine(file, lineNo, address))
128 emit enadisBreak(file, lineNo, address);
130 break;
134 void WinStack::mousePressEvent(QMouseEvent* mouseEvent)
136 // Check if right button was clicked.
137 if (mouseEvent->button() == RightButton)
139 emit clickedRight(mouseEvent->pos());
140 } else {
141 QWidget::mousePressEvent(mouseEvent);
146 void WinStack::reloadAllFiles()
148 SourceWindow* fw;
149 for (fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
150 fw->reloadFile();
154 void WinStack::activate(const QString& fileName, int lineNo, const DbgAddr& address)
156 QFileInfo fi(fileName);
158 if (!fi.isFile()) {
160 * We didn't find that file. Now check if it is a relative path and
161 * try m_lastOpenDir as prefix.
163 TRACE(fi.filePath() + (" not found, looking in " + m_lastOpenDir));
164 if (!fi.isRelative() || m_lastOpenDir.isEmpty()) {
165 return;
167 fi.setFile(m_lastOpenDir + "/" + fi.filePath());
168 if (!fi.isFile()) {
169 return;
172 // if this is not an absolute path name, make it one
173 activatePath(fi.absFilePath(), lineNo, address);
176 void WinStack::activateFile(const QString& fileName)
178 activatePath(fileName, 0, DbgAddr());
181 bool WinStack::activatePath(QString pathName, int lineNo, const DbgAddr& address)
183 // check whether the file is already open
184 SourceWindow* fw;
185 for (fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
186 if (fw->fileName() == pathName) {
187 break;
190 if (fw == 0) {
191 // not found, load it
192 fw = new SourceWindow(pathName, this, "fileWindow");
193 m_fileList.insert(0, fw);
194 connect(fw, SIGNAL(lineChanged()),SIGNAL(lineChanged()));
195 connect(fw, SIGNAL(clickedLeft(const QString&,int,const DbgAddr&,bool)),
196 SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)));
197 connect(fw, SIGNAL(clickedMid(const QString&,int,const DbgAddr&)),
198 SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)));
200 // Comunication when right button is clicked.
201 connect(fw, SIGNAL(clickedRight(const QPoint &)),
202 SLOT(slotFileWindowRightClick(const QPoint &)));
204 // disassemble code
205 connect(fw, SIGNAL(disassemble(const QString&, int)),
206 SIGNAL(disassemble(const QString&, int)));
207 connect(fw, SIGNAL(expanded(int)), SLOT(slotExpandCollapse(int)));
208 connect(fw, SIGNAL(collapsed(int)), SLOT(slotExpandCollapse(int)));
210 // tab width
211 connect(this, SIGNAL(setTabWidth(int)), fw, SLOT(setTabWidth(int)));
212 fw->setTabWidth(m_tabWidth);
214 changeWindowMenu();
216 // slurp the file in
217 fw->loadFile();
219 // set PC if there is one
220 emit newFileLoaded();
221 if (m_pcLine >= 0) {
222 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
225 return activateWindow(fw, lineNo, address);
228 bool WinStack::activateWindow(SourceWindow* fw, int lineNo, const DbgAddr& address)
230 int index = m_fileList.findRef(fw);
231 ASSERT(index >= 0);
232 if (index < 0) {
233 return false;
236 * If the file is not in the list of those that would appear in the
237 * window menu, move it to the first position.
239 if (index >= 9) {
240 m_fileList.remove();
241 m_fileList.insert(0, fw);
242 changeWindowMenu();
245 // make the line visible
246 if (lineNo >= 0) {
247 fw->scrollTo(lineNo, address);
250 // first resize the window, then lift it to the top
251 fw->setGeometry(0,0, width(),height());
252 fw->raise();
253 fw->show();
255 // set the focus to the new active window
256 QWidget* oldActive = m_activeWindow;
257 #if QT_VERSION < 200
258 fw->setFocusPolicy(QWidget::StrongFocus);
259 #else
260 fw->setFocusPolicy(QWidget::WheelFocus);
261 #endif
262 m_activeWindow = fw;
263 if (oldActive != 0 && oldActive != fw) {
264 // disable focus on non-active windows
265 oldActive->setFocusPolicy(QWidget::NoFocus);
267 fw->setFocus();
269 emit fileChanged();
271 return true;
274 bool WinStack::activeLine(QString& fileName, int& lineNo)
276 DbgAddr dummy;
277 return activeLine(fileName, lineNo, dummy);
280 bool WinStack::activeLine(QString& fileName, int& lineNo, DbgAddr& address)
282 if (m_activeWindow == 0) {
283 return false;
286 fileName = m_activeWindow->fileName();
287 m_activeWindow->activeLine(lineNo, address);
288 return true;
291 void WinStack::changeWindowMenu()
293 if (m_windowMenu == 0) {
294 return;
297 // delete window entries
298 while ((m_windowMenu->idAt(m_itemMore) & ~ID_WINDOW_INDEX_MASK) == ID_WINDOW_MORE) {
299 m_windowMenu->removeItemAt(m_itemMore);
302 // insert current windows
303 QString text;
304 int index = 1;
305 SourceWindow* fw = 0;
306 for (fw = m_fileList.first(); fw != 0 && index < 10; fw = m_fileList.next()) {
307 text.sprintf("&%d ", index);
308 text += fw->fileName();
309 m_windowMenu->insertItem(text, ID_WINDOW_MORE+index, m_itemMore+index-1);
310 index++;
312 if (fw != 0) {
313 // there are still windows
314 m_windowMenu->insertItem(m_textMore, ID_WINDOW_MORE, m_itemMore+9);
318 void WinStack::updateLineItems(const KDebugger* dbg)
320 SourceWindow* fw = 0;
321 for (fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
322 fw->updateLineItems(dbg);
326 void WinStack::updatePC(const QString& fileName, int lineNo, const DbgAddr& address, int frameNo)
328 if (m_pcLine >= 0) {
329 setPC(false, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
331 m_pcFile = fileName;
332 m_pcLine = lineNo;
333 m_pcAddress = address.asString();
334 m_pcFrame = frameNo;
335 if (lineNo >= 0) {
336 setPC(true, fileName, lineNo, address, frameNo);
340 void WinStack::setPC(bool set, const QString& fileName, int lineNo,
341 const DbgAddr& address, int frameNo)
343 TRACE((set ? "set PC: " : "clear PC: ") + fileName +
344 QString().sprintf(":%d#%d ", lineNo, frameNo) + address.asString());
345 // find file
346 SourceWindow* fw = 0;
347 for (fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
348 if (fw->fileNameMatches(fileName)) {
349 fw->setPC(set, lineNo, address, frameNo);
350 break;
355 void WinStack::resizeEvent(QResizeEvent*)
357 ASSERT(m_activeWindow == 0 || m_fileList.findRef(m_activeWindow) >= 0);
358 if (m_activeWindow != 0) {
359 m_activeWindow->resize(width(), height());
363 void WinStack::slotFindForward()
365 if (m_activeWindow != 0)
366 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
367 SourceWindow::findForward);
370 void WinStack::slotFindBackward()
372 if (m_activeWindow != 0)
373 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
374 SourceWindow::findBackward);
377 void WinStack::slotFileWindowRightClick(const QPoint & pos)
379 if (m_menuFloat.isVisible())
381 m_menuFloat.hide();
383 else
385 m_menuFloat.popup(mapToGlobal(pos));
389 void WinStack::slotWidgetRightClick(const QPoint & pos)
391 if (m_menuFileFloat.isVisible())
393 m_menuFileFloat.hide();
395 else
397 m_menuFileFloat.popup(mapToGlobal(pos));
401 void WinStack::maybeTip(const QPoint& p)
403 if (m_activeWindow == 0)
404 return;
406 // get the word at the point
407 QString word;
408 QRect r;
409 if (!m_activeWindow->wordAtPoint(p, word, r))
410 return;
412 // must be valid
413 assert(!word.isEmpty());
414 assert(r.isValid());
416 // remember the location
417 m_tipLocation = r;
419 emit initiateValuePopup(word);
422 void WinStack::slotShowValueTip(const QString& tipText)
424 m_valueTip.tip(m_tipLocation, tipText);
427 void WinStack::slotDisassembled(const QString& fileName, int lineNo,
428 const QList<DisassembledCode>& disass)
430 // lookup the file
431 SourceWindow* fw;
432 for (fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
433 if (fw->fileNameMatches(fileName)) {
434 break;
437 if (fw == 0) {
438 // not found: ignore
439 return;
442 fw->disassembled(lineNo, disass);
445 void WinStack::slotExpandCollapse(int)
447 // update line items after expanding or collapsing disassembled code
449 // HACK: we know that this will result in updateLineItems
450 // should be done more cleanly with a separate signal
451 emit newFileLoaded();
453 if (m_pcLine >= 0) {
454 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
459 void WinStack::slotSetTabWidth(int numChars)
461 m_tabWidth = numChars;
465 ValueTip::ValueTip(WinStack* parent) :
466 QToolTip(parent)
470 void ValueTip::maybeTip(const QPoint& p)
472 WinStack* w = static_cast<WinStack*>(parentWidget());
473 w->maybeTip(p);
477 class MoreWindowsDialog : public QDialog
479 public:
480 MoreWindowsDialog(QWidget* parent);
481 virtual ~MoreWindowsDialog();
483 void insertString(const char* text) { m_list.insertItem(text); }
484 void setListIndex(int i) { m_list.setCurrentItem(i); }
485 int listIndex() const { return m_list.currentItem(); }
487 protected:
488 QListBox m_list;
489 QPushButton m_buttonOK;
490 QPushButton m_buttonCancel;
491 QVBoxLayout m_layout;
492 QHBoxLayout m_buttons;
495 MoreWindowsDialog::MoreWindowsDialog(QWidget* parent) :
496 QDialog(parent, "morewindows", true),
497 m_list(this, "windows"),
498 m_buttonOK(this, "show"),
499 m_buttonCancel(this, "cancel"),
500 m_layout(this, 8),
501 m_buttons(4)
503 QString title = kapp->getCaption();
504 title += i18n(": Open Windows");
505 setCaption(title);
507 m_list.setMinimumSize(250, 100);
508 connect(&m_list, SIGNAL(selected(int)), SLOT(accept()));
510 m_buttonOK.setMinimumSize(100, 30);
511 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
512 m_buttonOK.setText(i18n("Show"));
513 m_buttonOK.setDefault(true);
515 m_buttonCancel.setMinimumSize(100, 30);
516 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
517 m_buttonCancel.setText(i18n("Cancel"));
519 m_layout.addWidget(&m_list, 10);
520 m_layout.addLayout(&m_buttons);
521 m_buttons.addStretch(10);
522 m_buttons.addWidget(&m_buttonOK);
523 m_buttons.addSpacing(40);
524 m_buttons.addWidget(&m_buttonCancel);
525 m_buttons.addStretch(10);
527 m_layout.activate();
529 m_list.setFocus();
530 resize(320, 320);
533 MoreWindowsDialog::~MoreWindowsDialog()
537 void WinStack::selectWindow(int id)
539 int index = 0;
541 if (id == 0) {
542 // more windows selected: show windows in a list
543 MoreWindowsDialog dlg(this);
544 int i = 0;
545 for (SourceWindow* fw = m_fileList.first(); fw != 0; fw = m_fileList.next()) {
546 dlg.insertString(fw->fileName());
547 if (m_activeWindow == fw) {
548 index = i;
550 i++;
552 dlg.setListIndex(index);
553 if (dlg.exec() == QDialog::Rejected)
554 return;
555 index = dlg.listIndex();
556 } else {
557 index = (id & ID_WINDOW_INDEX_MASK)-1;
560 SourceWindow* fw = m_fileList.first();
561 for (; index > 0; index--) {
562 fw = m_fileList.next();
564 ASSERT(fw != 0);
566 activateWindow(fw, -1, DbgAddr());
570 FindDialog::FindDialog() :
571 QDialog(0, "find", false),
572 m_searchText(this, "text"),
573 m_caseCheck(this, "case"),
574 m_buttonForward(this, "forward"),
575 m_buttonBackward(this, "backward"),
576 m_buttonClose(this, "close"),
577 m_layout(this, 8),
578 m_buttons(4)
580 setCaption(QString(kapp->getCaption()) + i18n(": Search"));
582 m_searchText.setMinimumSize(330, 24);
583 m_searchText.setMaxLength(10000);
584 m_searchText.setFrame(true);
586 m_caseCheck.setText(i18n("&Case sensitive"));
587 m_caseCheck.setChecked(true);
588 m_buttonForward.setText(i18n("&Forward"));
589 m_buttonForward.setDefault(true);
590 m_buttonBackward.setText(i18n("&Backward"));
591 m_buttonClose.setText(i18n("Close"));
593 m_caseCheck.setMinimumSize(330, 24);
595 // get maximum size of buttons
596 QSize maxSize(80,30);
597 #if QT_VERSION >= 140
598 maxSize.expandedTo(m_buttonForward.sizeHint());
599 maxSize.expandedTo(m_buttonBackward.sizeHint());
600 maxSize.expandedTo(m_buttonClose.sizeHint());
601 #endif
603 m_buttonForward.setMinimumSize(maxSize);
604 m_buttonBackward.setMinimumSize(maxSize);
605 m_buttonClose.setMinimumSize(maxSize);
607 connect(&m_buttonClose, SIGNAL(clicked()), SLOT(reject()));
609 m_layout.addWidget(&m_searchText);
610 m_layout.addWidget(&m_caseCheck);
611 m_layout.addLayout(&m_buttons);
612 m_layout.addStretch(10);
613 m_buttons.addWidget(&m_buttonForward);
614 m_buttons.addStretch(10);
615 m_buttons.addWidget(&m_buttonBackward);
616 m_buttons.addStretch(10);
617 m_buttons.addWidget(&m_buttonClose);
619 m_layout.activate();
621 m_searchText.setFocus();
622 resize( 350, 120 );
625 FindDialog::~FindDialog()
629 void FindDialog::closeEvent(QCloseEvent* ev)
631 QDialog::closeEvent(ev);
632 emit closed();
635 void FindDialog::done(int result)
637 QDialog::done(result);
638 emit closed();
641 #include "winstack.moc"