1
0
Fork 0

breakpoint, memory and threads view support multi-select (#1697)

* breakpoint, memory and threads view support multi-select

* fixed

* use older breakpointsview

* fixed

* revert deps change

* command in reference view

* to-do

* fixed deps
This commit is contained in:
Torusrxxx 2017-09-01 11:57:41 +00:00 committed by Duncan Ogilvie
parent 2b4a9bc9dc
commit 690b048c7f
13 changed files with 171 additions and 107 deletions

View File

@ -1643,6 +1643,11 @@ BRIDGE_IMPEXP void GuiFlushLog()
_gui_sendmessage(GUI_FLUSH_LOG, nullptr, nullptr);
}
BRIDGE_IMPEXP void GuiReferenceAddCommand(const char* title, const char* command)
{
_gui_sendmessage(GUI_REF_ADDCOMMAND, (void*)title, (void*)command);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;

View File

@ -1111,6 +1111,7 @@ typedef enum
GUI_REF_SEARCH_GETROWCOUNT, // param1=unused, param2=unused
GUI_REF_SEARCH_GETCELLCONTENT, // param1=int row, param2=int col
GUI_MENU_REMOVE, // param1=int hEntryMenu, param2=unused
GUI_REF_ADDCOMMAND // param1=const char* title, param2=const char* command
} GUIMSG;
//GUI Typedefs
@ -1284,6 +1285,7 @@ BRIDGE_IMPEXP bool GuiTypeClear();
BRIDGE_IMPEXP void GuiUpdateTypeWidget();
BRIDGE_IMPEXP void GuiCloseApplication();
BRIDGE_IMPEXP void GuiFlushLog();
BRIDGE_IMPEXP void GuiReferenceAddCommand(const char* title, const char* command);
#ifdef __cplusplus
}

View File

@ -106,6 +106,7 @@ bool cbInstrCommentList(int argc, char* argv[])
total++;
}
varset("$result", total, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "commentdel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d comment(s) listed in Reference View\n"), total);
GuiReferenceReloadData();
return true;
@ -180,6 +181,7 @@ bool cbInstrLabelList(int argc, char* argv[])
GuiReferenceSetCellContent(i, 2, labels[i].text.c_str());
}
varset("$result", count, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "labeldel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d label(s) listed in Reference View\n"), count);
GuiReferenceReloadData();
return true;
@ -264,6 +266,7 @@ bool cbInstrBookmarkList(int argc, char* argv[])
}
}
varset("$result", count, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "bookmarkdel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d bookmark(s) listed\n"), count);
GuiReferenceReloadData();
return true;
@ -354,6 +357,7 @@ bool cbInstrFunctionList(int argc, char* argv[])
}
}
varset("$result", count, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "functiondel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d function(s) listed\n"), count);
GuiReferenceReloadData();
return true;
@ -444,6 +448,7 @@ bool cbInstrArgumentList(int argc, char* argv[])
}
}
varset("$result", count, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "argumentdel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d argument(s) listed\n"), count);
GuiReferenceReloadData();
return true;
@ -543,6 +548,7 @@ bool cbInstrLoopList(int argc, char* argv[])
}
}
varset("$result", count, false);
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "loopdel $0");
dprintf(QT_TRANSLATE_NOOP("DBG", "%d loop(s) listed\n"), count);
GuiReferenceReloadData();
return true;

View File

@ -132,6 +132,7 @@ bool cbInstrVarList(int argc, char* argv[])
realvarcount++;
}
}
GuiReferenceAddCommand(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Delete")), "vardel $1");
GuiReferenceReloadData();
return true;
}

View File

@ -104,6 +104,7 @@ void ReferenceView::connectBridge()
connect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), this, SLOT(referenceSetProgressSlot(int)));
connect(Bridge::getBridge(), SIGNAL(referenceSetCurrentTaskProgress(int, QString)), this, SLOT(referenceSetCurrentTaskProgressSlot(int, QString)));
connect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
connect(Bridge::getBridge(), SIGNAL(referenceAddCommand(QString, QString)), this, SLOT(addCommand(QString, QString)));
connect(this->mSearchList, SIGNAL(selectionChangedSignal(int)), this, SLOT(searchSelectionChanged(int)));
connect(this->mList, SIGNAL(selectionChangedSignal(int)), this, SLOT(searchSelectionChanged(int)));
}
@ -118,6 +119,7 @@ void ReferenceView::disconnectBridge()
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchTotalProgress, SLOT(setValue(int)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetCurrentTaskProgress(int, QString)), this, SLOT(referenceSetCurrentTaskProgressSlot(int, QString)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
disconnect(Bridge::getBridge(), SIGNAL(referenceAddCommand(QString, QString)), this, SLOT(addCommand(QString, QString)));
disconnect(this->mSearchList, SIGNAL(selectionChangedSignal(int)), this, SLOT(searchSelectionChanged(int)));
disconnect(this->mList, SIGNAL(selectionChangedSignal(int)), this, SLOT(searchSelectionChanged(int)));
}
@ -177,6 +179,12 @@ void ReferenceView::setCellContent(int r, int c, QString s)
mList->setCellContent(r, c, s);
}
void ReferenceView::addCommand(QString title, QString command)
{
mCommnadTitles.append(title);
mCommands.append(command);
}
void ReferenceView::reloadData()
{
mSearchBox->setText("");
@ -206,31 +214,43 @@ void ReferenceView::referenceContextMenu(QMenu* wMenu)
duint addr;
if(!DbgFunctions()->ValFromString(text.toUtf8().constData(), &addr))
return;
if(!DbgMemIsValidReadPtr(addr))
return;
wMenu->addAction(mFollowAddress);
wMenu->addAction(mFollowDumpAddress);
dsint apiaddr = apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1));
if(apiaddr)
wMenu->addAction(mFollowApiAddress);
wMenu->addSeparator();
wMenu->addAction(mToggleBreakpoint);
wMenu->addAction(mSetBreakpointOnAllCommands);
wMenu->addAction(mRemoveBreakpointOnAllCommands);
if(apiaddr)
if(DbgMemIsValidReadPtr(addr))
{
char label[MAX_LABEL_SIZE] = "";
if(DbgGetLabelAt(apiaddr, SEG_DEFAULT, label))
wMenu->addAction(mFollowAddress);
wMenu->addAction(mFollowDumpAddress);
dsint apiaddr = apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1));
if(apiaddr)
wMenu->addAction(mFollowApiAddress);
wMenu->addSeparator();
wMenu->addAction(mToggleBreakpoint);
wMenu->addAction(mSetBreakpointOnAllCommands);
wMenu->addAction(mRemoveBreakpointOnAllCommands);
if(apiaddr)
{
wMenu->addSeparator();
mSetBreakpointOnAllApiCalls->setText(tr("Set breakpoint on all calls to %1").arg(label));
wMenu->addAction(mSetBreakpointOnAllApiCalls);
mRemoveBreakpointOnAllApiCalls->setText(tr("Remove breakpoint on all calls to %1").arg(label));
wMenu->addAction(mRemoveBreakpointOnAllApiCalls);
char label[MAX_LABEL_SIZE] = "";
if(DbgGetLabelAt(apiaddr, SEG_DEFAULT, label))
{
wMenu->addSeparator();
mSetBreakpointOnAllApiCalls->setText(tr("Set breakpoint on all calls to %1").arg(label));
wMenu->addAction(mSetBreakpointOnAllApiCalls);
mRemoveBreakpointOnAllApiCalls->setText(tr("Remove breakpoint on all calls to %1").arg(label));
wMenu->addAction(mRemoveBreakpointOnAllApiCalls);
}
}
wMenu->addSeparator();
wMenu->addAction(mToggleBookmark);
}
if(this->mCommands.size() > 0)
{
wMenu->addSeparator();
for(auto i = 0; i < this->mCommnadTitles.size(); i++)
{
QAction* newCommandAction = new QAction(this->mCommnadTitles.at(i), wMenu);
newCommandAction->setData(QVariant(mCommands.at(i)));
connect(newCommandAction, SIGNAL(triggered()), this, SLOT(referenceExecCommand()));
wMenu->addAction(newCommandAction);
}
}
wMenu->addSeparator();
wMenu->addAction(mToggleBookmark);
}
void ReferenceView::followAddress()
@ -392,3 +412,23 @@ dsint ReferenceView::apiAddressFromString(const QString & s)
duint value;
return DbgFunctions()->ValFromString(match.toUtf8().constData(), &value) && DbgMemIsValidReadPtr(value) ? value : 0;
}
void ReferenceView::referenceExecCommand()
{
QAction* act = qobject_cast<QAction*>(sender());
if(act != nullptr)
{
QString command = act->data().toString();
for(int selected : mCurList->getSelection()) //to do: enable multi-selection
{
QString specializedCommand = command;
for(int i = 0; i < mCurList->getColumnCount(); i++)
{
QString token = "$" + QString::number(i);
if(specializedCommand.contains(token))
specializedCommand.replace(token, mCurList->getCellContent(selected, i));
}
DbgCmdExec(specializedCommand);
}
}
}

View File

@ -19,6 +19,7 @@ public slots:
void addColumnAt(int width, QString title);
void setRowCount(dsint count);
void setCellContent(int r, int c, QString s);
void addCommand(QString title, QString command);
void reloadData();
void setSingleSelection(int index, bool scroll);
void setSearchStartCol(int col);
@ -41,6 +42,9 @@ public slots:
signals:
void showCpu();
private slots:
void referenceExecCommand();
private:
QProgressBar* mSearchTotalProgress;
QProgressBar* mSearchCurrentTaskProgress;
@ -54,6 +58,8 @@ private:
QAction* mSetBreakpointOnAllApiCalls;
QAction* mRemoveBreakpointOnAllApiCalls;
QLabel* mCountTotalLabel;
QVector<QString> mCommnadTitles;
QVector<QString> mCommands;
enum BPSetAction
{

View File

@ -343,22 +343,24 @@ bool StdTable::isValidIndex(int r, int c)
void StdTable::copyLineSlot()
{
int colCount = getColumnCount();
int selected = getInitialSelection();
QString finalText = "";
if(colCount == 1)
finalText = getCellContent(selected, 0);
finalText = getCellContent(getInitialSelection(), 0);
else
{
for(int i = 0; i < colCount; i++)
for(int selected : getSelection())
{
QString cellContent = getCellContent(selected, i);
if(!cellContent.length()) //skip empty cells
continue;
QString title = mCopyTitles.at(i);
if(title.length())
finalText += title + "=";
finalText += cellContent.trimmed();;
finalText += "\r\n";
for(int i = 0; i < colCount; i++)
{
QString cellContent = getCellContent(selected, i);
if(!cellContent.length()) //skip empty cells
continue;
QString title = mCopyTitles.at(i);
if(title.length())
finalText += title + "=";
finalText += cellContent.trimmed();;
finalText += "\r\n";
}
}
}
Bridge::CopyToClipboard(finalText);

View File

@ -814,6 +814,17 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
}
break;
case GUI_REF_ADDCOMMAND:
{
if(param1 == nullptr && param2 == nullptr)
return nullptr;
else if(param1 == nullptr)
emit referenceAddCommand(QString::fromUtf8((const char*)param2), QString::fromUtf8((const char*)param2));
else
emit referenceAddCommand(QString::fromUtf8((const char*)param1), QString::fromUtf8((const char*)param2));
}
break;
}
return nullptr;

View File

@ -70,6 +70,7 @@ signals:
void referenceAddColumnAt(int width, QString title);
void referenceSetRowCount(dsint count);
void referenceSetCellContent(int r, int c, QString s);
void referenceAddCommand(QString title, QString command);
void referenceReloadData();
void referenceSetSingleSelection(int index, bool scroll);
void referenceSetProgress(int progress);

View File

@ -19,7 +19,7 @@ MemoryMapView::MemoryMapView(StdTable* parent)
mCipBase(0)
{
setDrawDebugOnly(true);
enableMultiSelection(false);
enableMultiSelection(true);
int charwidth = getCharWidth();
@ -77,10 +77,10 @@ void MemoryMapView::setupContextMenu()
mMemoryAccessMenu = new QMenu(tr("Access"), this);
mMemoryAccessMenu->setIcon(DIcon("breakpoint_memory_access.png"));
mMemoryAccessSingleshoot = new QAction(DIcon("breakpoint_memory_singleshoot.png"), tr("&Singleshoot"), this);
connect(mMemoryAccessSingleshoot, SIGNAL(triggered()), this, SLOT(memoryAccessSingleshootSlot()));
makeCommandAction(mMemoryAccessSingleshoot, "bpm $, 0, a");
mMemoryAccessMenu->addAction(mMemoryAccessSingleshoot);
mMemoryAccessRestore = new QAction(DIcon("breakpoint_memory_restore_on_hit.png"), tr("&Restore"), this);
connect(mMemoryAccessRestore, SIGNAL(triggered()), this, SLOT(memoryAccessRestoreSlot()));
makeCommandAction(mMemoryAccessRestore, "bpm $, 1, a");
mMemoryAccessMenu->addAction(mMemoryAccessRestore);
mBreakpointMenu->addMenu(mMemoryAccessMenu);
@ -88,10 +88,10 @@ void MemoryMapView::setupContextMenu()
mMemoryWriteMenu = new QMenu(tr("Write"), this);
mMemoryWriteMenu->setIcon(DIcon("breakpoint_memory_write.png"));
mMemoryWriteSingleshoot = new QAction(DIcon("breakpoint_memory_singleshoot.png"), tr("&Singleshoot"), this);
connect(mMemoryWriteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryWriteSingleshootSlot()));
makeCommandAction(mMemoryWriteSingleshoot, "bpm $, 0, w");
mMemoryWriteMenu->addAction(mMemoryWriteSingleshoot);
mMemoryWriteRestore = new QAction(DIcon("breakpoint_memory_restore_on_hit.png"), tr("&Restore"), this);
connect(mMemoryWriteRestore, SIGNAL(triggered()), this, SLOT(memoryWriteRestoreSlot()));
makeCommandAction(mMemoryWriteRestore, "bpm $, 1, w");
mMemoryWriteMenu->addAction(mMemoryWriteRestore);
mBreakpointMenu->addMenu(mMemoryWriteMenu);
@ -100,17 +100,17 @@ void MemoryMapView::setupContextMenu()
mMemoryExecuteMenu->setIcon(DIcon("breakpoint_memory_execute.png"));
mMemoryExecuteSingleshoot = new QAction(DIcon("breakpoint_memory_singleshoot.png"), tr("&Singleshoot"), this);
mMemoryExecuteSingleshoot->setShortcutContext(Qt::WidgetShortcut);
connect(mMemoryExecuteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryExecuteSingleshootSlot()));
makeCommandAction(mMemoryExecuteSingleshoot, "bpm $, 0, x");
mMemoryExecuteMenu->addAction(mMemoryExecuteSingleshoot);
mMemoryExecuteRestore = new QAction(DIcon("breakpoint_memory_restore_on_hit.png"), tr("&Restore"), this);
connect(mMemoryExecuteRestore, SIGNAL(triggered()), this, SLOT(memoryExecuteRestoreSlot()));
makeCommandAction(mMemoryExecuteRestore, "bpm $, 1, x");
mMemoryExecuteMenu->addAction(mMemoryExecuteRestore);
mBreakpointMenu->addMenu(mMemoryExecuteMenu);
//Breakpoint->Remove
mMemoryRemove = new QAction(tr("&Remove"), this);
mMemoryRemove->setShortcutContext(Qt::WidgetShortcut);
connect(mMemoryRemove, SIGNAL(triggered()), this, SLOT(memoryRemoveSlot()));
makeCommandAction(mMemoryRemove, "bpmc $");
mBreakpointMenu->addAction(mMemoryRemove);
this->addAction(mMemoryRemove);
@ -129,7 +129,7 @@ void MemoryMapView::setupContextMenu()
//Free memory
mMemoryFree = new QAction(DIcon("memmap_free_memory.png"), tr("&Free memory"), this);
mMemoryFree->setShortcutContext(Qt::WidgetShortcut);
connect(mMemoryFree, SIGNAL(triggered()), this, SLOT(memoryFreeSlot()));
makeCommandAction(mMemoryFree, "free $");
this->addAction(mMemoryFree);
//Goto
@ -324,6 +324,36 @@ QString MemoryMapView::paintContent(QPainter* painter, dsint rowBase, int rowOff
return StdTable::paintContent(painter, rowBase, rowOffset, col, x, y, w, h);
}
QAction* MemoryMapView::makeCommandAction(QAction* action, const QString & command)
{
action->setData(QVariant(command));
connect(action, SIGNAL(triggered()), this, SLOT(ExecCommand()));
return action;
}
/**
* @brief MemoryMapView::ExecCommand execute command slot for menus.
*/
void MemoryMapView::ExecCommand()
{
QAction* action = qobject_cast<QAction*>(sender());
if(action)
{
QString command = action->data().toString();
if(command.contains('$'))
{
for(int i : getSelection())
{
QString specializedCommand = command;
specializedCommand.replace(QChar('$'), getCellContent(i, 0)); // $ -> Base address
DbgCmdExec(specializedCommand.toUtf8().constData());
}
}
else
DbgCmdExec(command.toUtf8().constData());
}
}
void MemoryMapView::refreshMap()
{
MEMMAP wMemMapStruct;
@ -454,60 +484,21 @@ void MemoryMapView::yaraSlot()
}
}
void MemoryMapView::memoryAccessSingleshootSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 0, a").toUtf8().constData());
}
void MemoryMapView::memoryAccessRestoreSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 1, a").toUtf8().constData());
}
void MemoryMapView::memoryWriteSingleshootSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 0, w").toUtf8().constData());
}
void MemoryMapView::memoryWriteRestoreSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 1, w").toUtf8().constData());
}
void MemoryMapView::memoryExecuteSingleshootSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 0, x").toUtf8().constData());
}
void MemoryMapView::memoryExecuteRestoreSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpm " + addr_text + ", 1, x").toUtf8().constData());
}
void MemoryMapView::memoryRemoveSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
DbgCmdExec(QString("bpmc " + addr_text).toUtf8().constData());
}
void MemoryMapView::memoryExecuteSingleshootToggleSlot()
{
QString addr_text = getCellContent(getInitialSelection(), 0);
for(int i : getSelection())
{
QString addr_text = getCellContent(i, 0);
#ifdef _WIN64
duint selectedAddr = addr_text.toULongLong(0, 16);
duint selectedAddr = addr_text.toULongLong(0, 16);
#else //x86
duint selectedAddr = addr_text.toULong(0, 16);
duint selectedAddr = addr_text.toULong(0, 16);
#endif //_WIN64
if((DbgGetBpxTypeAt(selectedAddr) & bp_memory) == bp_memory) //memory breakpoint set
memoryRemoveSlot();
else
memoryExecuteSingleshootSlot();
if((DbgGetBpxTypeAt(selectedAddr) & bp_memory) == bp_memory) //memory breakpoint set
DbgCmdExec(QString("bpmc ") + selectedAddr);
else
DbgCmdExec(QString("bpm %1, 0, x").arg(selectedAddr));
}
}
void MemoryMapView::pageMemoryRights()
@ -572,11 +563,6 @@ void MemoryMapView::memoryAllocateSlot()
}
}
void MemoryMapView::memoryFreeSlot()
{
DbgCmdExec(QString("free %1").arg(getCellContent(getInitialSelection(), 0)).toUtf8().constData());
}
void MemoryMapView::findPatternSlot()
{
HexEditDialog hexEdit(this);

View File

@ -23,16 +23,9 @@ public slots:
void followDisassemblerSlot();
void doubleClickedSlot();
void yaraSlot();
void memoryAccessSingleshootSlot();
void memoryAccessRestoreSlot();
void memoryWriteSingleshootSlot();
void memoryWriteRestoreSlot();
void memoryExecuteSingleshootSlot();
void memoryExecuteRestoreSlot();
void memoryRemoveSlot();
void memoryExecuteSingleshootToggleSlot();
void memoryAllocateSlot();
void memoryFreeSlot();
void ExecCommand();
void contextMenuSlot(const QPoint & pos);
void switchView();
void pageMemoryRights();
@ -50,6 +43,7 @@ public slots:
private:
QString getProtectionString(DWORD Protect);
QAction* makeCommandAction(QAction* action, const QString & command);
GotoDialog* mGoto = nullptr;

View File

@ -63,7 +63,7 @@ void SEHChainView::updateSEHChain()
void SEHChainView::contextMenuSlot(const QPoint pos)
{
if(!DbgIsDebugging())
if(!DbgIsDebugging() || this->getRowCount() == 0)
return;
QMenu wMenu(this); //create context menu
wMenu.addAction(mFollowAddress);

View File

@ -138,13 +138,23 @@ void ThreadView::ExecCommand()
if(action)
{
QString command = action->data().toString();
command.replace(QChar('$'), getCellContent(getInitialSelection(), 1)); // $ -> Thread Id
DbgCmdExec(command.toUtf8().constData());
if(command.contains('$'))
{
for(int i : getSelection())
{
QString specializedCommand = command;
specializedCommand.replace(QChar('$'), getCellContent(i, 1)); // $ -> Thread Id
DbgCmdExec(specializedCommand.toUtf8().constData());
}
}
else
DbgCmdExec(command.toUtf8().constData());
}
}
ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
{
enableMultiSelection(true);
int charwidth = getCharWidth();
addColumnAt(8 + charwidth * sizeof(unsigned int) * 2, tr("Number"), false, "", SortBy::AsInt);
addColumnAt(8 + charwidth * sizeof(unsigned int) * 2, tr("ID"), false, "", SortBy::AsHex);
@ -382,7 +392,7 @@ void ThreadView::SetNameSlot()
{
QString threadId = getCellContent(getInitialSelection(), 1);
LineEditDialog mLineEdit(this);
mLineEdit.setWindowTitle(tr("Name"));
mLineEdit.setWindowTitle(tr("Name") + threadId);
mLineEdit.setText(getCellContent(getInitialSelection(), 13));
if(mLineEdit.exec() != QDialog::Accepted)
return;