forked from qt-creator/qt-creator
debugger: implement per-type format changes in the watch view
This commit is contained in:
@@ -479,6 +479,23 @@ QString niceType(QString type)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString formattedValue(const WatchData &data,
|
||||||
|
int individualFormat, int typeFormat)
|
||||||
|
{
|
||||||
|
if (data.type == "int") {
|
||||||
|
int format = individualFormat == -1 ? typeFormat : individualFormat;
|
||||||
|
int value = data.value.toInt();
|
||||||
|
if (format == 1)
|
||||||
|
return ("(hex) ") + QString::number(value, 16);
|
||||||
|
if (format == 2)
|
||||||
|
return ("(bin) ") + QString::number(value, 2);
|
||||||
|
if (format == 3)
|
||||||
|
return ("(oct) ") + QString::number(value, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.value;
|
||||||
|
}
|
||||||
|
|
||||||
bool WatchModel::canFetchMore(const QModelIndex &index) const
|
bool WatchModel::canFetchMore(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
return index.isValid() && !watchItem(index)->fetchTriggered;
|
return index.isValid() && !watchItem(index)->fetchTriggered;
|
||||||
@@ -573,6 +590,18 @@ QModelIndex WatchModel::watchIndexHelper(const WatchItem *needle,
|
|||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex)
|
||||||
|
{
|
||||||
|
QModelIndex idx1 = index(0, column, parentIndex);
|
||||||
|
QModelIndex idx2 = index(rowCount(parentIndex) - 1, column, parentIndex);
|
||||||
|
if (idx1.isValid() && idx2.isValid())
|
||||||
|
emit dataChanged(idx1, idx2);
|
||||||
|
//qDebug() << "CHANGING:\n" << idx1 << "\n" << idx2 << "\n"
|
||||||
|
// << data(parentIndex, INameRole).toString();
|
||||||
|
for (int i = rowCount(parentIndex); --i >= 0; )
|
||||||
|
emitDataChanged(column, index(i, 0, parentIndex));
|
||||||
|
}
|
||||||
|
|
||||||
QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
const WatchItem &data = *watchItem(idx);
|
const WatchItem &data = *watchItem(idx);
|
||||||
@@ -581,7 +610,9 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
switch (idx.column()) {
|
switch (idx.column()) {
|
||||||
case 0: return data.name;
|
case 0: return data.name;
|
||||||
case 1: return data.value;
|
case 1: return formattedValue(data,
|
||||||
|
m_handler->m_individualFormats[data.iname],
|
||||||
|
m_handler->m_typeFormats[data.type]);
|
||||||
case 2: return niceType(data.type);
|
case 2: return niceType(data.type);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -616,7 +647,23 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|||||||
case ActiveDataRole:
|
case ActiveDataRole:
|
||||||
qDebug() << "ASK FOR" << data.iname;
|
qDebug() << "ASK FOR" << data.iname;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case TypeFormatListRole:
|
||||||
|
if (data.type == "int")
|
||||||
|
return QStringList() << tr("decimal") << tr("hexadecimal")
|
||||||
|
<< tr("binary") << tr("octal");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypeFormatRole:
|
||||||
|
return m_handler->m_typeFormats[data.type];
|
||||||
|
|
||||||
|
case IndividualFormatRole: {
|
||||||
|
int format = m_handler->m_individualFormats[data.iname];
|
||||||
|
if (format == -1)
|
||||||
|
return m_handler->m_typeFormats[data.type];
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -625,12 +672,16 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|||||||
|
|
||||||
bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
|
WatchItem &data = *watchItem(index);
|
||||||
if (role == ExpandedRole) {
|
if (role == ExpandedRole) {
|
||||||
QString iname = data(index, INameRole).toString();
|
|
||||||
if (value.toBool())
|
if (value.toBool())
|
||||||
m_handler->m_expandedINames.insert(iname);
|
m_handler->m_expandedINames.insert(data.iname);
|
||||||
else
|
else
|
||||||
m_handler->m_expandedINames.remove(iname);
|
m_handler->m_expandedINames.remove(data.iname);
|
||||||
|
} else if (role == TypeFormatRole) {
|
||||||
|
m_handler->setFormat(data.type, value.toInt());
|
||||||
|
} else if (role == IndividualFormatRole) {
|
||||||
|
m_handler->m_individualFormats[data.iname] = value.toInt();
|
||||||
}
|
}
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
return true;
|
return true;
|
||||||
@@ -773,66 +824,6 @@ void WatchHandler::endCycle()
|
|||||||
m_locals->removeOutdated();
|
m_locals->removeOutdated();
|
||||||
m_watchers->removeOutdated();
|
m_watchers->removeOutdated();
|
||||||
m_tooltips->removeOutdated();
|
m_tooltips->removeOutdated();
|
||||||
|
|
||||||
/*
|
|
||||||
if (m_inChange) {
|
|
||||||
MODEL_DEBUG("RECREATE MODEL IGNORED, CURRENT SET:\n" << toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_PENDING
|
|
||||||
MODEL_DEBUG("RECREATE MODEL, CURRENT SET:\n" << toString());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QHash<QString, int> oldTopINames;
|
|
||||||
QHash<QString, QString> oldValues;
|
|
||||||
for (int i = 0, n = m_oldSet.size(); i != n; ++i) {
|
|
||||||
WatchData &data = m_oldSet[i];
|
|
||||||
oldValues[data.iname] = data.value;
|
|
||||||
if (data.level == 2)
|
|
||||||
++oldTopINames[data.iname];
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_PENDING
|
|
||||||
MODEL_DEBUG("OLD VALUES: " << oldValues);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int i = m_completeSet.size(); --i >= 0; ) {
|
|
||||||
WatchData &data = m_completeSet[i];
|
|
||||||
data.level = data.iname.isEmpty() ? 0 : data.iname.count('.') + 1;
|
|
||||||
data.childIndex.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
qSort(m_completeSet.begin(), m_completeSet.end(), &iNameSorter);
|
|
||||||
|
|
||||||
// Possibly append dummy items to prevent empty views
|
|
||||||
bool ok = true;
|
|
||||||
|
|
||||||
if (ok) {
|
|
||||||
for (int i = 1; i <= 3; ++i) {
|
|
||||||
WatchData &data = m_displaySet[i];
|
|
||||||
if (data.childIndex.size() == 0) {
|
|
||||||
WatchData dummy;
|
|
||||||
dummy.state = 0;
|
|
||||||
dummy.row = 0;
|
|
||||||
if (i == 1) {
|
|
||||||
dummy.iname = QLatin1String("local.dummy");
|
|
||||||
dummy.name = tr("<No Locals>");
|
|
||||||
} else if (i == 2) {
|
|
||||||
dummy.iname = QLatin1String("tooltip.dummy");
|
|
||||||
dummy.name = tr("<No Tooltip>");
|
|
||||||
} else {
|
|
||||||
dummy.iname = QLatin1String("watch.dummy");
|
|
||||||
dummy.name = tr("<No Watchers>");
|
|
||||||
}
|
|
||||||
dummy.level = 2;
|
|
||||||
dummy.parentIndex = i;
|
|
||||||
dummy.childCount = 0;
|
|
||||||
data.childIndex.append(m_displaySet.size());
|
|
||||||
m_displaySet.append(dummy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::cleanup()
|
void WatchHandler::cleanup()
|
||||||
@@ -1020,17 +1011,19 @@ void WatchHandler::loadWatchers()
|
|||||||
sessionValueRequested("Watchers", &value);
|
sessionValueRequested("Watchers", &value);
|
||||||
foreach (const QString &exp, value.toStringList())
|
foreach (const QString &exp, value.toStringList())
|
||||||
m_watcherNames[exp] = watcherCounter++;
|
m_watcherNames[exp] = watcherCounter++;
|
||||||
|
|
||||||
//qDebug() << "LOAD WATCHERS: " << m_watchers;
|
//qDebug() << "LOAD WATCHERS: " << m_watchers;
|
||||||
//reinitializeWatchersHelper();
|
//reinitializeWatchersHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::saveWatchers()
|
void WatchHandler::saveWatchers()
|
||||||
{
|
{
|
||||||
//qDebug() << "SAVE WATCHERS: " << m_watchers.keys();
|
//qDebug() << "SAVE WATCHERS: " << m_watchers;
|
||||||
// Filter out valid watchers.
|
// Filter out valid watchers.
|
||||||
QStringList watcherNames;
|
QStringList watcherNames;
|
||||||
const QHash<QString, int>::const_iterator cend = m_watcherNames.constEnd();
|
QHashIterator<QString, int> it(m_watcherNames);
|
||||||
for (QHash<QString, int>::const_iterator it = m_watcherNames.constBegin(); it != cend; ++it) {
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
const QString &watcherName = it.key();
|
const QString &watcherName = it.key();
|
||||||
if (!watcherName.isEmpty() && watcherName != watcherEditPlaceHolder())
|
if (!watcherName.isEmpty() && watcherName != watcherEditPlaceHolder())
|
||||||
watcherNames.push_back(watcherName);
|
watcherNames.push_back(watcherName);
|
||||||
@@ -1038,14 +1031,42 @@ void WatchHandler::saveWatchers()
|
|||||||
setSessionValueRequested("Watchers", QVariant(watcherNames));
|
setSessionValueRequested("Watchers", QVariant(watcherNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WatchHandler::loadTypeFormats()
|
||||||
|
{
|
||||||
|
QVariant value;
|
||||||
|
sessionValueRequested("DefaultFormats", &value);
|
||||||
|
QMap<QString, QVariant> typeFormats = value.toMap();
|
||||||
|
QMapIterator<QString, QVariant> it(typeFormats);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
if (!it.key().isEmpty())
|
||||||
|
m_typeFormats.insert(it.key(), it.value().toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchHandler::saveTypeFormats()
|
||||||
|
{
|
||||||
|
QMap<QString, QVariant> typeFormats;
|
||||||
|
QHashIterator<QString, int> it(m_typeFormats);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
QString key = it.key().trimmed();
|
||||||
|
if (!key.isEmpty())
|
||||||
|
typeFormats.insert(key, it.value());
|
||||||
|
}
|
||||||
|
setSessionValueRequested("DefaultFormats", QVariant(typeFormats));
|
||||||
|
}
|
||||||
|
|
||||||
void WatchHandler::saveSessionData()
|
void WatchHandler::saveSessionData()
|
||||||
{
|
{
|
||||||
saveWatchers();
|
saveWatchers();
|
||||||
|
saveTypeFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::loadSessionData()
|
void WatchHandler::loadSessionData()
|
||||||
{
|
{
|
||||||
loadWatchers();
|
loadWatchers();
|
||||||
|
loadTypeFormats();
|
||||||
foreach (const QString &exp, m_watcherNames.keys()) {
|
foreach (const QString &exp, m_watcherNames.keys()) {
|
||||||
WatchData data;
|
WatchData data;
|
||||||
data.iname = watcherName(exp);
|
data.iname = watcherName(exp);
|
||||||
@@ -1092,5 +1113,14 @@ QString WatchHandler::watcherEditPlaceHolder()
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WatchHandler::setFormat(const QString &type, int format)
|
||||||
|
{
|
||||||
|
m_typeFormats[type] = format;
|
||||||
|
saveTypeFormats();
|
||||||
|
m_locals->emitDataChanged(1);
|
||||||
|
m_watchers->emitDataChanged(1);
|
||||||
|
m_tooltips->emitDataChanged(1);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -139,8 +139,11 @@ enum WatchRoles
|
|||||||
{
|
{
|
||||||
INameRole = Qt::UserRole,
|
INameRole = Qt::UserRole,
|
||||||
ExpressionRole,
|
ExpressionRole,
|
||||||
ExpandedRole,
|
ExpandedRole, // used to communicate prefered expanded state to the view
|
||||||
ActiveDataRole, // used for tooltip
|
ActiveDataRole, // used for tooltip
|
||||||
|
TypeFormatListRole,
|
||||||
|
TypeFormatRole, // used to communicate alternative formats to the view
|
||||||
|
IndividualFormatRole
|
||||||
};
|
};
|
||||||
|
|
||||||
class WatchModel : public QAbstractItemModel
|
class WatchModel : public QAbstractItemModel
|
||||||
@@ -180,6 +183,9 @@ private:
|
|||||||
void removeItem(WatchItem *item);
|
void removeItem(WatchItem *item);
|
||||||
void setActiveData(const QString &data) { m_activeData = data; }
|
void setActiveData(const QString &data) { m_activeData = data; }
|
||||||
|
|
||||||
|
void emitDataChanged(int column,
|
||||||
|
const QModelIndex &parentIndex = QModelIndex());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WatchHandler *m_handler;
|
WatchHandler *m_handler;
|
||||||
WatchType m_type;
|
WatchType m_type;
|
||||||
@@ -234,6 +240,10 @@ private:
|
|||||||
void loadWatchers();
|
void loadWatchers();
|
||||||
void saveWatchers();
|
void saveWatchers();
|
||||||
|
|
||||||
|
void loadTypeFormats();
|
||||||
|
void saveTypeFormats();
|
||||||
|
void setFormat(const QString &type, int format);
|
||||||
|
|
||||||
bool m_expandPointers;
|
bool m_expandPointers;
|
||||||
bool m_inChange;
|
bool m_inChange;
|
||||||
|
|
||||||
@@ -242,6 +252,8 @@ private:
|
|||||||
|
|
||||||
QHash<QString, int> m_watcherNames;
|
QHash<QString, int> m_watcherNames;
|
||||||
QString watcherName(const QString &exp);
|
QString watcherName(const QString &exp);
|
||||||
|
QHash<QString, int> m_typeFormats;
|
||||||
|
QHash<QString, int> m_individualFormats;
|
||||||
|
|
||||||
void setDisplayedIName(const QString &iname, bool on);
|
void setDisplayedIName(const QString &iname, bool on);
|
||||||
QSet<QString> m_expandedINames; // those expanded in the treeview
|
QSet<QString> m_expandedINames; // those expanded in the treeview
|
||||||
|
|||||||
@@ -199,30 +199,65 @@ void WatchWindow::dropEvent(QDropEvent *ev)
|
|||||||
|
|
||||||
void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
|
void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
{
|
{
|
||||||
|
QModelIndex idx = indexAt(ev->pos());
|
||||||
|
QModelIndex mi0 = idx.sibling(idx.row(), 0);
|
||||||
|
QModelIndex mi1 = idx.sibling(idx.row(), 1);
|
||||||
|
QModelIndex mi2 = idx.sibling(idx.row(), 2);
|
||||||
|
QString exp = model()->data(mi0).toString();
|
||||||
|
QString type = model()->data(mi2).toString();
|
||||||
|
|
||||||
|
QStringList alternativeFormats =
|
||||||
|
model()->data(mi0, TypeFormatListRole).toStringList();
|
||||||
|
int typeFormat =
|
||||||
|
model()->data(mi0, TypeFormatRole).toInt();
|
||||||
|
int individualFormat =
|
||||||
|
model()->data(mi0, IndividualFormatRole).toInt();
|
||||||
|
|
||||||
|
QMenu typeFormatMenu(tr("Change format for type '%1'").arg(type));
|
||||||
|
QMenu individualFormatMenu(tr("Change format for expression '%1'").arg(exp));
|
||||||
|
QList<QAction *> typeFormatActions;
|
||||||
|
QList<QAction *> individualFormatActions;
|
||||||
|
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
||||||
|
const QString format = alternativeFormats.at(i);
|
||||||
|
QAction *act = new QAction(format, &typeFormatMenu);
|
||||||
|
act->setCheckable(true);
|
||||||
|
if (i == typeFormat)
|
||||||
|
act->setChecked(true);
|
||||||
|
typeFormatMenu.addAction(act);
|
||||||
|
typeFormatActions.append(act);
|
||||||
|
act = new QAction(format, &individualFormatMenu);
|
||||||
|
act->setCheckable(true);
|
||||||
|
if (i == individualFormat)
|
||||||
|
act->setChecked(true);
|
||||||
|
individualFormatMenu.addAction(act);
|
||||||
|
individualFormatActions.append(act);
|
||||||
|
}
|
||||||
|
//typeFormatMenu.setActive(!alternativeFormats.isEmpty());
|
||||||
|
//individualFormatMenu.setActive(!alternativeFormats.isEmpty());
|
||||||
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
|
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
|
||||||
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
|
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
|
||||||
|
|
||||||
act2->setCheckable(true);
|
act2->setCheckable(true);
|
||||||
act2->setChecked(m_alwaysResizeColumnsToContents);
|
act2->setChecked(m_alwaysResizeColumnsToContents);
|
||||||
|
|
||||||
menu.addAction(act1);
|
|
||||||
menu.addAction(act2);
|
|
||||||
|
|
||||||
QModelIndex idx = indexAt(ev->pos());
|
|
||||||
QModelIndex mi0 = idx.sibling(idx.row(), 0);
|
|
||||||
QString exp = model()->data(mi0).toString();
|
|
||||||
|
|
||||||
menu.addSeparator();
|
|
||||||
int type = (m_type == LocalsType) ? WatchExpression : RemoveWatchExpression;
|
|
||||||
menu.addAction(theDebuggerAction(type)->updatedAction(exp));
|
|
||||||
|
|
||||||
//QAction *act4 = theDebuggerAction(WatchExpressionInWindow);
|
//QAction *act4 = theDebuggerAction(WatchExpressionInWindow);
|
||||||
//menu.addAction(act4);
|
//menu.addAction(act4);
|
||||||
|
|
||||||
QAction *act3 = new QAction(tr("Insert new watch item"), &menu);
|
QAction *act3 = new QAction(tr("Insert new watch item"), &menu);
|
||||||
menu.addAction(act3);
|
|
||||||
QAction *act4 = new QAction(tr("Select widget to watch"), &menu);
|
QAction *act4 = new QAction(tr("Select widget to watch"), &menu);
|
||||||
|
|
||||||
|
menu.addAction(act1);
|
||||||
|
menu.addAction(act2);
|
||||||
|
menu.addSeparator();
|
||||||
|
int atype = (m_type == LocalsType) ? WatchExpression : RemoveWatchExpression;
|
||||||
|
menu.addAction(theDebuggerAction(atype)->updatedAction(exp));
|
||||||
|
|
||||||
|
menu.addAction(act3);
|
||||||
menu.addAction(act4);
|
menu.addAction(act4);
|
||||||
|
menu.addMenu(&typeFormatMenu);
|
||||||
|
menu.addMenu(&individualFormatMenu);
|
||||||
|
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
menu.addAction(theDebuggerAction(RecheckDebuggingHelpers));
|
menu.addAction(theDebuggerAction(RecheckDebuggingHelpers));
|
||||||
@@ -232,16 +267,23 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
|
|
||||||
QAction *act = menu.exec(ev->globalPos());
|
QAction *act = menu.exec(ev->globalPos());
|
||||||
|
|
||||||
if (act == act1)
|
if (act == act1) {
|
||||||
resizeColumnsToContents();
|
resizeColumnsToContents();
|
||||||
else if (act == act2)
|
} else if (act == act2) {
|
||||||
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
|
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
|
||||||
else if (act == act3)
|
} else if (act == act3) {
|
||||||
theDebuggerAction(WatchExpression)
|
theDebuggerAction(WatchExpression)
|
||||||
->trigger(WatchHandler::watcherEditPlaceHolder());
|
->trigger(WatchHandler::watcherEditPlaceHolder());
|
||||||
else if (act == act4) {
|
} else if (act == act4) {
|
||||||
grabMouse(Qt::CrossCursor);
|
grabMouse(Qt::CrossCursor);
|
||||||
m_grabbing = true;
|
m_grabbing = true;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
||||||
|
if (act == typeFormatActions.at(i))
|
||||||
|
model()->setData(mi1, i, TypeFormatRole);
|
||||||
|
else if (act == individualFormatActions.at(i))
|
||||||
|
model()->setData(mi1, i, IndividualFormatRole);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user