Merge branch 'maint'
[kdbg.git] / kdbg / winstack.cpp
blob3bf81d21d24b8b670e7cb348720294cacc4311a7
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include "winstack.h"
7 #include "sourcewnd.h"
8 #include <qbrush.h>
9 #include <qfileinfo.h>
10 #include <qlistbox.h>
11 #include <kapp.h>
12 #include <kmainwindow.h>
13 #include <klocale.h> /* i18n */
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 #include "mydebug.h"
21 WinStack::WinStack(QWidget* parent, const char* name) :
22 QWidget(parent, name),
23 m_activeWindow(0),
24 m_windowMenu(0),
25 m_pcLine(-1),
26 m_valueTip(this),
27 m_tipLocation(1,1,10,10),
28 m_tabWidth(0)
30 connect(&m_findDlg.m_buttonForward,
31 SIGNAL(clicked()), SLOT(slotFindForward()));
32 connect(&m_findDlg.m_buttonBackward,
33 SIGNAL(clicked()), SLOT(slotFindBackward()));
35 connect(this, SIGNAL(setTabWidth(int)), this, SLOT(slotSetTabWidth(int)));
38 WinStack::~WinStack()
42 void WinStack::setWindowMenu(QPopupMenu* menu)
44 m_windowMenu = menu;
45 if (menu == 0) {
46 return;
49 // hook up for menu activations
50 connect(menu, SIGNAL(activated(int)), this, SLOT(selectWindow(int)));
53 void WinStack::contextMenuEvent(QContextMenuEvent* e)
55 // get the context menu from the GUI factory
56 QWidget* top = this;
58 top = top->parentWidget();
59 while (!top->isTopLevel());
60 KMainWindow* mw = static_cast<KMainWindow*>(top);
61 QPopupMenu* m =
62 static_cast<QPopupMenu*>(mw->factory()->container("popup_files_empty", mw));
63 m->exec(e->globalPos());
67 void WinStack::reloadAllFiles()
69 for (int i = 0; i < m_fileList.size(); i++) {
70 m_fileList[i]->reloadFile();
74 QSize WinStack::sizeHint() const
76 return QSize(640, 480);
79 void WinStack::activate(const QString& fileName, int lineNo, const DbgAddr& address)
81 QFileInfo fi(fileName);
83 if (!fi.isFile()) {
85 * We didn't find that file. Now check if it is a relative path and
86 * try m_lastOpenDir as prefix.
88 TRACE(fi.filePath() + (" not found, looking in " + m_lastOpenDir));
89 if (!fi.isRelative() || m_lastOpenDir.isEmpty()) {
90 return;
92 fi.setFile(m_lastOpenDir + "/" + fi.filePath());
93 if (!fi.isFile()) {
94 return;
97 // if this is not an absolute path name, make it one
98 activatePath(fi.absFilePath(), lineNo, address);
101 void WinStack::activateFile(const QString& fileName)
103 activatePath(fileName, 0, DbgAddr());
106 bool WinStack::activatePath(QString pathName, int lineNo, const DbgAddr& address)
108 // check whether the file is already open
109 SourceWindow* fw = 0;
110 for (int i = 0; i < m_fileList.size(); i++) {
111 if (m_fileList[i]->fileName() == pathName) {
112 fw = m_fileList[i];
113 break;
116 if (fw == 0) {
117 // not found, load it
118 fw = new SourceWindow(pathName, this, "fileWindow");
120 // slurp the file in
121 if (!fw->loadFile()) {
122 // read failed
123 delete fw;
124 return false;
127 m_fileList.insertAt(0, fw);
128 connect(fw, SIGNAL(lineChanged()),SIGNAL(lineChanged()));
129 connect(fw, SIGNAL(clickedLeft(const QString&,int,const DbgAddr&,bool)),
130 SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)));
131 connect(fw, SIGNAL(clickedMid(const QString&,int,const DbgAddr&)),
132 SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)));
134 // disassemble code
135 connect(fw, SIGNAL(disassemble(const QString&, int)),
136 SIGNAL(disassemble(const QString&, int)));
137 connect(fw, SIGNAL(expanded(int)), SLOT(slotExpandCollapse(int)));
138 connect(fw, SIGNAL(collapsed(int)), SLOT(slotExpandCollapse(int)));
140 // tab width
141 connect(this, SIGNAL(setTabWidth(int)), fw, SLOT(setTabWidth(int)));
142 fw->setTabWidth(m_tabWidth);
144 changeWindowMenu();
146 // set PC if there is one
147 emit newFileLoaded();
148 if (m_pcLine >= 0) {
149 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
152 return activateWindow(fw, lineNo, address);
155 bool WinStack::activateWindow(SourceWindow* fw, int lineNo, const DbgAddr& address)
157 // lookup fw
158 int index = m_fileList.size()-1;
159 while (index >= 0 && m_fileList[index] != fw)
160 --index;
161 ASSERT(index >= 0);
162 if (index < 0) {
163 return false;
166 * If the file is not in the list of those that would appear in the
167 * window menu, move it to the first position.
169 if (index >= 9) {
170 m_fileList.removeAt(index);
171 m_fileList.insertAt(0, fw);
172 changeWindowMenu();
175 // make the line visible
176 if (lineNo >= 0) {
177 fw->scrollTo(lineNo, address);
180 // first resize the window, then lift it to the top
181 fw->setGeometry(0,0, width(),height());
182 fw->raise();
183 fw->show();
185 // set the focus to the new active window
186 QWidget* oldActive = m_activeWindow;
187 fw->setFocusPolicy(QWidget::WheelFocus);
188 m_activeWindow = fw;
189 if (oldActive != 0 && oldActive != fw) {
190 // disable focus on non-active windows
191 oldActive->setFocusPolicy(QWidget::NoFocus);
193 fw->setFocus();
195 emit fileChanged();
197 return true;
200 bool WinStack::activeLine(QString& fileName, int& lineNo)
202 DbgAddr dummy;
203 return activeLine(fileName, lineNo, dummy);
206 bool WinStack::activeLine(QString& fileName, int& lineNo, DbgAddr& address)
208 if (m_activeWindow == 0) {
209 return false;
212 fileName = m_activeWindow->fileName();
213 m_activeWindow->activeLine(lineNo, address);
214 return true;
217 void WinStack::changeWindowMenu()
219 if (m_windowMenu == 0) {
220 return;
223 const int N = 9;
224 // Delete entries at most the N window entries that we insert below.
225 // When we get here if the More entry was selected, we must make sure
226 // that we don't delete it (or we crash).
227 bool haveMore = m_windowMenu->count() > uint(N);
228 int k = haveMore ? N : m_windowMenu->count();
230 for (int i = 0; i < k; i++) {
231 m_windowMenu->removeItemAt(0);
234 // insert current windows
235 QString text;
236 for (int i = 0; i < m_fileList.size() && i < N; i++) {
237 text.sprintf("&%d ", i+1);
238 text += m_fileList[i]->fileName();
239 m_windowMenu->insertItem(text, WindowMore+i+1, i);
241 // add More entry if we have none yet
242 if (!haveMore && m_fileList.size() > N) {
243 m_windowMenu->insertItem(i18n("&More..."), WindowMore, N);
247 void WinStack::updateLineItems(const KDebugger* dbg)
249 for (int i = 0; i < m_fileList.size(); i++) {
250 m_fileList[i]->updateLineItems(dbg);
254 void WinStack::updatePC(const QString& fileName, int lineNo, const DbgAddr& address, int frameNo)
256 if (m_pcLine >= 0) {
257 setPC(false, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
259 m_pcFile = fileName;
260 m_pcLine = lineNo;
261 m_pcAddress = address.asString();
262 m_pcFrame = frameNo;
263 if (lineNo >= 0) {
264 setPC(true, fileName, lineNo, address, frameNo);
268 void WinStack::setPC(bool set, const QString& fileName, int lineNo,
269 const DbgAddr& address, int frameNo)
271 TRACE((set ? "set PC: " : "clear PC: ") + fileName +
272 QString().sprintf(":%d#%d ", lineNo, frameNo) + address.asString());
273 // find file
274 for (int i = 0; i < m_fileList.size(); i++) {
275 if (m_fileList[i]->fileNameMatches(fileName)) {
276 m_fileList[i]->setPC(set, lineNo, address, frameNo);
277 break;
282 void WinStack::resizeEvent(QResizeEvent*)
284 if (m_activeWindow != 0) {
285 m_activeWindow->resize(width(), height());
289 QString WinStack::activeFileName() const
291 QString f;
292 if (m_activeWindow != 0)
293 f = m_activeWindow->fileName();
294 return f;
297 void WinStack::slotFindForward()
299 if (m_activeWindow != 0)
300 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
301 SourceWindow::findForward);
304 void WinStack::slotFindBackward()
306 if (m_activeWindow != 0)
307 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
308 SourceWindow::findBackward);
311 void WinStack::maybeTip(const QPoint& p)
313 if (m_activeWindow == 0)
314 return;
316 // get the word at the point
317 QString word;
318 QRect r;
319 if (!m_activeWindow->wordAtPoint(p, word, r))
320 return;
322 // must be valid
323 assert(!word.isEmpty());
324 assert(r.isValid());
326 // remember the location
327 m_tipLocation = r;
329 emit initiateValuePopup(word);
332 void WinStack::slotShowValueTip(const QString& tipText)
334 m_valueTip.tip(m_tipLocation, tipText);
337 void WinStack::slotDisassembled(const QString& fileName, int lineNo,
338 const QList<DisassembledCode>& disass)
340 // lookup the file
341 SourceWindow* fw = 0;
342 for (int i = 0; i < m_fileList.size(); i++) {
343 if (m_fileList[i]->fileNameMatches(fileName)) {
344 fw = m_fileList[i];
345 break;
348 if (fw == 0) {
349 // not found: ignore
350 return;
353 fw->disassembled(lineNo, disass);
356 void WinStack::slotExpandCollapse(int)
358 // update line items after expanding or collapsing disassembled code
360 // HACK: we know that this will result in updateLineItems
361 // should be done more cleanly with a separate signal
362 emit newFileLoaded();
364 if (m_pcLine >= 0) {
365 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
370 void WinStack::slotSetTabWidth(int numChars)
372 m_tabWidth = numChars;
375 void WinStack::slotFileReload()
377 if (m_activeWindow != 0) {
378 TRACE("reloading one file");
379 m_activeWindow->reloadFile();
383 void WinStack::slotViewFind()
385 if (m_findDlg.isVisible()) {
386 m_findDlg.done(0);
387 } else {
388 m_findDlg.show();
392 void WinStack::slotBrkptSet()
394 QString file;
395 int lineNo;
396 DbgAddr address;
397 if (activeLine(file, lineNo, address))
398 emit toggleBreak(file, lineNo, address, false);
401 void WinStack::slotBrkptSetTemp()
403 QString file;
404 int lineNo;
405 DbgAddr address;
406 if (activeLine(file, lineNo, address))
407 emit toggleBreak(file, lineNo, address, true);
410 void WinStack::slotBrkptEnable()
412 QString file;
413 int lineNo;
414 DbgAddr address;
415 if (activeLine(file, lineNo, address))
416 emit enadisBreak(file, lineNo, address);
419 void WinStack::slotMoveProgramCounter()
421 QString file;
422 int lineNo;
423 DbgAddr address;
424 if (activeLine(file, lineNo, address))
425 emit moveProgramCounter(file, lineNo, address);
429 ValueTip::ValueTip(WinStack* parent) :
430 QToolTip(parent)
434 void ValueTip::maybeTip(const QPoint& p)
436 WinStack* w = static_cast<WinStack*>(parentWidget());
437 w->maybeTip(p);
441 class MoreWindowsDialog : public QDialog
443 public:
444 MoreWindowsDialog(QWidget* parent);
445 virtual ~MoreWindowsDialog();
447 void insertString(const char* text) { m_list.insertItem(text); }
448 void setListIndex(int i) { m_list.setCurrentItem(i); }
449 int listIndex() const { return m_list.currentItem(); }
451 protected:
452 QListBox m_list;
453 QPushButton m_buttonOK;
454 QPushButton m_buttonCancel;
455 QVBoxLayout m_layout;
456 QHBoxLayout m_buttons;
459 MoreWindowsDialog::MoreWindowsDialog(QWidget* parent) :
460 QDialog(parent, "morewindows", true),
461 m_list(this, "windows"),
462 m_buttonOK(this, "show"),
463 m_buttonCancel(this, "cancel"),
464 m_layout(this, 8),
465 m_buttons(4)
467 QString title = kapp->caption();
468 title += i18n(": Open Windows");
469 setCaption(title);
471 m_list.setMinimumSize(250, 100);
472 connect(&m_list, SIGNAL(selected(int)), SLOT(accept()));
474 m_buttonOK.setMinimumSize(100, 30);
475 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
476 m_buttonOK.setText(i18n("Show"));
477 m_buttonOK.setDefault(true);
479 m_buttonCancel.setMinimumSize(100, 30);
480 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
481 m_buttonCancel.setText(i18n("Cancel"));
483 m_layout.addWidget(&m_list, 10);
484 m_layout.addLayout(&m_buttons);
485 m_buttons.addStretch(10);
486 m_buttons.addWidget(&m_buttonOK);
487 m_buttons.addSpacing(40);
488 m_buttons.addWidget(&m_buttonCancel);
489 m_buttons.addStretch(10);
491 m_layout.activate();
493 m_list.setFocus();
494 resize(320, 320);
497 MoreWindowsDialog::~MoreWindowsDialog()
501 void WinStack::selectWindow(int id)
503 // react only on menu entries concerning windows
504 if ((id & ~WindowMask) != WindowMore) {
505 return;
508 id &= WindowMask;
510 int index = 0;
512 if (id == 0) {
513 // more windows selected: show windows in a list
514 MoreWindowsDialog dlg(this);
515 for (int i = 0; i < m_fileList.size(); i++)
517 dlg.insertString(m_fileList[i]->fileName());
518 if (m_activeWindow == m_fileList[i]) {
519 index = i;
522 dlg.setListIndex(index);
523 if (dlg.exec() == QDialog::Rejected)
524 return;
525 index = dlg.listIndex();
526 } else {
527 index = (id & WindowMask)-1;
530 SourceWindow* fw = m_fileList[index];
531 ASSERT(fw != 0);
533 activateWindow(fw, -1, DbgAddr());
537 FindDialog::FindDialog() :
538 QDialog(0, "find", false),
539 m_searchText(this, "text"),
540 m_caseCheck(this, "case"),
541 m_buttonForward(this, "forward"),
542 m_buttonBackward(this, "backward"),
543 m_buttonClose(this, "close"),
544 m_layout(this, 8),
545 m_buttons(4)
547 setCaption(QString(kapp->caption()) + i18n(": Search"));
549 m_searchText.setMinimumSize(330, 24);
550 m_searchText.setMaxLength(10000);
551 m_searchText.setFrame(true);
553 m_caseCheck.setText(i18n("&Case sensitive"));
554 m_caseCheck.setChecked(true);
555 m_buttonForward.setText(i18n("&Forward"));
556 m_buttonForward.setDefault(true);
557 m_buttonBackward.setText(i18n("&Backward"));
558 m_buttonClose.setText(i18n("Close"));
560 m_caseCheck.setMinimumSize(330, 24);
562 // get maximum size of buttons
563 QSize maxSize(80,30);
564 maxSize.expandedTo(m_buttonForward.sizeHint());
565 maxSize.expandedTo(m_buttonBackward.sizeHint());
566 maxSize.expandedTo(m_buttonClose.sizeHint());
568 m_buttonForward.setMinimumSize(maxSize);
569 m_buttonBackward.setMinimumSize(maxSize);
570 m_buttonClose.setMinimumSize(maxSize);
572 connect(&m_buttonClose, SIGNAL(clicked()), SLOT(reject()));
574 m_layout.addWidget(&m_searchText);
575 m_layout.addWidget(&m_caseCheck);
576 m_layout.addLayout(&m_buttons);
577 m_layout.addStretch(10);
578 m_buttons.addWidget(&m_buttonForward);
579 m_buttons.addStretch(10);
580 m_buttons.addWidget(&m_buttonBackward);
581 m_buttons.addStretch(10);
582 m_buttons.addWidget(&m_buttonClose);
584 m_layout.activate();
586 m_searchText.setFocus();
587 resize( 350, 120 );
590 FindDialog::~FindDialog()
594 void FindDialog::closeEvent(QCloseEvent* ev)
596 QDialog::closeEvent(ev);
597 emit closed();
600 void FindDialog::done(int result)
602 QDialog::done(result);
603 emit closed();
606 #include "winstack.moc"