forked from qt-creator/qt-creator
debugger: support for per-thread breakpoints
This commit is contained in:
@@ -14,32 +14,65 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="labelFileName">
|
||||||
|
<property name="text">
|
||||||
|
<string>File name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEditFileName"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="labelLineNumber">
|
||||||
|
<property name="text">
|
||||||
|
<string>Line number:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEditLineNumber"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="labelFunction">
|
||||||
|
<property name="text">
|
||||||
|
<string>Function:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEditFunction"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="labelCondition">
|
<widget class="QLabel" name="labelCondition">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Condition:</string>
|
<string>Condition:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="lineEditCondition"/>
|
<widget class="QLineEdit" name="lineEditCondition"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="labelIgnoreCount">
|
<widget class="QLabel" name="labelIgnoreCount">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ignore count:</string>
|
<string>Ignore count:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QSpinBox" name="spinBoxIgnoreCount">
|
<widget class="QLineEdit" name="lineEditIgnoreCount"/>
|
||||||
<property name="layoutDirection">
|
</item>
|
||||||
<enum>Qt::LeftToRight</enum>
|
<item row="5" column="0">
|
||||||
</property>
|
<widget class="QLabel" name="labelThreadSpec">
|
||||||
<property name="maximum">
|
<property name="text">
|
||||||
<number>999999999</number>
|
<string>Thread specification:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEditThreadSpec"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -247,6 +247,8 @@ QString BreakpointData::toToolTip() const
|
|||||||
<< "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
|
<< "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
|
||||||
<< "<tr><td>" << BreakHandler::tr("Ignore Count:")
|
<< "<tr><td>" << BreakHandler::tr("Ignore Count:")
|
||||||
<< "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
|
<< "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
|
||||||
|
<< "<tr><td>" << BreakHandler::tr("Thread Specification:")
|
||||||
|
<< "</td><td>" << threadSpec << "</td><td>" << bpThreadSpec << "</td></tr>"
|
||||||
<< "</table></body></html>";
|
<< "</table></body></html>";
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -268,7 +270,9 @@ QString BreakpointData::toString() const
|
|||||||
<< BreakHandler::tr("Condition:")
|
<< BreakHandler::tr("Condition:")
|
||||||
<< condition << " -- " << bpCondition << '\n'
|
<< condition << " -- " << bpCondition << '\n'
|
||||||
<< BreakHandler::tr("Ignore Count:")
|
<< BreakHandler::tr("Ignore Count:")
|
||||||
<< ignoreCount << " -- " << bpIgnoreCount << '\n';
|
<< ignoreCount << " -- " << bpIgnoreCount << '\n'
|
||||||
|
<< BreakHandler::tr("Thread Specification:")
|
||||||
|
<< threadSpec << " -- " << bpThreadSpec << '\n';
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +324,7 @@ BreakHandler::~BreakHandler()
|
|||||||
|
|
||||||
int BreakHandler::columnCount(const QModelIndex &parent) const
|
int BreakHandler::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 7;
|
return parent.isValid() ? 0 : 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BreakHandler::rowCount(const QModelIndex &parent) const
|
int BreakHandler::rowCount(const QModelIndex &parent) const
|
||||||
@@ -418,6 +422,8 @@ void BreakHandler::saveBreakpoints()
|
|||||||
map.insert(QLatin1String("condition"), data->condition);
|
map.insert(QLatin1String("condition"), data->condition);
|
||||||
if (!data->ignoreCount.isEmpty())
|
if (!data->ignoreCount.isEmpty())
|
||||||
map.insert(QLatin1String("ignorecount"), data->ignoreCount);
|
map.insert(QLatin1String("ignorecount"), data->ignoreCount);
|
||||||
|
if (!data->threadSpec.isEmpty())
|
||||||
|
map.insert(QLatin1String("threadspec"), data->threadSpec);
|
||||||
if (!data->enabled)
|
if (!data->enabled)
|
||||||
map.insert(QLatin1String("disabled"), QLatin1String("1"));
|
map.insert(QLatin1String("disabled"), QLatin1String("1"));
|
||||||
if (data->useFullPath)
|
if (data->useFullPath)
|
||||||
@@ -447,6 +453,9 @@ void BreakHandler::loadBreakpoints()
|
|||||||
v = map.value(QLatin1String("ignorecount"));
|
v = map.value(QLatin1String("ignorecount"));
|
||||||
if (v.isValid())
|
if (v.isValid())
|
||||||
data->ignoreCount = v.toString().toLatin1();
|
data->ignoreCount = v.toString().toLatin1();
|
||||||
|
v = map.value(QLatin1String("threadspec"));
|
||||||
|
if (v.isValid())
|
||||||
|
data->threadSpec = v.toString().toLatin1();
|
||||||
v = map.value(QLatin1String("funcname"));
|
v = map.value(QLatin1String("funcname"));
|
||||||
if (v.isValid())
|
if (v.isValid())
|
||||||
data->funcName = v.toString();
|
data->funcName = v.toString();
|
||||||
@@ -476,6 +485,7 @@ void BreakHandler::resetBreakpoints()
|
|||||||
data->bpCorrectedLineNumber.clear();
|
data->bpCorrectedLineNumber.clear();
|
||||||
data->bpCondition.clear();
|
data->bpCondition.clear();
|
||||||
data->bpIgnoreCount.clear();
|
data->bpIgnoreCount.clear();
|
||||||
|
data->bpThreadSpec.clear();
|
||||||
data->bpAddress.clear();
|
data->bpAddress.clear();
|
||||||
// Keep marker data if it was primary.
|
// Keep marker data if it was primary.
|
||||||
if (data->markerFileName() != data->fileName)
|
if (data->markerFileName() != data->fileName)
|
||||||
@@ -502,7 +512,7 @@ QVariant BreakHandler::headerData(int section,
|
|||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||||
static QString headers[] = {
|
static QString headers[] = {
|
||||||
tr("Number"), tr("Function"), tr("File"), tr("Line"),
|
tr("Number"), tr("Function"), tr("File"), tr("Line"),
|
||||||
tr("Condition"), tr("Ignore"), tr("Address")
|
tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
|
||||||
};
|
};
|
||||||
return headers[section];
|
return headers[section];
|
||||||
}
|
}
|
||||||
@@ -538,6 +548,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|||||||
const QString str = data->pending ? data->funcName : data->bpFuncName;
|
const QString str = data->pending ? data->funcName : data->bpFuncName;
|
||||||
return str.isEmpty() ? empty : str;
|
return str.isEmpty() ? empty : str;
|
||||||
}
|
}
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->funcName;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
@@ -553,6 +565,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|||||||
}
|
}
|
||||||
if (role == Qt::UserRole)
|
if (role == Qt::UserRole)
|
||||||
return data->useFullPath;
|
return data->useFullPath;
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->fileName;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
@@ -562,19 +576,36 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|||||||
const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
|
const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
|
||||||
return str.isEmpty() ? empty : str;
|
return str.isEmpty() ? empty : str;
|
||||||
}
|
}
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->lineNumber;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
return data->pending ? data->condition : data->bpCondition;
|
return data->pending ? data->condition : data->bpCondition;
|
||||||
if (role == Qt::ToolTipRole)
|
if (role == Qt::ToolTipRole)
|
||||||
return tr("Breakpoint will only be hit if this condition is met.");
|
return tr("Breakpoint will only be hit if this condition is met.");
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->condition;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
return data->pending ? data->ignoreCount : data->bpIgnoreCount;
|
return data->pending ? data->ignoreCount : data->bpIgnoreCount;
|
||||||
if (role == Qt::ToolTipRole)
|
if (role == Qt::ToolTipRole)
|
||||||
return tr("Breakpoint will only be hit after being ignored so many times.");
|
return tr("Breakpoint will only be hit after being ignored so many times.");
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->ignoreCount;
|
||||||
case 6:
|
case 6:
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
if (data->pending)
|
||||||
|
return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
|
||||||
|
else
|
||||||
|
return !data->bpThreadSpec.isEmpty() ? data->bpThreadSpec : tr("(all)");
|
||||||
|
}
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return tr("Breakpoint will only be hit in the specified thread(s).");
|
||||||
|
if (role == Qt::UserRole + 1)
|
||||||
|
return data->threadSpec;
|
||||||
|
case 7:
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
return data->bpAddress;
|
return data->bpAddress;
|
||||||
break;
|
break;
|
||||||
@@ -597,38 +628,73 @@ Qt::ItemFlags BreakHandler::flags(const QModelIndex &mi) const
|
|||||||
|
|
||||||
bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
|
bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
if (role != Qt::EditRole)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BreakpointData *data = at(mi.row());
|
BreakpointData *data = at(mi.row());
|
||||||
switch (mi.column()) {
|
|
||||||
case 0: {
|
if (role == Qt::UserRole + 1) {
|
||||||
if (data->enabled != value.toBool()) {
|
if (data->enabled != value.toBool()) {
|
||||||
toggleBreakpointEnabled(data);
|
toggleBreakpointEnabled(data);
|
||||||
dataChanged(mi, mi);
|
layoutChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == Qt::UserRole + 2) {
|
||||||
|
if (data->useFullPath != value.toBool()) {
|
||||||
|
data->useFullPath = value.toBool();
|
||||||
|
layoutChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (role != Qt::EditRole)
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
switch (mi.column()) {
|
||||||
|
case 1: {
|
||||||
|
QString val = value.toString();
|
||||||
|
if (data->funcName != val) {
|
||||||
|
data->funcName = val;
|
||||||
|
layoutChanged();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
if (data->useFullPath != value.toBool()) {
|
QString val = value.toString();
|
||||||
data->useFullPath = value.toBool();
|
if (data->fileName != val) {
|
||||||
dataChanged(mi, mi);
|
data->fileName = val;
|
||||||
|
layoutChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
QByteArray val = value.toString().toLatin1();
|
||||||
|
if (data->lineNumber != val) {
|
||||||
|
data->lineNumber = val;
|
||||||
|
layoutChanged();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
QString val = value.toString();
|
QByteArray val = value.toString().toLatin1();
|
||||||
if (val != data->condition) {
|
if (val != data->condition) {
|
||||||
data->condition = val.toLatin1();
|
data->condition = val;
|
||||||
dataChanged(mi, mi);
|
layoutChanged();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 5: {
|
case 5: {
|
||||||
QString val = value.toString();
|
QByteArray val = value.toString().toLatin1();
|
||||||
if (val != data->ignoreCount) {
|
if (val != data->ignoreCount) {
|
||||||
data->ignoreCount = val.toLatin1();
|
data->ignoreCount = val;
|
||||||
dataChanged(mi, mi);
|
layoutChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
QByteArray val = value.toString().toLatin1();
|
||||||
|
if (val != data->threadSpec) {
|
||||||
|
data->threadSpec = val;
|
||||||
|
layoutChanged();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public:
|
|||||||
QByteArray condition; // Condition associated with breakpoint.
|
QByteArray condition; // Condition associated with breakpoint.
|
||||||
QByteArray ignoreCount; // Ignore count associated with breakpoint.
|
QByteArray ignoreCount; // Ignore count associated with breakpoint.
|
||||||
QByteArray lineNumber; // Line in source file.
|
QByteArray lineNumber; // Line in source file.
|
||||||
|
QByteArray threadSpec; // Thread specification.
|
||||||
QString funcName; // Name of containing function.
|
QString funcName; // Name of containing function.
|
||||||
bool useFullPath; // Should we use the full path when setting the bp?
|
bool useFullPath; // Should we use the full path when setting the bp?
|
||||||
|
|
||||||
@@ -91,6 +92,7 @@ public:
|
|||||||
QString bpFullName; // Full file name acknowledged by the debugger engine.
|
QString bpFullName; // Full file name acknowledged by the debugger engine.
|
||||||
QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
|
QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
|
||||||
QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
|
QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
|
||||||
|
QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
|
||||||
QString bpFuncName; // Function name acknowledged by the debugger engine.
|
QString bpFuncName; // Function name acknowledged by the debugger engine.
|
||||||
QByteArray bpAddress; // Address acknowledged by the debugger engine.
|
QByteArray bpAddress; // Address acknowledged by the debugger engine.
|
||||||
bool bpMultiple; // Happens in constructors/gdb.
|
bool bpMultiple; // Happens in constructors/gdb.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ BreakWindow::BreakWindow(Debugger::DebuggerManager *manager)
|
|||||||
|
|
||||||
void BreakWindow::showAddressColumn(bool on)
|
void BreakWindow::showAddressColumn(bool on)
|
||||||
{
|
{
|
||||||
setColumnHidden(6, !on);
|
setColumnHidden(7, !on);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QModelIndexList normalizeIndexes(const QModelIndexList &list)
|
static QModelIndexList normalizeIndexes(const QModelIndexList &list)
|
||||||
@@ -133,6 +133,13 @@ void BreakWindow::resizeEvent(QResizeEvent *ev)
|
|||||||
QTreeView::resizeEvent(ev);
|
QTreeView::resizeEvent(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakWindow::mouseDoubleClickEvent(QMouseEvent *ev)
|
||||||
|
{
|
||||||
|
QModelIndex indexUnderMouse = indexAt(ev->pos());
|
||||||
|
if (indexUnderMouse.isValid())
|
||||||
|
editBreakpoint(QModelIndexList() << indexUnderMouse);
|
||||||
|
}
|
||||||
|
|
||||||
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
{
|
{
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
@@ -185,9 +192,9 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
alwaysAdjustAction->setCheckable(true);
|
alwaysAdjustAction->setCheckable(true);
|
||||||
alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
|
alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
|
||||||
|
|
||||||
QAction *editConditionAction =
|
QAction *editBreakpointAction =
|
||||||
new QAction(tr("Edit Condition..."), &menu);
|
new QAction(tr("Edit Breakpoint..."), &menu);
|
||||||
editConditionAction->setEnabled(si.size() > 0);
|
editBreakpointAction->setEnabled(si.size() > 0);
|
||||||
|
|
||||||
QAction *synchronizeAction =
|
QAction *synchronizeAction =
|
||||||
new QAction(tr("Synchronize Breakpoints"), &menu);
|
new QAction(tr("Synchronize Breakpoints"), &menu);
|
||||||
@@ -223,7 +230,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
new QAction(tr("Set Breakpoint at \"catch\""), this);
|
new QAction(tr("Set Breakpoint at \"catch\""), this);
|
||||||
|
|
||||||
menu.addAction(deleteAction);
|
menu.addAction(deleteAction);
|
||||||
menu.addAction(editConditionAction);
|
menu.addAction(editBreakpointAction);
|
||||||
menu.addAction(toggleEnabledAction);
|
menu.addAction(toggleEnabledAction);
|
||||||
menu.addAction(pathAction);
|
menu.addAction(pathAction);
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
@@ -261,8 +268,8 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
resizeColumnsToContents();
|
resizeColumnsToContents();
|
||||||
else if (act == alwaysAdjustAction)
|
else if (act == alwaysAdjustAction)
|
||||||
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
|
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
|
||||||
else if (act == editConditionAction)
|
else if (act == editBreakpointAction)
|
||||||
editConditions(si);
|
editBreakpoint(si);
|
||||||
else if (act == synchronizeAction)
|
else if (act == synchronizeAction)
|
||||||
emit breakpointSynchronizationRequested();
|
emit breakpointSynchronizationRequested();
|
||||||
else if (act == toggleEnabledAction)
|
else if (act == toggleEnabledAction)
|
||||||
@@ -284,7 +291,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
|
void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
|
||||||
{
|
{
|
||||||
foreach (const QModelIndex &idx, list)
|
foreach (const QModelIndex &idx, list)
|
||||||
model()->setData(idx, enabled);
|
model()->setData(idx, enabled, Qt::UserRole + 1);
|
||||||
emit breakpointSynchronizationRequested();
|
emit breakpointSynchronizationRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +299,7 @@ void BreakWindow::setBreakpointsFullPath(const QModelIndexList &list, bool fullp
|
|||||||
{
|
{
|
||||||
foreach (const QModelIndex &idx, list) {
|
foreach (const QModelIndex &idx, list) {
|
||||||
QModelIndex idx2 = idx.sibling(idx.row(), 2);
|
QModelIndex idx2 = idx.sibling(idx.row(), 2);
|
||||||
model()->setData(idx2, fullpath);
|
model()->setData(idx2, fullpath, Qt::UserRole + 2);
|
||||||
}
|
}
|
||||||
emit breakpointSynchronizationRequested();
|
emit breakpointSynchronizationRequested();
|
||||||
}
|
}
|
||||||
@@ -320,7 +327,7 @@ void BreakWindow::deleteBreakpoints(QList<int> list)
|
|||||||
setCurrentIndex(model()->index(row, 0));
|
setCurrentIndex(model()->index(row, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BreakWindow::editConditions(const QModelIndexList &list)
|
void BreakWindow::editBreakpoint(const QModelIndexList &list)
|
||||||
{
|
{
|
||||||
QDialog dlg(this);
|
QDialog dlg(this);
|
||||||
Ui::BreakCondition ui;
|
Ui::BreakCondition ui;
|
||||||
@@ -330,15 +337,36 @@ void BreakWindow::editConditions(const QModelIndexList &list)
|
|||||||
QModelIndex idx = list.front();
|
QModelIndex idx = list.front();
|
||||||
int row = idx.row();
|
int row = idx.row();
|
||||||
dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
|
dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
|
||||||
ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString());
|
int role = Qt::UserRole + 1;
|
||||||
ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt());
|
ui.lineEditFunction->hide();
|
||||||
|
ui.labelFunction->hide();
|
||||||
|
ui.lineEditFileName->hide();
|
||||||
|
ui.labelFileName->hide();
|
||||||
|
ui.lineEditLineNumber->hide();
|
||||||
|
ui.labelLineNumber->hide();
|
||||||
|
//ui.lineEditFunction->setText(
|
||||||
|
// model()->data(idx.sibling(row, 1), role).toString());
|
||||||
|
//ui.lineEditFileName->setText(
|
||||||
|
// model()->data(idx.sibling(row, 2), role).toString());
|
||||||
|
//ui.lineEditLineNumber->setText(
|
||||||
|
// model()->data(idx.sibling(row, 3), role).toString());
|
||||||
|
ui.lineEditCondition->setText(
|
||||||
|
model()->data(idx.sibling(row, 4), role).toString());
|
||||||
|
ui.lineEditIgnoreCount->setText(
|
||||||
|
model()->data(idx.sibling(row, 5), role).toString());
|
||||||
|
ui.lineEditThreadSpec->setText(
|
||||||
|
model()->data(idx.sibling(row, 6), role).toString());
|
||||||
|
|
||||||
if (dlg.exec() == QDialog::Rejected)
|
if (dlg.exec() == QDialog::Rejected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (const QModelIndex &idx, list) {
|
foreach (const QModelIndex &idx, list) {
|
||||||
|
//model()->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
|
||||||
|
//model()->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
|
||||||
|
//model()->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
|
||||||
model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
|
model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
|
||||||
model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value());
|
model()->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
|
||||||
|
model()->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
|
||||||
}
|
}
|
||||||
emit breakpointSynchronizationRequested();
|
emit breakpointSynchronizationRequested();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
QT_END_NAMESPACE
|
||||||
**
|
**
|
||||||
** This file is part of Qt Creator
|
** This file is part of Qt Creator
|
||||||
**
|
**
|
||||||
@@ -65,11 +66,12 @@ protected:
|
|||||||
void resizeEvent(QResizeEvent *ev);
|
void resizeEvent(QResizeEvent *ev);
|
||||||
void contextMenuEvent(QContextMenuEvent *ev);
|
void contextMenuEvent(QContextMenuEvent *ev);
|
||||||
void keyPressEvent(QKeyEvent *ev);
|
void keyPressEvent(QKeyEvent *ev);
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *ev);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void deleteBreakpoints(const QModelIndexList &list);
|
void deleteBreakpoints(const QModelIndexList &list);
|
||||||
void deleteBreakpoints(QList<int> rows);
|
void deleteBreakpoints(QList<int> rows);
|
||||||
void editConditions(const QModelIndexList &list);
|
void editBreakpoint(const QModelIndexList &list);
|
||||||
void setBreakpointsEnabled(const QModelIndexList &list, bool enabled);
|
void setBreakpointsEnabled(const QModelIndexList &list, bool enabled);
|
||||||
void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath);
|
void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath);
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
|
|||||||
// Take over rest as is
|
// Take over rest as is
|
||||||
nbd->bpCondition = nbd->condition;
|
nbd->bpCondition = nbd->condition;
|
||||||
nbd->bpIgnoreCount = nbd->ignoreCount;
|
nbd->bpIgnoreCount = nbd->ignoreCount;
|
||||||
|
nbd->bpThreadSpec = nbd->threadSpec;
|
||||||
nbd->bpFileName = nbd->fileName;
|
nbd->bpFileName = nbd->fileName;
|
||||||
nbd->bpLineNumber = nbd->lineNumber;
|
nbd->bpLineNumber = nbd->lineNumber;
|
||||||
nbd->bpFuncName = nbd->funcName;
|
nbd->bpFuncName = nbd->funcName;
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
|
|||||||
int progress = m_progress->progressValue();
|
int progress = m_progress->progressValue();
|
||||||
m_progress->setProgressValue(qMin(70, progress + 1));
|
m_progress->setProgressValue(qMin(70, progress + 1));
|
||||||
QByteArray id = result.findChild("id").data();
|
QByteArray id = result.findChild("id").data();
|
||||||
showStatusMessage(tr("Thread group %1 created.").arg(_(id)), 1000);
|
showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
|
||||||
int pid = id.toInt();
|
int pid = id.toInt();
|
||||||
if (pid != inferiorPid())
|
if (pid != inferiorPid())
|
||||||
handleInferiorPidChanged(pid);
|
handleInferiorPidChanged(pid);
|
||||||
@@ -789,7 +789,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
|
|||||||
} else if (state() == InferiorRunningRequested_Kill) {
|
} else if (state() == InferiorRunningRequested_Kill) {
|
||||||
debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
|
debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
|
||||||
} else if (state() == InferiorRunning) {
|
} else if (state() == InferiorRunning) {
|
||||||
showStatusMessage(tr("Stopping temporarily."), 1000);
|
showStatusMessage(tr("Stopping temporarily"), 1000);
|
||||||
interruptInferiorTemporarily();
|
interruptInferiorTemporarily();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
|
qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
|
||||||
@@ -802,7 +802,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
|
|||||||
|
|
||||||
void GdbEngine::flushQueuedCommands()
|
void GdbEngine::flushQueuedCommands()
|
||||||
{
|
{
|
||||||
showStatusMessage(tr("Processing queued commands."), 1000);
|
showStatusMessage(tr("Processing queued commands"), 1000);
|
||||||
while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
|
while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
|
||||||
GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
|
GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
|
||||||
debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
|
debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
|
||||||
@@ -908,7 +908,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
|
|||||||
debugMessage(_("APPLYING WORKAROUND #1"));
|
debugMessage(_("APPLYING WORKAROUND #1"));
|
||||||
showMessageBox(QMessageBox::Critical,
|
showMessageBox(QMessageBox::Critical,
|
||||||
tr("Executable failed"), QString::fromLocal8Bit(msg));
|
tr("Executable failed"), QString::fromLocal8Bit(msg));
|
||||||
showStatusMessage(tr("Process failed to start."));
|
showStatusMessage(tr("Process failed to start"));
|
||||||
shutdown();
|
shutdown();
|
||||||
} else if (msg == "\"finish\" not meaningful in the outermost frame.") {
|
} else if (msg == "\"finish\" not meaningful in the outermost frame.") {
|
||||||
// Handle a case known to appear on gdb 6.4 symbianelf when
|
// Handle a case known to appear on gdb 6.4 symbianelf when
|
||||||
@@ -1091,7 +1091,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
|
|||||||
// ~"242\t x *= 2;"
|
// ~"242\t x *= 2;"
|
||||||
//109^done"
|
//109^done"
|
||||||
setState(InferiorStopped);
|
setState(InferiorStopped);
|
||||||
showStatusMessage(tr("Jumped. Stopped."));
|
showStatusMessage(tr("Jumped. Stopped"));
|
||||||
QByteArray output = response.data.findChild("logstreamoutput").data();
|
QByteArray output = response.data.findChild("logstreamoutput").data();
|
||||||
if (output.isEmpty())
|
if (output.isEmpty())
|
||||||
return;
|
return;
|
||||||
@@ -1117,7 +1117,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
|
|||||||
// // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
|
// // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
|
||||||
// QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
|
// QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
|
||||||
// setState(InferiorStopped);
|
// setState(InferiorStopped);
|
||||||
// showStatusMessage(tr("Function reached. Stopped."));
|
// showStatusMessage(tr("Function reached. Stopped"));
|
||||||
// GdbMi frame = response.data.findChild("frame");
|
// GdbMi frame = response.data.findChild("frame");
|
||||||
// StackFrame f = parseStackFrame(frame, 0);
|
// StackFrame f = parseStackFrame(frame, 0);
|
||||||
// gotoLocation(f, true);
|
// gotoLocation(f, true);
|
||||||
@@ -1389,7 +1389,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
|
|||||||
if (reason == "breakpoint-hit") {
|
if (reason == "breakpoint-hit") {
|
||||||
QByteArray bpNumber = data.findChild("bkptno").data();
|
QByteArray bpNumber = data.findChild("bkptno").data();
|
||||||
QByteArray threadId = data.findChild("thread-id").data();
|
QByteArray threadId = data.findChild("thread-id").data();
|
||||||
showStatusMessage(tr("Stopped at breakpoint %1 in thread %2.")
|
showStatusMessage(tr("Stopped at breakpoint %1 in thread %2")
|
||||||
.arg(_(bpNumber), _(threadId)));
|
.arg(_(bpNumber), _(threadId)));
|
||||||
} else {
|
} else {
|
||||||
QString reasontr = tr("Stopped: \"%1\"").arg(_(reason));
|
QString reasontr = tr("Stopped: \"%1\"").arg(_(reason));
|
||||||
@@ -2115,6 +2115,8 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt
|
|||||||
if (ba.startsWith('<') && ba.endsWith('>'))
|
if (ba.startsWith('<') && ba.endsWith('>'))
|
||||||
ba = ba.mid(1, ba.size() - 2);
|
ba = ba.mid(1, ba.size() - 2);
|
||||||
data->bpFuncName = _(ba);
|
data->bpFuncName = _(ba);
|
||||||
|
} else if (child.hasName("thread")) {
|
||||||
|
data->bpThreadSpec = child.data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This field is not present. Contents needs to be parsed from
|
// This field is not present. Contents needs to be parsed from
|
||||||
@@ -2145,9 +2147,8 @@ QString GdbEngine::breakLocation(const QString &file) const
|
|||||||
return where;
|
return where;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray GdbEngine::breakpointLocation(int index)
|
QByteArray GdbEngine::breakpointLocation(const BreakpointData *data)
|
||||||
{
|
{
|
||||||
const BreakpointData *data = manager()->breakHandler()->at(index);
|
|
||||||
if (!data->funcName.isEmpty())
|
if (!data->funcName.isEmpty())
|
||||||
return data->funcName.toLatin1();
|
return data->funcName.toLatin1();
|
||||||
// In this case, data->funcName is something like '*0xdeadbeef'
|
// In this case, data->funcName is something like '*0xdeadbeef'
|
||||||
@@ -2162,21 +2163,28 @@ QByteArray GdbEngine::breakpointLocation(int index)
|
|||||||
|
|
||||||
void GdbEngine::sendInsertBreakpoint(int index)
|
void GdbEngine::sendInsertBreakpoint(int index)
|
||||||
{
|
{
|
||||||
|
const BreakpointData *data = manager()->breakHandler()->at(index);
|
||||||
// Set up fallback in case of pending breakpoints which aren't handled
|
// Set up fallback in case of pending breakpoints which aren't handled
|
||||||
// by the MI interface.
|
// by the MI interface.
|
||||||
QByteArray cmd;
|
QByteArray cmd;
|
||||||
if (m_isMacGdb)
|
if (m_isMacGdb) {
|
||||||
cmd = "-break-insert -l -1 -f ";
|
cmd = "-break-insert -l -1 -f ";
|
||||||
else if (m_gdbAdapter->isTrkAdapter())
|
} else if (m_gdbAdapter->isTrkAdapter()) {
|
||||||
cmd = "-break-insert -h -f ";
|
cmd = "-break-insert -h -f ";
|
||||||
else if (m_gdbVersion >= 60800)
|
} else if (m_gdbVersion >= 70000) {
|
||||||
|
cmd = "-break-insert ";
|
||||||
|
if (!data->threadSpec.isEmpty())
|
||||||
|
cmd += "-p " + data->threadSpec;
|
||||||
|
cmd += " -f ";
|
||||||
|
} else if (m_gdbVersion >= 60800) {
|
||||||
// Probably some earlier version would work as well.
|
// Probably some earlier version would work as well.
|
||||||
cmd = "-break-insert -f ";
|
cmd = "-break-insert -f ";
|
||||||
else
|
} else {
|
||||||
cmd = "-break-insert ";
|
cmd = "-break-insert ";
|
||||||
|
}
|
||||||
//if (!data->condition.isEmpty())
|
//if (!data->condition.isEmpty())
|
||||||
// cmd += "-c " + data->condition + ' ';
|
// cmd += "-c " + data->condition + ' ';
|
||||||
cmd += breakpointLocation(index);
|
cmd += breakpointLocation(data);
|
||||||
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
|
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
|
||||||
CB(handleBreakInsert1), index);
|
CB(handleBreakInsert1), index);
|
||||||
}
|
}
|
||||||
@@ -2184,17 +2192,16 @@ void GdbEngine::sendInsertBreakpoint(int index)
|
|||||||
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
|
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
|
||||||
{
|
{
|
||||||
int index = response.cookie.toInt();
|
int index = response.cookie.toInt();
|
||||||
BreakHandler *handler = manager()->breakHandler();
|
BreakpointData *data = manager()->breakHandler()->at(index);
|
||||||
if (response.resultClass == GdbResultDone) {
|
if (response.resultClass == GdbResultDone) {
|
||||||
// Interesting only on Mac?
|
// Interesting only on Mac?
|
||||||
BreakpointData *data = handler->at(index);
|
|
||||||
GdbMi bkpt = response.data.findChild("bkpt");
|
GdbMi bkpt = response.data.findChild("bkpt");
|
||||||
breakpointDataFromOutput(data, bkpt);
|
breakpointDataFromOutput(data, bkpt);
|
||||||
} else {
|
} else {
|
||||||
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
|
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
|
||||||
// know how to do pending breakpoints using CLI but not MI. So try
|
// know how to do pending breakpoints using CLI but not MI. So try
|
||||||
// again with MI.
|
// again with MI.
|
||||||
QByteArray cmd = "break " + breakpointLocation(index);
|
QByteArray cmd = "break " + breakpointLocation(data);
|
||||||
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
|
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
|
||||||
CB(handleBreakInsert2), index);
|
CB(handleBreakInsert2), index);
|
||||||
}
|
}
|
||||||
@@ -2524,7 +2531,8 @@ void GdbEngine::attemptBreakpointSynchronization()
|
|||||||
else // Because gdb won't do both changes at a time anyway.
|
else // Because gdb won't do both changes at a time anyway.
|
||||||
if (data->ignoreCount != data->bpIgnoreCount) {
|
if (data->ignoreCount != data->bpIgnoreCount) {
|
||||||
// Update ignorecount if needed.
|
// Update ignorecount if needed.
|
||||||
postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount,
|
QByteArray ic = QByteArray::number(data->ignoreCount.toInt());
|
||||||
|
postCommand("ignore " + data->bpNumber + ' ' + ic,
|
||||||
NeedsStop | RebuildBreakpointModel,
|
NeedsStop | RebuildBreakpointModel,
|
||||||
CB(handleBreakIgnore), data->bpNumber.toInt());
|
CB(handleBreakIgnore), data->bpNumber.toInt());
|
||||||
continue;
|
continue;
|
||||||
@@ -2536,6 +2544,17 @@ void GdbEngine::attemptBreakpointSynchronization()
|
|||||||
data->bpEnabled = false;
|
data->bpEnabled = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (data->threadSpec != data->bpThreadSpec && !data->bpThreadSpec.isEmpty()) {
|
||||||
|
// The only way to change this seems to be to re-set the bp completely.
|
||||||
|
//qDebug() << "FIXME: THREAD: " << data->threadSpec << data->bpThreadSpec;
|
||||||
|
//data->bpThreadSpec = data->threadSpec;
|
||||||
|
if (!data->bpNumber.isEmpty()) {
|
||||||
|
postCommand("-break-delete " + data->bpNumber,
|
||||||
|
NeedsStop | RebuildBreakpointModel);
|
||||||
|
sendInsertBreakpoint(index);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (data->bpAddress.startsWith("0x")
|
if (data->bpAddress.startsWith("0x")
|
||||||
&& data->bpCorrectedLineNumber.isEmpty()) {
|
&& data->bpCorrectedLineNumber.isEmpty()) {
|
||||||
// Prevent endless loop.
|
// Prevent endless loop.
|
||||||
@@ -3958,7 +3977,7 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
|
|||||||
}
|
}
|
||||||
if (!foundPython) {
|
if (!foundPython) {
|
||||||
debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
|
debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
|
||||||
showStatusMessage(_("Gdb at %1 does not have python.").arg(m_gdb));
|
showStatusMessage(_("Gdb at %1 does not have python").arg(m_gdb));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ private: ////////// View & Data Stuff //////////
|
|||||||
void handleInfoLine(const GdbResponse &response);
|
void handleInfoLine(const GdbResponse &response);
|
||||||
void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
|
void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
|
||||||
void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
|
void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
|
||||||
QByteArray breakpointLocation(int index);
|
QByteArray breakpointLocation(const BreakpointData *data);
|
||||||
void sendInsertBreakpoint(int index);
|
void sendInsertBreakpoint(int index);
|
||||||
QString breakLocation(const QString &file) const;
|
QString breakLocation(const QString &file) const;
|
||||||
void reloadBreakListInternal();
|
void reloadBreakListInternal();
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
|||||||
//qDebug() << "SECOND CHUNK: " << out;
|
//qDebug() << "SECOND CHUNK: " << out;
|
||||||
int pos = out.indexOf("data=");
|
int pos = out.indexOf("data=");
|
||||||
if (pos != 0) {
|
if (pos != 0) {
|
||||||
qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: "
|
debugMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: "
|
||||||
<< out.left(pos);
|
+ out.left(pos)));
|
||||||
out = out.mid(pos);
|
out = out.mid(pos);
|
||||||
}
|
}
|
||||||
GdbMi all;
|
GdbMi all;
|
||||||
|
|||||||
@@ -1218,10 +1218,13 @@ public:
|
|||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
int j = 2;
|
||||||
|
++j;
|
||||||
for (int i = 0; i != 100000; ++i) {
|
for (int i = 0; i != 100000; ++i) {
|
||||||
//sleep(1);
|
//sleep(1);
|
||||||
std::cerr << m_id;
|
std::cerr << m_id;
|
||||||
}
|
}
|
||||||
|
std::cerr << j;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1655,7 +1658,7 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
testQStringList();
|
testQStringList();
|
||||||
testStruct();
|
testStruct();
|
||||||
//testThreads();
|
testQThread();
|
||||||
testQVariant1();
|
testQVariant1();
|
||||||
testQVariant2();
|
testQVariant2();
|
||||||
testQVariant3();
|
testQVariant3();
|
||||||
|
|||||||
Reference in New Issue
Block a user