1 /*
2  * Copyright Johannes Sixt
3  * This file is licensed under the GNU General Public License Version 2.
4  * See the file COPYING in the toplevel directory of the source directory.
5  */
6 
7 #include "winstack.h"
8 #include "sourcewnd.h"
9 #include "dbgdriver.h"
10 #include <QFileInfo>
11 #include <QMenu>
12 #include <QContextMenuEvent>
13 #include <QToolTip>
14 #include <kxmlguiwindow.h>
15 #include <kxmlguifactory.h>
16 #include <klocalizedstring.h>		/* i18n */
17 #include "mydebug.h"
18 
19 
20 
WinStack(QWidget * parent)21 WinStack::WinStack(QWidget* parent) :
22 	QTabWidget(parent),
23 	m_pcLine(-1),
24 	m_tabWidth(0)
25 {
26     setTabsClosable(true);
27     setMovable(true);
28 
29     connect(&m_findDlg.m_buttonForward,
30 	    SIGNAL(clicked()), SLOT(slotFindForward()));
31     connect(&m_findDlg.m_buttonBackward,
32 	    SIGNAL(clicked()), SLOT(slotFindBackward()));
33 
34     connect(this, SIGNAL(setTabWidth(int)), this, SLOT(slotSetTabWidth(int)));
35     connect(this, SIGNAL(tabCloseRequested(int)),
36 	    this, SLOT(slotCloseTab(int)));
37 }
38 
~WinStack()39 WinStack::~WinStack()
40 {
41 }
42 
contextMenuEvent(QContextMenuEvent * e)43 void WinStack::contextMenuEvent(QContextMenuEvent* e)
44 {
45     // get the context menu from the GUI factory
46     QWidget* top = this;
47     do
48 	top = top->parentWidget();
49     while (!top->isTopLevel());
50     KXmlGuiWindow* mw = static_cast<KXmlGuiWindow*>(top);
51     QMenu* m =
52 	static_cast<QMenu*>(mw->factory()->container("popup_files_empty", mw));
53     m->exec(e->globalPos());
54 }
55 
56 
reloadAllFiles()57 void WinStack::reloadAllFiles()
58 {
59     for (int i = count()-1; i >= 0; i--) {
60 	windowAt(i)->reloadFile();
61     }
62 }
63 
sizeHint() const64 QSize WinStack::sizeHint() const
65 {
66     return QSize(640, 480);
67 }
68 
activate(const QString & fileName,int lineNo,const DbgAddr & address)69 void WinStack::activate(const QString& fileName, int lineNo, const DbgAddr& address)
70 {
71     QFileInfo fi(fileName);
72 
73     if (!fi.isFile()) {
74 	/*
75 	 * We didn't find that file. Now check if it is a relative path and
76 	 * try m_lastOpenDir as prefix.
77 	 */
78 	TRACE(fi.filePath() + (" not found, looking in " + m_lastOpenDir));
79 	if (!fi.isRelative() || m_lastOpenDir.isEmpty()) {
80 	    return;
81 	}
82 	fi.setFile(m_lastOpenDir + "/" + fi.filePath());
83 	if (!fi.isFile()) {
84 	    return;
85 	}
86     }
87     // if this is not an absolute path name, make it one
88     activatePath(fi.absoluteFilePath(), lineNo, address);
89 }
90 
activateFile(const QString & fileName)91 void WinStack::activateFile(const QString& fileName)
92 {
93     activatePath(fileName, 0, DbgAddr());
94 }
95 
activatePath(QString pathName,int lineNo,const DbgAddr & address)96 bool WinStack::activatePath(QString pathName, int lineNo, const DbgAddr& address)
97 {
98     // check whether the file is already open
99     SourceWindow* fw = 0;
100     for (int i = count()-1; i >= 0; i--) {
101 	if (windowAt(i)->fileName() == pathName) {
102 	    fw = windowAt(i);
103 	    break;
104 	}
105     }
106     if (fw == 0) {
107 	// not found, load it
108 	fw = new SourceWindow(pathName, this);
109 
110 	// slurp the file in
111 	if (!fw->loadFile()) {
112 	    // read failed
113 	    delete fw;
114 	    return false;
115 	}
116 
117 	int idx = addTab(fw, QFileInfo(pathName).fileName());
118 	setTabToolTip(idx, pathName);
119 
120 	connect(fw, SIGNAL(clickedLeft(const QString&,int,const DbgAddr&,bool)),
121 		SIGNAL(toggleBreak(const QString&,int,const DbgAddr&,bool)));
122 	connect(fw, SIGNAL(clickedMid(const QString&,int,const DbgAddr&)),
123 		SIGNAL(enadisBreak(const QString&,int,const DbgAddr&)));
124 
125 	// disassemble code
126 	connect(fw, SIGNAL(disassemble(const QString&, int)),
127 		SIGNAL(disassemble(const QString&, int)));
128 	connect(fw, SIGNAL(expanded(int)), SLOT(slotExpandCollapse(int)));
129 	connect(fw, SIGNAL(collapsed(int)), SLOT(slotExpandCollapse(int)));
130 
131 	// tab width
132 	connect(this, SIGNAL(setTabWidth(int)), fw, SLOT(setTabWidth(int)));
133 	fw->setTabWidth(m_tabWidth);
134 	fw->setFocusPolicy(Qt::WheelFocus);
135 
136 	// set PC if there is one
137 	emit newFileLoaded();
138 	if (m_pcLine >= 0) {
139 	    setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
140 	}
141     }
142     return activateWindow(fw, lineNo, address);
143 }
144 
activateWindow(SourceWindow * fw,int lineNo,const DbgAddr & address)145 bool WinStack::activateWindow(SourceWindow* fw, int lineNo, const DbgAddr& address)
146 {
147     // make the line visible
148     if (lineNo >= 0) {
149 	fw->scrollTo(lineNo, address);
150     }
151 
152     setCurrentWidget(fw);
153     fw->setFocus();
154 
155     return true;
156 }
157 
activeLine(QString & fileName,int & lineNo)158 bool WinStack::activeLine(QString& fileName, int& lineNo)
159 {
160     DbgAddr dummy;
161     return activeLine(fileName, lineNo, dummy);
162 }
163 
activeLine(QString & fileName,int & lineNo,DbgAddr & address)164 bool WinStack::activeLine(QString& fileName, int& lineNo, DbgAddr& address)
165 {
166     if (activeWindow() == 0) {
167 	return false;
168     }
169 
170     fileName = activeFileName();
171     activeWindow()->activeLine(lineNo, address);
172     return true;
173 }
174 
updateLineItems(const KDebugger * dbg)175 void WinStack::updateLineItems(const KDebugger* dbg)
176 {
177     for (int i = count()-1; i >= 0; i--) {
178 	windowAt(i)->updateLineItems(dbg);
179     }
180 }
181 
updatePC(const QString & fileName,int lineNo,const DbgAddr & address,int frameNo)182 void WinStack::updatePC(const QString& fileName, int lineNo, const DbgAddr& address, int frameNo)
183 {
184     if (m_pcLine >= 0) {
185 	setPC(false, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
186     }
187     m_pcFile = fileName;
188     m_pcLine = lineNo;
189     m_pcAddress = address.asString();
190     m_pcFrame = frameNo;
191     if (lineNo >= 0) {
192 	setPC(true, fileName, lineNo, address, frameNo);
193     }
194 }
195 
findByFileName(const QString & fileName) const196 SourceWindow* WinStack::findByFileName(const QString& fileName) const
197 {
198     for (int i = count()-1; i >= 0; i--) {
199 	if (windowAt(i)->fileNameMatches(fileName)) {
200 	    return windowAt(i);
201 	}
202     }
203     return 0;
204 }
205 
setPC(bool set,const QString & fileName,int lineNo,const DbgAddr & address,int frameNo)206 void WinStack::setPC(bool set, const QString& fileName, int lineNo,
207 		     const DbgAddr& address, int frameNo)
208 {
209     TRACE((set ? "set PC: " : "clear PC: ") + fileName +
210 	  QString().sprintf(":%d#%d ", lineNo, frameNo) + address.asString());
211     SourceWindow* fw = findByFileName(fileName);
212     if (fw)
213 	fw->setPC(set, lineNo, address, frameNo);
214 }
215 
windowAt(int i) const216 SourceWindow* WinStack::windowAt(int i) const
217 {
218     return static_cast<SourceWindow*>(widget(i));
219 }
220 
activeWindow() const221 SourceWindow* WinStack::activeWindow() const
222 {
223     return static_cast<SourceWindow*>(currentWidget());
224 }
225 
activeFileName() const226 QString WinStack::activeFileName() const
227 {
228     QString f;
229     if (activeWindow() != 0)
230 	f = activeWindow()->fileName();
231     return f;
232 }
233 
slotFindForward()234 void WinStack::slotFindForward()
235 {
236     if (activeWindow() != 0)
237 	activeWindow()->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
238 			     SourceWindow::findForward);
239 }
240 
slotFindBackward()241 void WinStack::slotFindBackward()
242 {
243     if (activeWindow() != 0)
244 	activeWindow()->find(m_findDlg.searchText(), m_findDlg.caseSensitive(),
245 			     SourceWindow::findBackward);
246 }
247 
event(QEvent * evt)248 bool WinStack::event(QEvent* evt)
249 {
250     if (evt->type() != QEvent::ToolTip)
251 	return QTabWidget::event(evt);
252 
253     SourceWindow* w = activeWindow();
254     if (w == 0)
255 	return true;
256 
257     QPoint p = static_cast<QHelpEvent*>(evt)->globalPos();
258     // get the word at the point
259     QString word;
260     QRect r;
261     if (!w->wordAtPoint(w->mapFromGlobal(p), word, r)) {
262 	QToolTip::hideText();
263 	return true;
264     }
265 
266     // must be valid
267     assert(!word.isEmpty());
268     assert(r.isValid());
269 
270     // remember the location
271     m_tipLocation = p;
272     m_tipRegion = QRect(w->mapTo(this, r.topLeft()), r.size());
273 
274     emit initiateValuePopup(word);
275     return true;
276 }
277 
slotShowValueTip(const QString & tipText)278 void WinStack::slotShowValueTip(const QString& tipText)
279 {
280     QToolTip::showText(m_tipLocation, tipText, this, m_tipRegion);
281 }
282 
slotDisassembled(const QString & fileName,int lineNo,const std::list<DisassembledCode> & disass)283 void WinStack::slotDisassembled(const QString& fileName, int lineNo,
284 				const std::list<DisassembledCode>& disass)
285 {
286     SourceWindow* fw = findByFileName(fileName);
287     if (fw == 0) {
288 	// not found: ignore
289 	return;
290     }
291 
292     fw->disassembled(lineNo, disass);
293 }
294 
slotExpandCollapse(int)295 void WinStack::slotExpandCollapse(int)
296 {
297     // update line items after expanding or collapsing disassembled code
298 
299     // HACK: we know that this will result in updateLineItems
300     // should be done more cleanly with a separate signal
301     emit newFileLoaded();
302 
303     if (m_pcLine >= 0) {
304 	setPC(true, m_pcFile, m_pcLine, DbgAddr(m_pcAddress), m_pcFrame);
305     }
306 }
307 
308 
slotSetTabWidth(int numChars)309 void WinStack::slotSetTabWidth(int numChars)
310 {
311     m_tabWidth = numChars;
312 }
313 
slotFileReload()314 void WinStack::slotFileReload()
315 {
316     if (activeWindow() != 0) {
317 	TRACE("reloading one file");
318 	activeWindow()->reloadFile();
319     }
320 }
321 
slotViewFind()322 void WinStack::slotViewFind()
323 {
324     if (m_findDlg.isVisible()) {
325 	m_findDlg.done(0);
326     } else {
327 	m_findDlg.show();
328     }
329 }
330 
slotBrkptSet()331 void WinStack::slotBrkptSet()
332 {
333     QString file;
334     int lineNo;
335     DbgAddr address;
336     if (activeLine(file, lineNo, address))
337 	emit toggleBreak(file, lineNo, address, false);
338 }
339 
slotBrkptSetTemp()340 void WinStack::slotBrkptSetTemp()
341 {
342     QString file;
343     int lineNo;
344     DbgAddr address;
345     if (activeLine(file, lineNo, address))
346 	emit toggleBreak(file, lineNo, address, true);
347 }
348 
slotBrkptEnable()349 void WinStack::slotBrkptEnable()
350 {
351     QString file;
352     int lineNo;
353     DbgAddr address;
354     if (activeLine(file, lineNo, address))
355 	emit enadisBreak(file, lineNo, address);
356 }
357 
slotMoveProgramCounter()358 void WinStack::slotMoveProgramCounter()
359 {
360     QString file;
361     int lineNo;
362     DbgAddr address;
363     if (activeLine(file, lineNo, address))
364 	emit moveProgramCounter(file, lineNo, address);
365 }
366 
slotClose()367 void WinStack::slotClose()
368 {
369     slotCloseTab(currentIndex());
370 }
371 
slotCloseTab(int tab)372 void WinStack::slotCloseTab(int tab)
373 {
374     QWidget* w = widget(tab);
375     if (!w)
376 	return;
377 
378     removeTab(tab);
379     delete w;
380 }
381 
382 
FindDialog()383 FindDialog::FindDialog() :
384 	QDialog(),
385 	m_searchText(this),
386 	m_caseCheck(this),
387 	m_buttonForward(this),
388 	m_buttonBackward(this),
389 	m_buttonClose(this)
390 {
391     setWindowTitle(i18n("Search"));
392 
393     m_searchText.setMinimumSize(330, 24);
394     m_searchText.setMaxLength(10000);
395     m_searchText.setFrame(true);
396     m_searchText.setFocus();
397 
398     m_caseCheck.setText(i18n("&Case sensitive"));
399     m_caseCheck.setChecked(true);
400     m_buttonForward.setText(i18n("&Forward"));
401     m_buttonForward.setDefault(true);
402     m_buttonBackward.setText(i18n("&Backward"));
403     m_buttonClose.setText(i18n("Close"));
404 
405     connect(&m_buttonClose, SIGNAL(clicked()), SLOT(reject()));
406 
407     m_layout.addWidget(&m_searchText);
408     m_layout.addWidget(&m_caseCheck);
409     m_layout.addLayout(&m_buttons);
410 
411     m_buttons.addWidget(&m_buttonForward);
412     m_buttons.addWidget(&m_buttonBackward);
413     m_buttons.addWidget(&m_buttonClose);
414 
415     setLayout(&m_layout);
416 }
417 
~FindDialog()418 FindDialog::~FindDialog()
419 {
420 }
421 
closeEvent(QCloseEvent * ev)422 void FindDialog::closeEvent(QCloseEvent* ev)
423 {
424     QDialog::closeEvent(ev);
425     emit closed();
426 }
427 
done(int result)428 void FindDialog::done(int result)
429 {
430     QDialog::done(result);
431     emit closed();
432 }
433 
434 #include "winstack.moc"
435