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