Don't start with a tiny window when started for the first time.
[kdbg.git] / kdbg / winstack.cpp
blob668e4ed6e2a423768e571f670056a322c3efd84d
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 void WinStack::slotFindForward()
292 if (m_activeWindow != 0)
293 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
294 SourceWindow::findForward);
297 void WinStack::slotFindBackward()
299 if (m_activeWindow != 0)
300 m_activeWindow->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
301 SourceWindow::findBackward);
304 void WinStack::maybeTip(const QPoint& p)
306 if (m_activeWindow == 0)
307 return;
309 // get the word at the point
310 QString word;
311 QRect r;
312 if (!m_activeWindow->wordAtPoint(p, word, r))
313 return;
315 // must be valid
316 assert(!word.isEmpty());
317 assert(r.isValid());
319 // remember the location
320 m_tipLocation = r;
322 emit initiateValuePopup(word);
325 void WinStack::slotShowValueTip(const QString& tipText)
327 m_valueTip.tip(m_tipLocation, tipText);
330 void WinStack::slotDisassembled(const QString& fileName, int lineNo,
331 const QList<DisassembledCode>& disass)
333 // lookup the file
334 SourceWindow* fw = 0;
335 for (int i = 0; i < m_fileList.size(); i++) {
336 if (m_fileList[i]->fileNameMatches(fileName)) {
337 fw = m_fileList[i];
338 break;
341 if (fw == 0) {
342 // not found: ignore
343 return;
346 fw->disassembled(lineNo, disass);
349 void WinStack::slotExpandCollapse(int)
351 // update line items after expanding or collapsing disassembled code
353 // HACK: we know that this will result in updateLineItems
354 // should be done more cleanly with a separate signal
355 emit newFileLoaded();
357 if (m_pcLine >= 0) {
358 setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
363 void WinStack::slotSetTabWidth(int numChars)
365 m_tabWidth = numChars;
368 void WinStack::slotFileReload()
370 if (m_activeWindow != 0) {
371 TRACE("reloading one file");
372 m_activeWindow->reloadFile();
376 void WinStack::slotViewFind()
378 if (m_findDlg.isVisible()) {
379 m_findDlg.done(0);
380 } else {
381 m_findDlg.show();
385 void WinStack::slotBrkptSet()
387 QString file;
388 int lineNo;
389 DbgAddr address;
390 if (activeLine(file, lineNo, address))
391 emit toggleBreak(file, lineNo, address, false);
394 void WinStack::slotBrkptSetTemp()
396 QString file;
397 int lineNo;
398 DbgAddr address;
399 if (activeLine(file, lineNo, address))
400 emit toggleBreak(file, lineNo, address, true);
403 void WinStack::slotBrkptEnable()
405 QString file;
406 int lineNo;
407 DbgAddr address;
408 if (activeLine(file, lineNo, address))
409 emit enadisBreak(file, lineNo, address);
412 void WinStack::slotMoveProgramCounter()
414 QString file;
415 int lineNo;
416 DbgAddr address;
417 if (activeLine(file, lineNo, address))
418 emit moveProgramCounter(file, lineNo, address);
422 ValueTip::ValueTip(WinStack* parent) :
423 QToolTip(parent)
427 void ValueTip::maybeTip(const QPoint& p)
429 WinStack* w = static_cast<WinStack*>(parentWidget());
430 w->maybeTip(p);
434 class MoreWindowsDialog : public QDialog
436 public:
437 MoreWindowsDialog(QWidget* parent);
438 virtual ~MoreWindowsDialog();
440 void insertString(const char* text) { m_list.insertItem(text); }
441 void setListIndex(int i) { m_list.setCurrentItem(i); }
442 int listIndex() const { return m_list.currentItem(); }
444 protected:
445 QListBox m_list;
446 QPushButton m_buttonOK;
447 QPushButton m_buttonCancel;
448 QVBoxLayout m_layout;
449 QHBoxLayout m_buttons;
452 MoreWindowsDialog::MoreWindowsDialog(QWidget* parent) :
453 QDialog(parent, "morewindows", true),
454 m_list(this, "windows"),
455 m_buttonOK(this, "show"),
456 m_buttonCancel(this, "cancel"),
457 m_layout(this, 8),
458 m_buttons(4)
460 QString title = kapp->caption();
461 title += i18n(": Open Windows");
462 setCaption(title);
464 m_list.setMinimumSize(250, 100);
465 connect(&m_list, SIGNAL(selected(int)), SLOT(accept()));
467 m_buttonOK.setMinimumSize(100, 30);
468 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
469 m_buttonOK.setText(i18n("Show"));
470 m_buttonOK.setDefault(true);
472 m_buttonCancel.setMinimumSize(100, 30);
473 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
474 m_buttonCancel.setText(i18n("Cancel"));
476 m_layout.addWidget(&m_list, 10);
477 m_layout.addLayout(&m_buttons);
478 m_buttons.addStretch(10);
479 m_buttons.addWidget(&m_buttonOK);
480 m_buttons.addSpacing(40);
481 m_buttons.addWidget(&m_buttonCancel);
482 m_buttons.addStretch(10);
484 m_layout.activate();
486 m_list.setFocus();
487 resize(320, 320);
490 MoreWindowsDialog::~MoreWindowsDialog()
494 void WinStack::selectWindow(int id)
496 // react only on menu entries concerning windows
497 if ((id & ~WindowMask) != WindowMore) {
498 return;
501 id &= WindowMask;
503 int index = 0;
505 if (id == 0) {
506 // more windows selected: show windows in a list
507 MoreWindowsDialog dlg(this);
508 for (int i = 0; i < m_fileList.size(); i++)
510 dlg.insertString(m_fileList[i]->fileName());
511 if (m_activeWindow == m_fileList[i]) {
512 index = i;
515 dlg.setListIndex(index);
516 if (dlg.exec() == QDialog::Rejected)
517 return;
518 index = dlg.listIndex();
519 } else {
520 index = (id & WindowMask)-1;
523 SourceWindow* fw = m_fileList[index];
524 ASSERT(fw != 0);
526 activateWindow(fw, -1, DbgAddr());
530 FindDialog::FindDialog() :
531 QDialog(0, "find", false),
532 m_searchText(this, "text"),
533 m_caseCheck(this, "case"),
534 m_buttonForward(this, "forward"),
535 m_buttonBackward(this, "backward"),
536 m_buttonClose(this, "close"),
537 m_layout(this, 8),
538 m_buttons(4)
540 setCaption(QString(kapp->caption()) + i18n(": Search"));
542 m_searchText.setMinimumSize(330, 24);
543 m_searchText.setMaxLength(10000);
544 m_searchText.setFrame(true);
546 m_caseCheck.setText(i18n("&Case sensitive"));
547 m_caseCheck.setChecked(true);
548 m_buttonForward.setText(i18n("&Forward"));
549 m_buttonForward.setDefault(true);
550 m_buttonBackward.setText(i18n("&Backward"));
551 m_buttonClose.setText(i18n("Close"));
553 m_caseCheck.setMinimumSize(330, 24);
555 // get maximum size of buttons
556 QSize maxSize(80,30);
557 maxSize.expandedTo(m_buttonForward.sizeHint());
558 maxSize.expandedTo(m_buttonBackward.sizeHint());
559 maxSize.expandedTo(m_buttonClose.sizeHint());
561 m_buttonForward.setMinimumSize(maxSize);
562 m_buttonBackward.setMinimumSize(maxSize);
563 m_buttonClose.setMinimumSize(maxSize);
565 connect(&m_buttonClose, SIGNAL(clicked()), SLOT(reject()));
567 m_layout.addWidget(&m_searchText);
568 m_layout.addWidget(&m_caseCheck);
569 m_layout.addLayout(&m_buttons);
570 m_layout.addStretch(10);
571 m_buttons.addWidget(&m_buttonForward);
572 m_buttons.addStretch(10);
573 m_buttons.addWidget(&m_buttonBackward);
574 m_buttons.addStretch(10);
575 m_buttons.addWidget(&m_buttonClose);
577 m_layout.activate();
579 m_searchText.setFocus();
580 resize( 350, 120 );
583 FindDialog::~FindDialog()
587 void FindDialog::closeEvent(QCloseEvent* ev)
589 QDialog::closeEvent(ev);
590 emit closed();
593 void FindDialog::done(int result)
595 QDialog::done(result);
596 emit closed();
599 #include "winstack.moc"