Prepare for QTextEdit transition: Add KTextEdit::charAt() for wordAtPoint().
[kdbg.git] / kdbg / winstack.cpp
blob29372915007b3639633bc0ef5f2406780eef4d88
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 <klocale.h> /* i18n */
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 #include "mydebug.h"
20 WinStack::WinStack(QWidget* parent, const char* name) :
21 QWidget(parent, name),
22 m_activeWindow(0),
23 m_windowMenu(0),
24 m_pcLine(-1),
25 m_valueTip(this),
26 m_tipLocation(1,1,10,10),
27 m_tabWidth(0)
29 connect(&m_findDlg.m_buttonForward,
30 SIGNAL(clicked()), SLOT(slotFindForward()));
31 connect(&m_findDlg.m_buttonBackward,
32 SIGNAL(clicked()), SLOT(slotFindBackward()));
34 connect(this, SIGNAL(setTabWidth(int)), this, SLOT(slotSetTabWidth(int)));
37 WinStack::~WinStack()
41 void WinStack::setWindowMenu(QPopupMenu* menu)
43 m_windowMenu = menu;
44 if (menu == 0) {
45 return;
48 // hook up for menu activations
49 connect(menu, SIGNAL(activated(int)), this, SLOT(selectWindow(int)));
52 void WinStack::mousePressEvent(QMouseEvent* mouseEvent)
54 // Check if right button was clicked.
55 if (mouseEvent->button() == RightButton)
57 emit clickedRight(mouseEvent->pos());
58 } else {
59 QWidget::mousePressEvent(mouseEvent);
64 void WinStack::reloadAllFiles()
66 for (int i = 0; i < m_fileList.size(); i++) {
67 m_fileList[i]->reloadFile();
71 QSize WinStack::sizeHint() const
73 return QSize(640, 480);
76 void WinStack::activate(const QString& fileName, int lineNo, const DbgAddr& address)
78 QFileInfo fi(fileName);
80 if (!fi.isFile()) {
82 * We didn't find that file. Now check if it is a relative path and
83 * try m_lastOpenDir as prefix.
85 TRACE(fi.filePath() + (" not found, looking in " + m_lastOpenDir));
86 if (!fi.isRelative() || m_lastOpenDir.isEmpty()) {
87 return;
89 fi.setFile(m_lastOpenDir + "/" + fi.filePath());
90 if (!fi.isFile()) {
91 return;
94 // if this is not an absolute path name, make it one
95 activatePath(fi.absFilePath(), lineNo, address);
98 void WinStack::activateFile(const QString& fileName)
100 activatePath(fileName, 0, DbgAddr());
103 bool WinStack::activatePath(QString pathName, int lineNo, const DbgAddr& address)
105 // check whether the file is already open
106 SourceWindow* fw = 0;
107 for (int i = 0; i < m_fileList.size(); i++) {
108 if (m_fileList[i]->fileName() == pathName) {
109 fw = m_fileList[i];
110 break;
113 if (fw == 0) {
114 // not found, load it
115 fw = new SourceWindow(pathName, this, "fileWindow");
117 // slurp the file in
118 if (!fw->loadFile()) {
119 // read failed
120 delete fw;
121 return false;
124 m_fileList.insertAt(0, fw);
125 connect(fw, SIGNAL(lineChanged()),SIGNAL(lineChanged()));
126 connect(fw, SIGNAL(clickedLeft(const QString&,int,const DbgAddr&,bool)),
127 SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)));
128 connect(fw, SIGNAL(clickedMid(const QString&,int,const DbgAddr&)),
129 SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)));
131 // Comunication when right button is clicked.
132 connect(fw, SIGNAL(clickedRight(const QPoint &)),
133 SIGNAL(filesRightClick(const QPoint &)));
135 // disassemble code
136 connect(fw, SIGNAL(disassemble(const QString&, int)),
137 SIGNAL(disassemble(const QString&, int)));
138 connect(fw, SIGNAL(expanded(int)), SLOT(slotExpandCollapse(int)));
139 connect(fw, SIGNAL(collapsed(int)), SLOT(slotExpandCollapse(int)));
141 // tab width
142 connect(this, SIGNAL(setTabWidth(int)), fw, SLOT(setTabWidth(int)));
143 fw->setTabWidth(m_tabWidth);
145 changeWindowMenu();
147 // set PC if there is one
148 emit newFileLoaded();
149 if (m_pcLine >= 0) {
150 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
153 return activateWindow(fw, lineNo, address);
156 bool WinStack::activateWindow(SourceWindow* fw, int lineNo, const DbgAddr& address)
158 // lookup fw
159 int index = m_fileList.size()-1;
160 while (index >= 0 && m_fileList[index] != fw)
161 --index;
162 ASSERT(index >= 0);
163 if (index < 0) {
164 return false;
167 * If the file is not in the list of those that would appear in the
168 * window menu, move it to the first position.
170 if (index >= 9) {
171 m_fileList.removeAt(index);
172 m_fileList.insertAt(0, fw);
173 changeWindowMenu();
176 // make the line visible
177 if (lineNo >= 0) {
178 fw->scrollTo(lineNo, address);
181 // first resize the window, then lift it to the top
182 fw->setGeometry(0,0, width(),height());
183 fw->raise();
184 fw->show();
186 // set the focus to the new active window
187 QWidget* oldActive = m_activeWindow;
188 fw->setFocusPolicy(QWidget::WheelFocus);
189 m_activeWindow = fw;
190 if (oldActive != 0 && oldActive != fw) {
191 // disable focus on non-active windows
192 oldActive->setFocusPolicy(QWidget::NoFocus);
194 fw->setFocus();
196 emit fileChanged();
198 return true;
201 bool WinStack::activeLine(QString& fileName, int& lineNo)
203 DbgAddr dummy;
204 return activeLine(fileName, lineNo, dummy);
207 bool WinStack::activeLine(QString& fileName, int& lineNo, DbgAddr& address)
209 if (m_activeWindow == 0) {
210 return false;
213 fileName = m_activeWindow->fileName();
214 m_activeWindow->activeLine(lineNo, address);
215 return true;
218 void WinStack::changeWindowMenu()
220 if (m_windowMenu == 0) {
221 return;
224 const int N = 9;
225 // Delete entries at most the N window entries that we insert below.
226 // When we get here if the More entry was selected, we must make sure
227 // that we don't delete it (or we crash).
228 bool haveMore = m_windowMenu->count() > uint(N);
229 int k = haveMore ? N : m_windowMenu->count();
231 for (int i = 0; i < k; i++) {
232 m_windowMenu->removeItemAt(0);
235 // insert current windows
236 QString text;
237 for (int i = 0; i < m_fileList.size() && i < N; i++) {
238 text.sprintf("&%d ", i+1);
239 text += m_fileList[i]->fileName();
240 m_windowMenu->insertItem(text, WindowMore+i+1, i);
242 // add More entry if we have none yet
243 if (!haveMore && m_fileList.size() > N) {
244 m_windowMenu->insertItem(i18n("&More..."), WindowMore, N);
248 void WinStack::updateLineItems(const KDebugger* dbg)
250 for (int i = 0; i < m_fileList.size(); i++) {
251 m_fileList[i]->updateLineItems(dbg);
255 void WinStack::updatePC(const QString& fileName, int lineNo, const DbgAddr& address, int frameNo)
257 if (m_pcLine >= 0) {
258 setPC(false, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
260 m_pcFile = fileName;
261 m_pcLine = lineNo;
262 m_pcAddress = address.asString();
263 m_pcFrame = frameNo;
264 if (lineNo >= 0) {
265 setPC(true, fileName, lineNo, address, frameNo);
269 void WinStack::setPC(bool set, const QString& fileName, int lineNo,
270 const DbgAddr& address, int frameNo)
272 TRACE((set ? "set PC: " : "clear PC: ") + fileName +
273 QString().sprintf(":%d#%d ", lineNo, frameNo) + address.asString());
274 // find file
275 for (int i = 0; i < m_fileList.size(); i++) {
276 if (m_fileList[i]->fileNameMatches(fileName)) {
277 m_fileList[i]->setPC(set, lineNo, address, frameNo);
278 break;
283 void WinStack::resizeEvent(QResizeEvent*)
285 if (m_activeWindow != 0) {
286 m_activeWindow->resize(width(), height());
290 QString WinStack::activeFileName() const
292 QString f;
293 if (m_activeWindow != 0)
294 f = m_activeWindow->fileName();
295 return f;
298 void WinStack::slotFindForward()
300 if (m_activeWindow != 0)
301 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
302 SourceWindow::findForward);
305 void WinStack::slotFindBackward()
307 if (m_activeWindow != 0)
308 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
309 SourceWindow::findBackward);
312 void WinStack::maybeTip(const QPoint& p)
314 if (m_activeWindow == 0)
315 return;
317 // get the word at the point
318 QString word;
319 QRect r;
320 if (!m_activeWindow->wordAtPoint(p, word, r))
321 return;
323 // must be valid
324 assert(!word.isEmpty());
325 assert(r.isValid());
327 // remember the location
328 m_tipLocation = r;
330 emit initiateValuePopup(word);
333 void WinStack::slotShowValueTip(const QString& tipText)
335 m_valueTip.tip(m_tipLocation, tipText);
338 void WinStack::slotDisassembled(const QString& fileName, int lineNo,
339 const QList<DisassembledCode>& disass)
341 // lookup the file
342 SourceWindow* fw = 0;
343 for (int i = 0; i < m_fileList.size(); i++) {
344 if (m_fileList[i]->fileNameMatches(fileName)) {
345 fw = m_fileList[i];
346 break;
349 if (fw == 0) {
350 // not found: ignore
351 return;
354 fw->disassembled(lineNo, disass);
357 void WinStack::slotExpandCollapse(int)
359 // update line items after expanding or collapsing disassembled code
361 // HACK: we know that this will result in updateLineItems
362 // should be done more cleanly with a separate signal
363 emit newFileLoaded();
365 if (m_pcLine >= 0) {
366 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
371 void WinStack::slotSetTabWidth(int numChars)
373 m_tabWidth = numChars;
376 void WinStack::slotFileReload()
378 if (m_activeWindow != 0) {
379 TRACE("reloading one file");
380 m_activeWindow->reloadFile();
384 void WinStack::slotViewFind()
386 if (m_findDlg.isVisible()) {
387 m_findDlg.done(0);
388 } else {
389 m_findDlg.show();
393 void WinStack::slotBrkptSet()
395 QString file;
396 int lineNo;
397 DbgAddr address;
398 if (activeLine(file, lineNo, address))
399 emit toggleBreak(file, lineNo, address, false);
402 void WinStack::slotBrkptSetTemp()
404 QString file;
405 int lineNo;
406 DbgAddr address;
407 if (activeLine(file, lineNo, address))
408 emit toggleBreak(file, lineNo, address, true);
411 void WinStack::slotBrkptEnable()
413 QString file;
414 int lineNo;
415 DbgAddr address;
416 if (activeLine(file, lineNo, address))
417 emit enadisBreak(file, lineNo, address);
420 void WinStack::slotMoveProgramCounter()
422 QString file;
423 int lineNo;
424 DbgAddr address;
425 if (activeLine(file, lineNo, address))
426 emit moveProgramCounter(file, lineNo, address);
430 ValueTip::ValueTip(WinStack* parent) :
431 QToolTip(parent)
435 void ValueTip::maybeTip(const QPoint& p)
437 WinStack* w = static_cast<WinStack*>(parentWidget());
438 w->maybeTip(p);
442 class MoreWindowsDialog : public QDialog
444 public:
445 MoreWindowsDialog(QWidget* parent);
446 virtual ~MoreWindowsDialog();
448 void insertString(const char* text) { m_list.insertItem(text); }
449 void setListIndex(int i) { m_list.setCurrentItem(i); }
450 int listIndex() const { return m_list.currentItem(); }
452 protected:
453 QListBox m_list;
454 QPushButton m_buttonOK;
455 QPushButton m_buttonCancel;
456 QVBoxLayout m_layout;
457 QHBoxLayout m_buttons;
460 MoreWindowsDialog::MoreWindowsDialog(QWidget* parent) :
461 QDialog(parent, "morewindows", true),
462 m_list(this, "windows"),
463 m_buttonOK(this, "show"),
464 m_buttonCancel(this, "cancel"),
465 m_layout(this, 8),
466 m_buttons(4)
468 QString title = kapp->caption();
469 title += i18n(": Open Windows");
470 setCaption(title);
472 m_list.setMinimumSize(250, 100);
473 connect(&m_list, SIGNAL(selected(int)), SLOT(accept()));
475 m_buttonOK.setMinimumSize(100, 30);
476 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
477 m_buttonOK.setText(i18n("Show"));
478 m_buttonOK.setDefault(true);
480 m_buttonCancel.setMinimumSize(100, 30);
481 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
482 m_buttonCancel.setText(i18n("Cancel"));
484 m_layout.addWidget(&m_list, 10);
485 m_layout.addLayout(&m_buttons);
486 m_buttons.addStretch(10);
487 m_buttons.addWidget(&m_buttonOK);
488 m_buttons.addSpacing(40);
489 m_buttons.addWidget(&m_buttonCancel);
490 m_buttons.addStretch(10);
492 m_layout.activate();
494 m_list.setFocus();
495 resize(320, 320);
498 MoreWindowsDialog::~MoreWindowsDialog()
502 void WinStack::selectWindow(int id)
504 // react only on menu entries concerning windows
505 if ((id & ~WindowMask) != WindowMore) {
506 return;
509 id &= WindowMask;
511 int index = 0;
513 if (id == 0) {
514 // more windows selected: show windows in a list
515 MoreWindowsDialog dlg(this);
516 for (int i = 0; i < m_fileList.size(); i++)
518 dlg.insertString(m_fileList[i]->fileName());
519 if (m_activeWindow == m_fileList[i]) {
520 index = i;
523 dlg.setListIndex(index);
524 if (dlg.exec() == QDialog::Rejected)
525 return;
526 index = dlg.listIndex();
527 } else {
528 index = (id & WindowMask)-1;
531 SourceWindow* fw = m_fileList[index];
532 ASSERT(fw != 0);
534 activateWindow(fw, -1, DbgAddr());
538 FindDialog::FindDialog() :
539 QDialog(0, "find", false),
540 m_searchText(this, "text"),
541 m_caseCheck(this, "case"),
542 m_buttonForward(this, "forward"),
543 m_buttonBackward(this, "backward"),
544 m_buttonClose(this, "close"),
545 m_layout(this, 8),
546 m_buttons(4)
548 setCaption(QString(kapp->caption()) + i18n(": Search"));
550 m_searchText.setMinimumSize(330, 24);
551 m_searchText.setMaxLength(10000);
552 m_searchText.setFrame(true);
554 m_caseCheck.setText(i18n("&Case sensitive"));
555 m_caseCheck.setChecked(true);
556 m_buttonForward.setText(i18n("&Forward"));
557 m_buttonForward.setDefault(true);
558 m_buttonBackward.setText(i18n("&Backward"));
559 m_buttonClose.setText(i18n("Close"));
561 m_caseCheck.setMinimumSize(330, 24);
563 // get maximum size of buttons
564 QSize maxSize(80,30);
565 maxSize.expandedTo(m_buttonForward.sizeHint());
566 maxSize.expandedTo(m_buttonBackward.sizeHint());
567 maxSize.expandedTo(m_buttonClose.sizeHint());
569 m_buttonForward.setMinimumSize(maxSize);
570 m_buttonBackward.setMinimumSize(maxSize);
571 m_buttonClose.setMinimumSize(maxSize);
573 connect(&m_buttonClose, SIGNAL(clicked()), SLOT(reject()));
575 m_layout.addWidget(&m_searchText);
576 m_layout.addWidget(&m_caseCheck);
577 m_layout.addLayout(&m_buttons);
578 m_layout.addStretch(10);
579 m_buttons.addWidget(&m_buttonForward);
580 m_buttons.addStretch(10);
581 m_buttons.addWidget(&m_buttonBackward);
582 m_buttons.addStretch(10);
583 m_buttons.addWidget(&m_buttonClose);
585 m_layout.activate();
587 m_searchText.setFocus();
588 resize( 350, 120 );
591 FindDialog::~FindDialog()
595 void FindDialog::closeEvent(QCloseEvent* ev)
597 QDialog::closeEvent(ev);
598 emit closed();
601 void FindDialog::done(int result)
603 QDialog::done(result);
604 emit closed();
607 #include "winstack.moc"