OSDN Git Service

d61dcd58b3e19e8f3a505e4d0d56914208b36023
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / watchwindow.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "watchwindow.h"
35
36 #include "breakhandler.h"
37 #include "debuggeractions.h"
38 #include "debuggerconstants.h"
39 #include "debuggercore.h"
40 #include "debuggerdialogs.h"
41 #include "debuggerengine.h"
42 #include "watchdelegatewidgets.h"
43 #include "watchhandler.h"
44 #include "debuggertooltipmanager.h"
45
46 #include <utils/qtcassert.h>
47 #include <utils/savedaction.h>
48
49 #include <QtCore/QDebug>
50 #include <QtCore/QMetaObject>
51 #include <QtCore/QMetaProperty>
52 #include <QtCore/QVariant>
53
54 #include <QtGui/QApplication>
55 #include <QtGui/QClipboard>
56 #include <QtGui/QContextMenuEvent>
57 #include <QtGui/QHeaderView>
58 #include <QtGui/QItemDelegate>
59 #include <QtGui/QMenu>
60 #include <QtGui/QPainter>
61 #include <QtGui/QResizeEvent>
62 #include <QtGui/QInputDialog>
63
64 /////////////////////////////////////////////////////////////////////
65 //
66 // WatchDelegate
67 //
68 /////////////////////////////////////////////////////////////////////
69
70 namespace Debugger {
71 namespace Internal {
72
73 static DebuggerEngine *currentEngine()
74 {
75     return debuggerCore()->currentEngine();
76 }
77
78 class WatchDelegate : public QItemDelegate
79 {
80 public:
81     explicit WatchDelegate(WatchWindow *parent)
82         : QItemDelegate(parent), m_watchWindow(parent)
83     {}
84
85     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
86         const QModelIndex &index) const
87     {
88         // Value column: Custom editor. Apply integer-specific settings.
89         if (index.column() == 1) {
90             const QVariant::Type type =
91                 static_cast<QVariant::Type>(index.data(LocalsEditTypeRole).toInt());
92             switch (type) {
93             case QVariant::Bool:
94                 return new BooleanComboBox(parent);
95             default:
96                 break;
97             }
98             WatchLineEdit *edit = WatchLineEdit::create(type, parent);
99             edit->setFrame(false);
100             IntegerWatchLineEdit *intEdit
101                 = qobject_cast<IntegerWatchLineEdit *>(edit);
102             if (intEdit)
103                 intEdit->setBase(index.data(LocalsIntegerBaseRole).toInt());
104             return edit;
105         }
106
107         // Standard line edits for the rest.
108         QLineEdit *lineEdit = new QLineEdit(parent);
109         lineEdit->setFrame(false);
110         return lineEdit;
111     }
112
113     void setModelData(QWidget *editor, QAbstractItemModel *model,
114                       const QModelIndex &index) const
115     {
116         // Standard handling for anything but the watcher name column (change
117         // expression), which removes/recreates a row, which cannot be done
118         // in model->setData().
119         if (index.column() != 0) {
120             QItemDelegate::setModelData(editor, model, index);
121             return;
122         }
123         const QMetaProperty userProperty = editor->metaObject()->userProperty();
124         QTC_ASSERT(userProperty.isValid(), return);
125         const QString value = editor->property(userProperty.name()).toString();
126         const QString exp = index.data(LocalsExpressionRole).toString();
127         if (exp == value)
128             return;
129         m_watchWindow->removeWatchExpression(exp);
130         m_watchWindow->watchExpression(value);
131     }
132
133     void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
134         const QModelIndex &) const
135     {
136         editor->setGeometry(option.rect);
137     }
138
139 private:
140     WatchWindow *m_watchWindow;
141 };
142
143 /////////////////////////////////////////////////////////////////////
144 //
145 // WatchWindow
146 //
147 /////////////////////////////////////////////////////////////////////
148
149 WatchWindow::WatchWindow(Type type, QWidget *parent)
150   : QTreeView(parent),
151     m_type(type)
152 {
153     m_grabbing = false;
154
155     setFrameStyle(QFrame::NoFrame);
156     setAttribute(Qt::WA_MacShowFocusRect, false);
157     setWindowTitle(tr("Locals and Watchers"));
158     setIndentation(indentation() * 9/10);
159     setUniformRowHeights(true);
160     setItemDelegate(new WatchDelegate(this));
161     setDragEnabled(true);
162     setAcceptDrops(true);
163     setDropIndicatorShown(true);
164
165     QAction *useColors = debuggerCore()->action(UseAlternatingRowColors);
166     setAlternatingRowColors(useColors->isChecked());
167
168     QAction *adjustColumns = debuggerCore()->action(AlwaysAdjustLocalsColumnWidths);
169
170     connect(useColors, SIGNAL(toggled(bool)),
171         SLOT(setAlternatingRowColorsHelper(bool)));
172     connect(adjustColumns, SIGNAL(triggered(bool)),
173         SLOT(setAlwaysResizeColumnsToContents(bool)));
174     connect(this, SIGNAL(expanded(QModelIndex)),
175         SLOT(expandNode(QModelIndex)));
176     connect(this, SIGNAL(collapsed(QModelIndex)),
177         SLOT(collapseNode(QModelIndex)));
178 }
179
180 void WatchWindow::expandNode(const QModelIndex &idx)
181 {
182     setModelData(LocalsExpandedRole, true, idx);
183 }
184
185 void WatchWindow::collapseNode(const QModelIndex &idx)
186 {
187     setModelData(LocalsExpandedRole, false, idx);
188 }
189
190 void WatchWindow::keyPressEvent(QKeyEvent *ev)
191 {
192     if (ev->key() == Qt::Key_Delete && m_type == WatchersType) {
193         QModelIndex idx = currentIndex();
194         QModelIndex idx1 = idx.sibling(idx.row(), 0);
195         QString exp = idx1.data(LocalsRawExpressionRole).toString();
196         removeWatchExpression(exp);
197     } else if (ev->key() == Qt::Key_Return
198             && ev->modifiers() == Qt::ControlModifier
199             && m_type == LocalsType) {
200         QModelIndex idx = currentIndex();
201         QModelIndex idx1 = idx.sibling(idx.row(), 0);
202         QString exp = model()->data(idx1).toString();
203         watchExpression(exp);
204     }
205     QTreeView::keyPressEvent(ev);
206 }
207
208 void WatchWindow::dragEnterEvent(QDragEnterEvent *ev)
209 {
210     //QTreeView::dragEnterEvent(ev);
211     if (ev->mimeData()->hasFormat("text/plain")) {
212         ev->setDropAction(Qt::CopyAction);
213         ev->accept();
214     }
215 }
216
217 void WatchWindow::dragMoveEvent(QDragMoveEvent *ev)
218 {
219     //QTreeView::dragMoveEvent(ev);
220     if (ev->mimeData()->hasFormat("text/plain")) {
221         ev->setDropAction(Qt::CopyAction);
222         ev->accept();
223     }
224 }
225
226 void WatchWindow::dropEvent(QDropEvent *ev)
227 {
228     if (ev->mimeData()->hasFormat("text/plain")) {
229         watchExpression(ev->mimeData()->text());
230         //ev->acceptProposedAction();
231         ev->setDropAction(Qt::CopyAction);
232         ev->accept();
233     }
234     //QTreeView::dropEvent(ev);
235 }
236
237 void WatchWindow::mouseDoubleClickEvent(QMouseEvent *ev)
238 {
239     const QModelIndex idx = indexAt(ev->pos());
240     if (!idx.isValid()) {
241         // The "<Edit>" case.
242         watchExpression(QString());
243         return;
244     }
245     QTreeView::mouseDoubleClickEvent(ev);
246 }
247
248 // Text for add watch action with truncated expression
249 static inline QString addWatchActionText(QString exp)
250 {
251     if (exp.isEmpty())
252         return WatchWindow::tr("Watch Expression");
253     if (exp.size() > 30) {
254         exp.truncate(30);
255         exp.append(QLatin1String("..."));
256     }
257     return WatchWindow::tr("Watch Expression \"%1\"").arg(exp);
258 }
259
260 // Text for add watch action with truncated expression
261 static inline QString removeWatchActionText(QString exp)
262 {
263     if (exp.isEmpty())
264         return WatchWindow::tr("Remove Watch Expression");
265     if (exp.size() > 30) {
266         exp.truncate(30);
267         exp.append(QLatin1String("..."));
268     }
269     return WatchWindow::tr("Remove Watch Expression \"%1\"").arg(exp);
270 }
271
272 void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
273 {
274     DebuggerEngine *engine = currentEngine();
275     WatchHandler *handler = engine->watchHandler();
276
277     const QModelIndex idx = indexAt(ev->pos());
278     const QModelIndex mi0 = idx.sibling(idx.row(), 0);
279     const QModelIndex mi1 = idx.sibling(idx.row(), 1);
280     const QModelIndex mi2 = idx.sibling(idx.row(), 2);
281     const quint64 address = mi0.data(LocalsAddressRole).toULongLong();
282     const quint64 pointerValue = mi0.data(LocalsPointerValueRole).toULongLong();
283     const QString exp = mi0.data(LocalsExpressionRole).toString();
284     const QString type = mi2.data().toString();
285
286     const QStringList alternativeFormats =
287         mi0.data(LocalsTypeFormatListRole).toStringList();
288     const int typeFormat =
289         mi0.data(LocalsTypeFormatRole).toInt();
290     const int individualFormat =
291         mi0.data(LocalsIndividualFormatRole).toInt();
292     const int effectiveIndividualFormat =
293         individualFormat == -1 ? typeFormat : individualFormat;
294     const int unprintableBase = handler->unprintableBase();
295
296     QMenu formatMenu;
297     QList<QAction *> typeFormatActions;
298     QList<QAction *> individualFormatActions;
299     QAction *clearTypeFormatAction = 0;
300     QAction *clearIndividualFormatAction = 0;
301     QAction *showUnprintableUnicode = 0;
302     QAction *showUnprintableOctal = 0;
303     QAction *showUnprintableHexadecimal = 0;
304     formatMenu.setTitle(tr("Change Display Format..."));
305     showUnprintableUnicode =
306         formatMenu.addAction(tr("Treat All Characters as Printable"));
307     showUnprintableUnicode->setCheckable(true);
308     showUnprintableUnicode->setChecked(unprintableBase == 0);
309     showUnprintableOctal =
310         formatMenu.addAction(tr("Show Unprintable Characters as Octal"));
311     showUnprintableOctal->setCheckable(true);
312     showUnprintableOctal->setChecked(unprintableBase == 8);
313     showUnprintableHexadecimal =
314         formatMenu.addAction(tr("Show Unprintable Characters as Hexadecimal"));
315     showUnprintableHexadecimal->setCheckable(true);
316     showUnprintableHexadecimal->setChecked(unprintableBase == 16);
317     if (idx.isValid() /*&& !alternativeFormats.isEmpty() */) {
318         const QString spacer = QLatin1String("     ");
319         formatMenu.addSeparator();
320         QAction *dummy = formatMenu.addAction(
321             tr("Change Display for Type \"%1\":").arg(type));
322         dummy->setEnabled(false);
323         clearTypeFormatAction = formatMenu.addAction(spacer + tr("Automatic"));
324         //clearTypeFormatAction->setEnabled(typeFormat != -1);
325         //clearTypeFormatAction->setEnabled(individualFormat != -1);
326         clearTypeFormatAction->setCheckable(true);
327         clearTypeFormatAction->setChecked(typeFormat == -1);
328         for (int i = 0; i != alternativeFormats.size(); ++i) {
329             const QString format = spacer + alternativeFormats.at(i);
330             QAction *act = new QAction(format, &formatMenu);
331             act->setCheckable(true);
332             //act->setEnabled(individualFormat != -1);
333             if (i == typeFormat)
334                 act->setChecked(true);
335             formatMenu.addAction(act);
336             typeFormatActions.append(act);
337         }
338         formatMenu.addSeparator();
339         dummy = formatMenu.addAction(
340             tr("Change Display for Object Named \"%1\":").arg(mi0.data().toString()));
341         dummy->setEnabled(false);
342         clearIndividualFormatAction
343             = formatMenu.addAction(spacer + tr("Use Display Format Based on Type"));
344         //clearIndividualFormatAction->setEnabled(individualFormat != -1);
345         clearIndividualFormatAction->setCheckable(true);
346         clearIndividualFormatAction->setChecked(effectiveIndividualFormat == -1);
347         for (int i = 0; i != alternativeFormats.size(); ++i) {
348             const QString format = spacer + alternativeFormats.at(i);
349             QAction *act = new QAction(format, &formatMenu);
350             act->setCheckable(true);
351             if (i == effectiveIndividualFormat)
352                 act->setChecked(true);
353             formatMenu.addAction(act);
354             individualFormatActions.append(act);
355         }
356     } else {
357         QAction *dummy = formatMenu.addAction(
358             tr("Change Display for Type or Item..."));
359         dummy->setEnabled(false);
360     }
361
362     const bool actionsEnabled = engine->debuggerActionsEnabled();
363     const unsigned engineCapabilities = engine->debuggerCapabilities();
364     const bool canHandleWatches = engineCapabilities & AddWatcherCapability;
365     const DebuggerState state = engine->state();
366     const bool canInsertWatches = (state==InferiorStopOk) || ((state==InferiorRunOk) && engine->acceptsWatchesWhileRunning());
367
368     QMenu menu;
369     QAction *actInsertNewWatchItem = menu.addAction(tr("Insert New Watch Item"));
370     actInsertNewWatchItem->setEnabled(canHandleWatches && canInsertWatches);
371     QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch"));
372     actSelectWidgetToWatch->setEnabled(canHandleWatches && (engine->canWatchWidgets()));
373
374     // Offer to open address pointed to or variable address.
375     const bool createPointerActions = pointerValue && pointerValue != address;
376
377     menu.addSeparator();
378
379     QAction *actSetWatchpointAtVariableAddress = 0;
380     QAction *actSetWatchpointAtPointerValue = 0;
381     const bool canSetWatchpoint = engineCapabilities & WatchpointCapability;
382     if (canSetWatchpoint && address) {
383         actSetWatchpointAtVariableAddress =
384             new QAction(tr("Add Watchpoint at Object's Address (0x%1)")
385                 .arg(address, 0, 16), &menu);
386         actSetWatchpointAtVariableAddress->
387             setChecked(mi0.data(LocalsIsWatchpointAtAddressRole).toBool());
388         if (createPointerActions) {
389             actSetWatchpointAtPointerValue =
390                 new QAction(tr("Add Watchpoint at Referenced Address (0x%1)")
391                     .arg(pointerValue, 0, 16), &menu);
392             actSetWatchpointAtPointerValue->setCheckable(true);
393             actSetWatchpointAtPointerValue->
394                 setChecked(mi0.data(LocalsIsWatchpointAtPointerValueRole).toBool());
395         }
396     } else {
397         actSetWatchpointAtVariableAddress =
398             new QAction(tr("Add Watchpoint"), &menu);
399         actSetWatchpointAtVariableAddress->setEnabled(false);
400     }
401     actSetWatchpointAtVariableAddress->setToolTip(
402         tr("Setting a watchpoint on an address will cause the program "
403            "to stop when the data at the address it modified."));
404
405     QAction *actWatchExpression = new QAction(addWatchActionText(exp), &menu);
406     actWatchExpression->setEnabled(canHandleWatches && !exp.isEmpty());
407
408     // Can remove watch if engine can handle it or session engine.
409     QAction *actRemoveWatchExpression = new QAction(removeWatchActionText(exp), &menu);
410     actRemoveWatchExpression->setEnabled(
411         (canHandleWatches || state == DebuggerNotReady) && !exp.isEmpty());
412     QAction *actRemoveWatches = new QAction(tr("Remove All Watch Items"), &menu);
413     actRemoveWatches->setEnabled(!WatchHandler::watcherNames().isEmpty());
414
415     if (m_type == LocalsType)
416         menu.addAction(actWatchExpression);
417     else {
418         menu.addAction(actRemoveWatchExpression);
419         menu.addAction(actRemoveWatches);
420     }
421
422     QMenu memoryMenu;
423     memoryMenu.setTitle(tr("Open Memory Editor..."));
424     QAction *actOpenMemoryEditAtVariableAddress = new QAction(&memoryMenu);
425     QAction *actOpenMemoryEditAtPointerValue = new QAction(&memoryMenu);
426     QAction *actOpenMemoryEditor = new QAction(&memoryMenu);
427     if (engineCapabilities & ShowMemoryCapability) {
428         actOpenMemoryEditor->setText(tr("Open Memory Editor..."));
429         if (address) {
430             actOpenMemoryEditAtVariableAddress->setText(
431                 tr("Open Memory Editor at Object's Address (0x%1)")
432                     .arg(address, 0, 16));
433         } else {
434             actOpenMemoryEditAtVariableAddress->setText(
435                 tr("Open Memory Editor at Object's Address"));
436             actOpenMemoryEditAtVariableAddress->setEnabled(false);
437         }
438         if (createPointerActions) {
439             actOpenMemoryEditAtPointerValue->setText(
440                 tr("Open Memory Editor at Referenced Address (0x%1)")
441                     .arg(pointerValue, 0, 16));
442         } else {
443             actOpenMemoryEditAtPointerValue->setText(
444                 tr("Open Memory Editor at Referenced Address"));
445             actOpenMemoryEditAtPointerValue->setEnabled(false);
446         }
447         memoryMenu.addAction(actOpenMemoryEditAtVariableAddress);
448         memoryMenu.addAction(actOpenMemoryEditAtPointerValue);
449         memoryMenu.addAction(actOpenMemoryEditor);
450     } else {
451         memoryMenu.setEnabled(false);
452     }
453
454     QAction *actCopy = new QAction(tr("Copy Contents to Clipboard"), &menu);
455
456     menu.addAction(actInsertNewWatchItem);
457     menu.addAction(actSelectWidgetToWatch);
458     menu.addMenu(&formatMenu);
459     menu.addMenu(&memoryMenu);
460     menu.addAction(actSetWatchpointAtVariableAddress);
461     if (actSetWatchpointAtPointerValue)
462         menu.addAction(actSetWatchpointAtPointerValue);
463     menu.addAction(actCopy );
464     menu.addSeparator();
465
466     menu.addAction(debuggerCore()->action(UseDebuggingHelpers));
467     menu.addAction(debuggerCore()->action(UseToolTipsInLocalsView));
468     menu.addAction(debuggerCore()->action(AutoDerefPointers));
469     menu.addAction(debuggerCore()->action(ShowStdNamespace));
470     menu.addAction(debuggerCore()->action(ShowQtNamespace));
471     menu.addAction(debuggerCore()->action(SortStructMembers));
472
473     QAction *actAdjustColumnWidths =
474         menu.addAction(tr("Adjust Column Widths to Contents"));
475     menu.addAction(debuggerCore()->action(AlwaysAdjustLocalsColumnWidths));
476     menu.addSeparator();
477
478     QAction *actClearCodeModelSnapshot
479         = new QAction(tr("Refresh Code Model Snapshot"), &menu);
480     actClearCodeModelSnapshot->setEnabled(actionsEnabled
481         && debuggerCore()->action(UseCodeModel)->isChecked());
482     menu.addAction(actClearCodeModelSnapshot);
483     QAction *actShowInEditor
484         = new QAction(tr("Show View Contents in Editor"), &menu);
485     actShowInEditor->setEnabled(actionsEnabled);
486     menu.addAction(actShowInEditor);
487     menu.addAction(debuggerCore()->action(SettingsDialog));
488
489     QAction *actCloseEditorToolTips = new QAction(tr("Close Editor Tooltips"), &menu);
490     actCloseEditorToolTips->setEnabled(DebuggerToolTipManager::instance()->hasToolTips());
491     menu.addAction(actCloseEditorToolTips);
492
493     QAction *act = menu.exec(ev->globalPos());
494     if (act == 0)
495         return;
496
497     if (act == actAdjustColumnWidths) {
498         resizeColumnsToContents();
499     } else if (act == actInsertNewWatchItem) {
500         bool ok;
501         QString newExp = QInputDialog::getText(this, tr("Enter watch expression"),
502                                    tr("Expression:"), QLineEdit::Normal,
503                                    QString(), &ok);
504         if (ok && !newExp.isEmpty()) {
505             watchExpression(newExp);
506         }
507     } else if (act == actOpenMemoryEditAtVariableAddress) {
508         currentEngine()->openMemoryView(address);
509     } else if (act == actOpenMemoryEditAtPointerValue) {
510         currentEngine()->openMemoryView(pointerValue);
511     } else if (act == actOpenMemoryEditor) {
512         AddressDialog dialog;
513         if (dialog.exec() == QDialog::Accepted)
514             currentEngine()->openMemoryView(dialog.address());
515     } else if (act == actSetWatchpointAtVariableAddress) {
516         setWatchpoint(address);
517     } else if (act == actSetWatchpointAtPointerValue) {
518         setWatchpoint(pointerValue);
519     } else if (act == actSelectWidgetToWatch) {
520         grabMouse(Qt::CrossCursor);
521         m_grabbing = true;
522     } else if (act == actWatchExpression) {
523         watchExpression(exp);
524     } else if (act == actRemoveWatchExpression) {
525         removeWatchExpression(exp);
526     } else if (act == actCopy ) {
527         const QString clipboardText = DebuggerTreeViewToolTipWidget::treeModelClipboardContents(model());
528         QClipboard *clipboard = QApplication::clipboard();
529 #ifdef Q_WS_X11
530         clipboard->setText(clipboardText, QClipboard::Selection);
531 #endif
532         clipboard->setText(clipboardText, QClipboard::Clipboard);
533     } else if (act == actRemoveWatches) {
534         currentEngine()->watchHandler()->clearWatches();
535     } else if (act == actClearCodeModelSnapshot) {
536         debuggerCore()->clearCppCodeModelSnapshot();
537     } else if (act == clearTypeFormatAction) {
538         setModelData(LocalsTypeFormatRole, -1, mi1);
539     } else if (act == clearIndividualFormatAction) {
540         setModelData(LocalsIndividualFormatRole, -1, mi1);
541     } else if (act == actShowInEditor) {
542         QString contents = handler->editorContents();
543         debuggerCore()->openTextEditor(tr("Locals & Watchers"), contents);
544     } else if (act == showUnprintableUnicode) {
545         handler->setUnprintableBase(0);
546     } else if (act == showUnprintableOctal) {
547         handler->setUnprintableBase(8);
548     } else if (act == showUnprintableHexadecimal) {
549         handler->setUnprintableBase(16);
550     } else if (act == actCloseEditorToolTips) {
551         DebuggerToolTipManager::instance()->closeAllToolTips();
552     } else {
553         for (int i = 0; i != typeFormatActions.size(); ++i) {
554             if (act == typeFormatActions.at(i))
555                 setModelData(LocalsTypeFormatRole, i, mi1);
556         }
557         for (int i = 0; i != individualFormatActions.size(); ++i) {
558             if (act == individualFormatActions.at(i))
559                 setModelData(LocalsIndividualFormatRole, i, mi1);
560         }
561     }
562 }
563
564 void WatchWindow::resizeColumnsToContents()
565 {
566     resizeColumnToContents(0);
567     resizeColumnToContents(1);
568 }
569
570 void WatchWindow::setAlwaysResizeColumnsToContents(bool on)
571 {
572     if (!header())
573         return;
574     QHeaderView::ResizeMode mode = on
575         ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
576     header()->setResizeMode(0, mode);
577     header()->setResizeMode(1, mode);
578 }
579
580 bool WatchWindow::event(QEvent *ev)
581 {
582     if (m_grabbing && ev->type() == QEvent::MouseButtonPress) {
583         QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
584         m_grabbing = false;
585         releaseMouse();
586         currentEngine()->watchPoint(mapToGlobal(mev->pos()));
587     }
588     return QTreeView::event(ev);
589 }
590
591 void WatchWindow::editItem(const QModelIndex &idx)
592 {
593     Q_UNUSED(idx) // FIXME
594 }
595
596 void WatchWindow::setModel(QAbstractItemModel *model)
597 {
598     QTreeView::setModel(model);
599
600     setRootIsDecorated(true);
601     if (header()) {
602         setAlwaysResizeColumnsToContents(
603             debuggerCore()->boolSetting(AlwaysAdjustLocalsColumnWidths));
604         header()->setDefaultAlignment(Qt::AlignLeft);
605         if (m_type != LocalsType)
606             header()->hide();
607     }
608
609     connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
610     connect(model, SIGNAL(enableUpdates(bool)), SLOT(setUpdatesEnabled(bool)));
611     // Potentially left in disabled state in case engine crashes when expanding.
612     setUpdatesEnabled(true);
613 }
614
615 void WatchWindow::setUpdatesEnabled(bool enable)
616 {
617     //qDebug() << "ENABLING UPDATES: " << enable;
618     QTreeView::setUpdatesEnabled(enable);
619 }
620
621 void WatchWindow::resetHelper()
622 {
623     bool old = updatesEnabled();
624     setUpdatesEnabled(false);
625     resetHelper(model()->index(0, 0));
626     setUpdatesEnabled(old);
627 }
628
629 void WatchWindow::resetHelper(const QModelIndex &idx)
630 {
631     if (idx.data(LocalsExpandedRole).toBool()) {
632         //qDebug() << "EXPANDING " << model()->data(idx, INameRole);
633         if (!isExpanded(idx)) {
634             expand(idx);
635             for (int i = 0, n = model()->rowCount(idx); i != n; ++i) {
636                 QModelIndex idx1 = model()->index(i, 0, idx);
637                 resetHelper(idx1);
638             }
639         }
640     } else {
641         //qDebug() << "COLLAPSING " << model()->data(idx, INameRole);
642         if (isExpanded(idx))
643             collapse(idx);
644     }
645 }
646
647 void WatchWindow::watchExpression(const QString &exp)
648 {
649     currentEngine()->watchHandler()->watchExpression(exp);
650 }
651
652 void WatchWindow::removeWatchExpression(const QString &exp)
653 {
654     currentEngine()->watchHandler()->removeWatchExpression(exp);
655 }
656
657 void WatchWindow::setModelData
658     (int role, const QVariant &value, const QModelIndex &index)
659 {
660     QTC_ASSERT(model(), return);
661     model()->setData(index, value, role);
662 }
663
664 void WatchWindow::setWatchpoint(quint64 address)
665 {
666     BreakpointParameters data(Watchpoint);
667     data.address = address;
668     BreakpointId id = breakHandler()->findWatchpoint(data);
669     if (id) {
670         qDebug() << "WATCHPOINT EXISTS";
671         //   removeBreakpoint(index);
672         return;
673     }
674     breakHandler()->appendBreakpoint(data);
675 }
676
677 } // namespace Internal
678 } // namespace Debugger
679