Disassembly Options Dialog (#21)

* Add AsmOptionsDialog
* Add bbline to AsmOptionsDialog, properly handle defaults
* Remove now redundant asm options from right click and menu
This commit is contained in:
Florian Märkl 2017-10-01 16:36:40 +02:00 committed by xarkes
parent ffa52bd3e8
commit 808da402da
19 changed files with 561 additions and 539 deletions

View File

@ -2,6 +2,7 @@
#include <QJsonObject>
#include "cutter.h"
#include "sdb.h"
#include "settings.h"
#define DB this->db
@ -50,11 +51,11 @@ CutterCore::CutterCore(QObject *parent) :
// IMPLICIT r_bin_iobind (core_->bin, core_->io);
// Otherwise r2 may ask the user for input and Cutter would freeze
config("scr.interactive", "false");
setConfig("scr.interactive", false);
// Used by the HTML5 graph
config("http.cors", "true");
config("http.sandbox", "false");
setConfig("http.cors", true);
setConfig("http.sandbox", false);
//config("http.port", "14170");
// Temporary fixes
@ -457,35 +458,72 @@ QString CutterCore::itoa(ut64 num, int rdx)
return QString::number(num, rdx);
}
QString CutterCore::config(const QString &k, const QString &v)
void CutterCore::setConfig(const QString &k, const QString &v)
{
CORE_LOCK();
QByteArray key = k.toUtf8();
if (v != NULL)
{
r_config_set(core_->config, key.constData(), v.toUtf8().constData());
return NULL;
}
return QString(r_config_get(core_->config, key.constData()));
r_config_set(core_->config, k.toUtf8().constData(), v.toUtf8().constData());
}
int CutterCore::config(const QString &k, int v)
void CutterCore::setConfig(const QString &k, int v)
{
CORE_LOCK();
QByteArray key = k.toUtf8();
if (v != -1)
{
r_config_set_i(core_->config, key.constData(), v);
return 0;
}
return r_config_get_i(core_->config, key.constData());
r_config_set_i(core_->config, k.toUtf8().constData(), static_cast<const unsigned long long int>(v));
}
void CutterCore::setConfig(const QString &k, bool v)
{
CORE_LOCK();
r_config_set_i(core_->config, k.toUtf8().constData(), v ? 1 : 0);
}
int CutterCore::getConfigi(const QString &k)
{
CORE_LOCK();
QByteArray key = k.toUtf8();
return r_config_get_i(core_->config, key.constData());
return static_cast<int>(r_config_get_i(core_->config, key.constData()));
}
bool CutterCore::getConfigb(const QString &k)
{
CORE_LOCK();
return r_config_get_i(core_->config, k.toUtf8().constData()) != 0;
}
void CutterCore::triggerAsmOptionsChanged()
{
emit asmOptionsChanged();
}
void CutterCore::resetDefaultAsmOptions()
{
Settings settings;
setConfig("asm.esil", settings.getAsmESIL());
setConfig("asm.pseudo", settings.getAsmPseudo());
setConfig("asm.offset", settings.getAsmOffset());
setConfig("asm.describe", settings.getAsmDescribe());
setConfig("asm.stackptr", settings.getAsmStackPointer());
setConfig("asm.bytes", settings.getAsmBytes());
setConfig("asm.bytespace", settings.getAsmBytespace());
setConfig("asm.lbytes", settings.getAsmLBytes());
setConfig("asm.syntax", settings.getAsmSyntax());
setConfig("asm.ucase", settings.getAsmUppercase());
setConfig("asm.bbline", settings.getAsmBBLine());
}
void CutterCore::saveDefaultAsmOptions()
{
Settings settings;
settings.setAsmESIL(getConfigb("asm.esil"));
settings.setAsmPseudo(getConfigb("asm.pseudo"));
settings.setAsmOffset(getConfigb("asm.offset"));
settings.setAsmDescribe(getConfigb("asm.describe"));
settings.setAsmStackPointer(getConfigb("asm.stackptr"));
settings.setAsmBytes(getConfigb("asm.bytes"));
settings.setAsmBytespace(getConfigb("asm.bytespace"));
settings.setAsmLBytes(getConfigb("asm.lbytes"));
settings.setAsmSyntax(getConfig("asm.syntax"));
settings.setAsmUppercase(getConfigb("asm.ucase"));
settings.setAsmBBLine(getConfigb("asm.bbline"));
}
QString CutterCore::getConfig(const QString &k)
@ -510,9 +548,9 @@ void CutterCore::setOptions(QString key)
void CutterCore::setCPU(QString arch, QString cpu, int bits, bool temporary)
{
config("asm.arch", arch);
config("asm.cpu", cpu);
config("asm.bits", bits);
setConfig("asm.arch", arch);
setConfig("asm.cpu", cpu);
setConfig("asm.bits", bits);
if (!temporary)
{
default_arch = arch;
@ -524,11 +562,11 @@ void CutterCore::setCPU(QString arch, QString cpu, int bits, bool temporary)
void CutterCore::setDefaultCPU()
{
if (!default_arch.isEmpty())
config("asm.arch", default_arch);
setConfig("asm.arch", default_arch);
if (!default_cpu.isEmpty())
config("asm.cpu", default_cpu);
setConfig("asm.cpu", default_cpu);
if (default_bits)
config("asm.bits", QString::number(default_bits));
setConfig("asm.bits", QString::number(default_bits));
}
QString CutterCore::assemble(const QString &code)
@ -697,60 +735,55 @@ void CutterCore::getOpcodes()
void CutterCore::setSettings()
{
config("scr.color", "false");
config("scr.interactive", "false");
config("asm.lines", "false");
setConfig("scr.color", false);
setConfig("scr.interactive", false);
setConfig("asm.lines", false);
// Intredazting...
//config("asm.linesright", "true");
//config("asm.lineswidth", "15");
//config("asm.functions", "false");
config("hex.pairs", "false");
config("asm.bytespace", "true");
config("asm.cmtflgrefs", "false");
config("asm.cmtright", "true");
config("asm.cmtcol", "70");
config("asm.xrefs", "false");
config("asm.fcnlines", "false");
//setConfig("asm.linesright", "true");
//setConfig("asm.lineswidth", "15");
//setConfig("asm.functions", "false");
setConfig("hex.pairs", false);
setConfig("asm.cmtflgrefs", false);
setConfig("asm.cmtright", true);
setConfig("asm.cmtcol", 70);
setConfig("asm.xrefs", false);
setConfig("asm.fcnlines", false);
config("asm.tabs", "5");
config("asm.tabsonce", "true");
config("asm.tabsoff", "5");
config("asm.nbytes", "10");
config("asm.midflags", "2");
//config("asm.bbline", "true");
setConfig("asm.tabs", 5);
setConfig("asm.tabsonce", true);
setConfig("asm.tabsoff", 5);
setConfig("asm.nbytes", 10);
setConfig("asm.midflags", 2);
//setConfig("asm.bbline", "true");
config("anal.hasnext", "true");
config("asm.fcncalls", "false");
config("asm.calls", "false");
config("asm.lines.call", "false");
config("asm.flgoff", "true");
config("anal.autoname", "true");
// Required for consistency with GUI checkboxes
config("asm.esil", "false");
config("asm.pseudo", "false");
setConfig("anal.hasnext", true);
setConfig("asm.fcncalls", false);
setConfig("asm.calls", false);
setConfig("asm.lines.call", false);
setConfig("asm.flgoff", true);
setConfig("anal.autoname", true);
// Highlight current node in graphviz
config("graph.gv.current", "true");
setConfig("graph.gv.current", true);
// Fucking pancake xD
config("cfg.fortunes.tts", "false");
setConfig("cfg.fortunes.tts", false);
// Experimenting with asm options
//config("asm.spacy", "true"); // We need to handle blank lines on scroll
//config("asm.section", "true"); // Breaks the disasm and navigation
//config("asm.invhex", "true"); // Needs further testing
//config("asm.flags", "false"); // Add with default true in future
//setConfig("asm.spacy", "true"); // We need to handle blank lines on scroll
//setConfig("asm.section", "true"); // Breaks the disasm and navigation
//setConfig("asm.invhex", "true"); // Needs further testing
//setConfig("asm.flags", "false"); // Add with default true in future
// Used by the HTML5 graph
config("http.cors", "true");
config("http.sandbox", "false");
setConfig("http.cors", true);
setConfig("http.sandbox", false);
//config("http.port", "14170");
// Temporary fixes
//config("http.root","/usr/local/share/radare2/last/www");
//config("http.root","/usr/local/radare2/osx/share/radare2/1.1.0-git/www");
//config("bin.rawstr", "true");
//setConfig("http.root","/usr/local/share/radare2/last/www");
//setConfig("http.root","/usr/local/radare2/osx/share/radare2/1.1.0-git/www");
//setConfig("bin.rawstr", "true");
// Graph colors and design
cmd("ec graph.true rgb:88FF88");

View File

@ -208,10 +208,16 @@ public:
void seek(ut64 offset);
ut64 math(const QString &expr);
QString itoa(ut64 num, int rdx = 16);
QString config(const QString &k, const QString &v = NULL);
int config(const QString &k, int v);
void setConfig(const QString &k, const QString &v);
void setConfig(const QString &k, int v);
void setConfig(const QString &k, bool v);
void setConfig(const QString &k, const char *v) { setConfig(k, QString(v)); }
int getConfigi(const QString &k);
bool getConfigb(const QString &k);
QString getConfig(const QString &k);
QString assemble(const QString &code);
QString disassemble(const QString &hex);
QString disassembleSingleInstruction(RVA addr);
@ -268,6 +274,11 @@ public:
void addFlag(RVA offset, QString name, RVA size);
void triggerAsmOptionsChanged();
void resetDefaultAsmOptions();
void saveDefaultAsmOptions();
RCoreLocked core() const;
/* fields */
@ -280,6 +291,11 @@ signals:
void flagsChanged();
void commentsChanged();
/*!
* emitted when config regarding disassembly display changes
*/
void asmOptionsChanged();
public slots:
private:

View File

@ -73,7 +73,8 @@ SOURCES += \
dialogs/flagdialog.cpp \
widgets/DisassemblerGraphView.cpp \
widgets/MemoryWidget.cpp \
utils/RichTextPainter.cpp
utils/RichTextPainter.cpp \
dialogs/asmoptionsdialog.cpp
HEADERS += \
mainwindow.h \
@ -117,7 +118,9 @@ HEADERS += \
widgets/DisassemblerGraphView.h \
widgets/MemoryWidget.h \
utils/RichTextPainter.h \
utils/CachedFontMetrics.h
utils/CachedFontMetrics.h \
dialogs/asmoptionsdialog.h
FORMS += \
mainwindow.ui \
newfiledialog.ui \
@ -143,6 +146,7 @@ FORMS += \
widgets/consolewidget.ui \
widgets/entrypointwidget.ui \
dialogs/flagdialog.ui \
dialogs/asmoptionsdialog.ui \
widgets/MemoryWidget.ui
RESOURCES += \

View File

@ -0,0 +1,155 @@
#include "settings.h"
#include "asmoptionsdialog.h"
#include "ui_asmoptionsdialog.h"
#include "helpers.h"
AsmOptionsDialog::AsmOptionsDialog(CutterCore *core, QWidget *parent) : QDialog(parent), ui(new Ui::AsmOptionsDialog)
{
this->core = core;
ui->setupUi(this);
ui->buttonBox->addButton(tr("Save as Defaults"), QDialogButtonBox::ButtonRole::ApplyRole);
ui->syntaxComboBox->blockSignals(true);
for(const auto &syntax : core->cmdList("e asm.syntax=?"))
ui->syntaxComboBox->addItem(syntax, syntax);
ui->syntaxComboBox->blockSignals(false);
updateFromVars();
}
AsmOptionsDialog::~AsmOptionsDialog()
{
delete ui;
}
void AsmOptionsDialog::updateFromVars()
{
qhelpers::setCheckedWithoutSignals(ui->esilCheckBox, core->getConfigb("asm.esil"));
qhelpers::setCheckedWithoutSignals(ui->pseudoCheckBox, core->getConfigb("asm.pseudo"));
qhelpers::setCheckedWithoutSignals(ui->offsetCheckBox, core->getConfigb("asm.offset"));
qhelpers::setCheckedWithoutSignals(ui->describeCheckBox, core->getConfigb("asm.describe"));
qhelpers::setCheckedWithoutSignals(ui->stackpointerCheckBox, core->getConfigb("asm.stackptr"));
bool bytesEnabled = core->getConfigb("asm.bytes");
qhelpers::setCheckedWithoutSignals(ui->bytesCheckBox, bytesEnabled);
qhelpers::setCheckedWithoutSignals(ui->bytespaceCheckBox, core->getConfigb("asm.bytespace"));
ui->bytespaceCheckBox->setEnabled(bytesEnabled);
qhelpers::setCheckedWithoutSignals(ui->lbytesCheckBox, core->getConfigb("asm.lbytes"));
ui->lbytesCheckBox->setEnabled(bytesEnabled);
QString currentSyntax = core->getConfig("asm.syntax");
for (int i = 0; i < ui->syntaxComboBox->count(); i++)
{
if (ui->syntaxComboBox->itemData(i) == currentSyntax)
{
ui->syntaxComboBox->blockSignals(true);
ui->syntaxComboBox->setCurrentIndex(i);
ui->syntaxComboBox->blockSignals(false);
break;
}
}
qhelpers::setCheckedWithoutSignals(ui->uppercaseCheckBox, core->getConfigb("asm.ucase"));
qhelpers::setCheckedWithoutSignals(ui->bblineCheckBox, core->getConfigb("asm.bbline"));
}
void AsmOptionsDialog::saveAsDefault()
{
core->saveDefaultAsmOptions();
}
void AsmOptionsDialog::resetToDefault()
{
core->resetDefaultAsmOptions();
updateFromVars();
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_esilCheckBox_toggled(bool checked)
{
core->setConfig("asm.esil", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_pseudoCheckBox_toggled(bool checked)
{
core->setConfig("asm.pseudo", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_offsetCheckBox_toggled(bool checked)
{
core->setConfig("asm.offset", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_describeCheckBox_toggled(bool checked)
{
core->setConfig("asm.describe", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_stackpointerCheckBox_toggled(bool checked)
{
core->setConfig("asm.stackptr", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_bytesCheckBox_toggled(bool checked)
{
core->setConfig("asm.bytes", checked);
ui->bytespaceCheckBox->setEnabled(checked);
ui->lbytesCheckBox->setEnabled(checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_bytespaceCheckBox_toggled(bool checked)
{
core->setConfig("asm.bytespace", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_lbytesCheckBox_toggled(bool checked)
{
core->setConfig("asm.lbytes", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_syntaxComboBox_currentIndexChanged(int index)
{
core->setConfig("asm.syntax", ui->syntaxComboBox->itemData(index).toString().toUtf8().constData());
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_uppercaseCheckBox_toggled(bool checked)
{
core->setConfig("asm.ucase", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_bblineCheckBox_toggled(bool checked)
{
core->setConfig("asm.bbline", checked);
core->triggerAsmOptionsChanged();
}
void AsmOptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
{
switch (ui->buttonBox->buttonRole(button))
{
case QDialogButtonBox::ButtonRole::ApplyRole:
saveAsDefault();
break;
case QDialogButtonBox::ButtonRole::ResetRole:
resetToDefault();
break;
default:
break;
}
}

View File

@ -0,0 +1,49 @@
#ifndef ASMOPTIONSDIALOG_H
#define ASMOPTIONSDIALOG_H
#include <QDialog>
#include <QPushButton>
#include "cutter.h"
namespace Ui
{
class AsmOptionsDialog;
}
class AsmOptionsDialog : public QDialog
{
Q_OBJECT
public:
explicit AsmOptionsDialog(CutterCore *core, QWidget *parent = nullptr);
~AsmOptionsDialog();
private:
CutterCore *core;
Ui::AsmOptionsDialog *ui;
void updateFromVars();
void saveAsDefault();
void resetToDefault();
private slots:
void on_esilCheckBox_toggled(bool checked);
void on_pseudoCheckBox_toggled(bool checked);
void on_offsetCheckBox_toggled(bool checked);
void on_describeCheckBox_toggled(bool checked);
void on_stackpointerCheckBox_toggled(bool checked);
void on_bytesCheckBox_toggled(bool checked);
void on_bytespaceCheckBox_toggled(bool checked);
void on_lbytesCheckBox_toggled(bool checked);
void on_syntaxComboBox_currentIndexChanged(int index);
void on_uppercaseCheckBox_toggled(bool checked);
void on_bblineCheckBox_toggled(bool checked);
void on_buttonBox_clicked(QAbstractButton *button);
};
#endif //ASMOPTIONSDIALOG_H

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AsmOptionsDialog</class>
<widget class="QDialog" name="AsmOptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>415</width>
<height>368</height>
</rect>
</property>
<property name="windowTitle">
<string>Disassembly Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<item>
<widget class="QCheckBox" name="esilCheckBox">
<property name="text">
<string>Show ESIL instead of assembly (asm.esil)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="pseudoCheckBox">
<property name="text">
<string>Show pseudocode instead of assembly (asm.pseudo)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="offsetCheckBox">
<property name="text">
<string>Show offsets (asm.offset)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="describeCheckBox">
<property name="text">
<string>Show opcode description (asm.describe)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="stackpointerCheckBox">
<property name="text">
<string>Show stack pointer (asm.stackptr)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="bytesCheckBox">
<property name="text">
<string>Show bytes (asm.bytes)</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>16</number>
</property>
<item>
<widget class="QCheckBox" name="bytespaceCheckBox">
<property name="text">
<string>Separate bytes with whitespace (asm.bytespace)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="lbytesCheckBox">
<property name="text">
<string>Align bytes to the left (asm.lbytes)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="syntaxLabel">
<property name="text">
<string>Syntax (asm.syntax):</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="syntaxComboBox"/>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="uppercaseCheckBox">
<property name="text">
<string>Uppercase syntax (asm.ucase)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="bblineCheckBox">
<property name="text">
<string>Show empty line after every basic block (asm.bbline)</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
</layout>
<action name="actionSaveAsDefault">
<property name="text">
<string>Save as Default</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -7,6 +7,7 @@
#include <QTreeWidget>
#include <QString>
#include <QAbstractItemView>
#include <QAbstractButton>
static QAbstractItemView::ScrollMode scrollMode()
@ -84,4 +85,12 @@ namespace qhelpers
tw->setVerticalScrollMode(scrollMode());
}
void setCheckedWithoutSignals(QAbstractButton *button, bool checked)
{
bool blocked = button->signalsBlocked();
button->blockSignals(true);
button->setChecked(checked);
button->blockSignals(blocked);
}
} // end namespace

View File

@ -9,6 +9,7 @@ class QString;
class QTreeWidget;
class QTreeWidgetItem;
class QAbstractItemView;
class QAbstractButton;
namespace qhelpers
{
@ -23,6 +24,8 @@ namespace qhelpers
const QString &str3 = QString(), const QString &str4 = QString(), const QString &str5 = QString());
void setVerticalScrollMode(QAbstractItemView *tw);
void setCheckedWithoutSignals(QAbstractButton *button, bool checked);
}
#endif // HELPERS_H

View File

@ -4,6 +4,7 @@
#include "dialogs/commentsdialog.h"
#include "dialogs/aboutdialog.h"
#include "dialogs/renamedialog.h"
#include "dialogs/asmoptionsdialog.h"
#include "helpers.h"
#include <QComboBox>
@ -181,27 +182,6 @@ void MainWindow::initUI()
addToolBarBreak(Qt::TopToolBarArea);
addToolBar(graphicsBar);
// Asm syntaxes
QList<QString> list = core->cmd("e asm.syntax =?").split("\n");
QString checked = core->getConfig("asm.syntax");
for (QString syntax : list)
{
if (syntax == "")
{
break;
}
QAction *action = new QAction(ui->menuAsm_syntax);
action->setText(syntax);
action->setCheckable(true);
if (syntax == checked)
{
action->setChecked(true);
}
connect(action, SIGNAL(triggered()), this, SLOT(actionAsm_syntax_triggered()));
asmSyntaxes.append(action);
ui->menuAsm_syntax->addAction(action);
}
/*
* Dock Widgets
*/
@ -388,63 +368,6 @@ void MainWindow::finalizeOpen()
notepadDock->highlightPreview();
}
void MainWindow::applySettings()
{
Settings settings;
// Show asm bytes
if (settings.getAsmBytes())
{
core->config("asm.bytes", "true");
core->config("asm.cmtcol", "100");
}
else
{
core->config("asm.bytes", "false");
core->config("asm.cmtcol", "70");
}
// Show opcode description
if (settings.getOpcodeDescription())
{
core->config("asm.describe", "true");
}
else
{
core->config("asm.describe", "false");
}
// Show stack pointer
if (settings.getStackPointer())
{
core->config("asm.stackptr", "true");
}
else
{
core->config("asm.stackptr", "false");
}
// Show uppercase dasm
if (settings.getUppercaseDisas())
{
core->config("asm.ucase", "true");
}
else
{
core->config("asm.ucase", "false");
}
// Show spaces in dasm
if (settings.getSpacy())
{
core->config("asm.bbline", "true");
}
else
{
core->config("asm.bbline", "false");
}
}
void MainWindow::saveProject()
{
QString project_name = qhelpers::uniqueProjectName(filename);
@ -1094,40 +1017,8 @@ void MainWindow::on_actionRefresh_contents_triggered()
refreshVisibleDockWidgets();
}
void MainWindow::on_actionDisplay_Esil_triggered()
void MainWindow::on_actionAsmOptions_triggered()
{
int esil = this->core->getConfigi("asm.esil");
core->config("asm.esil", !esil);
refreshVisibleDockWidgets();
}
void MainWindow::on_actionDisplay_Pseudocode_triggered()
{
int pseudo = this->core->getConfigi("asm.pseudo");
core->config("asm.pseudo", !pseudo);
refreshVisibleDockWidgets();
}
void MainWindow::on_actionDisplay_Offsets_triggered()
{
bool checked = ui->actionDisplay_Offsets->isChecked();
memoryDock->showOffsets(checked);
refreshVisibleDockWidgets();
}
void MainWindow::actionAsm_syntax_triggered()
{
QObject *sender = QObject::sender();
// Uncheck every other choices
for (QAction *action : asmSyntaxes)
{
action->setChecked(false);
}
// Check selected choice
QAction *action = (QAction *) sender;
action->setChecked(true);
// Set r2 config
core->config("asm.syntax", action->text());
// Refresh views
refreshVisibleDockWidgets();
auto dialog = new AsmOptionsDialog(core, this);
dialog->show();
}

View File

@ -57,8 +57,6 @@ public:
void initUI();
void finalizeOpen();
void applySettings();
void saveProject();
void start_web_server();
@ -173,13 +171,7 @@ private slots:
void on_actionRefresh_contents_triggered();
void on_actionDisplay_Esil_triggered();
void on_actionDisplay_Pseudocode_triggered();
void on_actionDisplay_Offsets_triggered();
void actionAsm_syntax_triggered();
void on_actionAsmOptions_triggered();
private:
QDockWidget *asmDock;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1013</width>
<height>686</height>
<height>606</height>
</rect>
</property>
<property name="sizePolicy">
@ -20,7 +20,7 @@
<string notr="true">Cutter</string>
</property>
<property name="windowIcon">
<iconset resource="resources.qrc">
<iconset>
<normaloff>:/img/logo-small.png</normaloff>:/img/logo-small.png</iconset>
</property>
<property name="styleSheet">
@ -159,7 +159,7 @@ border-top: 0px;
<x>0</x>
<y>0</y>
<width>1013</width>
<height>20</height>
<height>22</height>
</rect>
</property>
<property name="defaultUp">
@ -173,8 +173,8 @@ border-top: 0px;
<rect>
<x>273</x>
<y>136</y>
<width>148</width>
<height>167</height>
<width>173</width>
<height>181</height>
</rect>
</property>
<property name="title">
@ -204,11 +204,6 @@ border-top: 0px;
<property name="tabsOnTop" stdset="0">
<bool>false</bool>
</property>
<widget class="QMenu" name="menuAsm_syntax">
<property name="title">
<string>Asm syntax</string>
</property>
</widget>
<addaction name="actionRefresh_contents"/>
<addaction name="separator"/>
<addaction name="actionDefaut"/>
@ -220,10 +215,7 @@ border-top: 0px;
<addaction name="actionWhite_Theme"/>
<addaction name="actionDark_Theme"/>
<addaction name="separator"/>
<addaction name="actionDisplay_Esil"/>
<addaction name="actionDisplay_Pseudocode"/>
<addaction name="actionDisplay_Offsets"/>
<addaction name="menuAsm_syntax"/>
<addaction name="actionAsmOptions"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@ -968,6 +960,11 @@ QToolButton .svg-icon path {
<string>Display offsets</string>
</property>
</action>
<action name="actionAsmOptions">
<property name="text">
<string>Disassembly Options</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -49,14 +49,6 @@ OptionsDialog::OptionsDialog(MainWindow *main):
for (auto plugin : main->core->getRBinPluginDescriptions("bin"))
ui->formatComboBox->addItem(plugin.name, QVariant::fromValue(plugin));
// Restore settings
QSettings settings;
ui->bytesCheckBox->setChecked(settings.value("bytes").toBool());
ui->descriptionCheckBox->setChecked(settings.value("describe").toBool());
ui->stackCheckBox->setChecked(settings.value("stackptr").toBool());
ui->ucaseCheckBox->setChecked(settings.value("ucase").toBool());
ui->spacyCheckBox->setChecked(settings.value("bbline").toBool());
ui->hideFrame->setVisible(false);
ui->analoptionsFrame->setVisible(false);
@ -143,19 +135,9 @@ void OptionsDialog::setupAndStartAnalysis(int level, QList<QString> advanced)
ui->statusLabel->setText(tr("Starting analysis"));
//ui->progressBar->setValue(5);
// Save options in settings
Settings settings;
settings.setAsmBytes(ui->bytesCheckBox->isChecked());
settings.setOpcodeDescription(ui->descriptionCheckBox->isChecked());
settings.setStackPointer(ui->stackCheckBox->isChecked());
settings.setUppercaseDisas(ui->ucaseCheckBox->isChecked());
settings.setSpacy(ui->spacyCheckBox->isChecked());
main->initUI();
// Apply options set above in MainWindow
main->applySettings();
main->core->resetDefaultAsmOptions();
// Threads stuff
// connect signal/slot

View File

@ -406,67 +406,14 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);
color: rgb(0, 0, 0);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="formAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="11" column="0">
<widget class="QCheckBox" name="binCheckBox">
<property name="text">
<string>Load bin information</string>
@ -476,7 +423,7 @@ color: rgb(0, 0, 0);</string>
</property>
</widget>
</item>
<item row="12" column="0">
<item>
<widget class="QCheckBox" name="vaCheckBox">
<property name="styleSheet">
<string notr="true"/>
@ -489,70 +436,6 @@ color: rgb(0, 0, 0);</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="spacyCheckBox">
<property name="text">
<string>Add space after calls</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QCheckBox" name="bytesCheckBox">
<property name="text">
<string>Display asm bytes</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="formAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QCheckBox" name="descriptionCheckBox">
<property name="text">
<string>Show opcode description</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="stackCheckBox">
<property name="text">
<string>Show stack pointer</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="ucaseCheckBox">
<property name="text">
<string>Uppercase disassembly</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -26,13 +26,13 @@ void RadareWebServer::start()
// pretty sure now cutter runs as AppImage
//QString defaultPath("/usr/share/radare2/1.5.0-git/www");
QString defaultHttpRoot(core->config("http.root"));
QString defaultHttpRoot(core->getConfig("http.root"));
if (defaultHttpRoot.startsWith("/usr"))
{
QString path(QCoreApplication::applicationDirPath());
path.replace("bin/", defaultHttpRoot.remove("/usr"));
core->config("http.root", path);
core->setConfig("http.root", path);
}
}

View File

@ -10,20 +10,38 @@ private:
QSettings settings;
public:
bool getAsmBytes() const { return settings.value("bytes", false).toBool(); }
void setAsmBytes(bool v) { settings.setValue("bytes", v); }
bool getAsmESIL() const { return settings.value("asm.esil", false).toBool(); }
void setAsmESIL(bool v) { settings.setValue("asm.esil", v); }
bool getOpcodeDescription() const { return settings.value("describe", false).toBool(); }
void setOpcodeDescription(bool v) { settings.setValue("describe", v); }
bool getAsmPseudo() const { return settings.value("asm.pseudo", false).toBool(); }
void setAsmPseudo(bool v) { settings.setValue("asm.pseudo", v); }
bool getStackPointer() const { return settings.value("stackptr", false).toBool(); }
void setStackPointer(bool v) { settings.setValue("stackptr", v); }
bool getAsmOffset() const { return settings.value("asm.offset", true).toBool(); }
void setAsmOffset(bool v) { settings.setValue("asm.offset", v); }
bool getUppercaseDisas() const { return settings.value("ucase", false).toBool(); }
void setUppercaseDisas(bool v) { settings.setValue("ucase", v); }
bool getAsmDescribe() const { return settings.value("asm.describe", false).toBool(); }
void setAsmDescribe(bool v) { settings.setValue("asm.describe", v); }
bool getSpacy() const { return settings.value("spacy", false).toBool(); }
void setSpacy(bool v) { settings.setValue("bbline", v); }
bool getAsmStackPointer() const { return settings.value("asm.stackptr", false).toBool(); }
void setAsmStackPointer(bool v) { settings.setValue("asm.stackptr", v); }
bool getAsmBytes() const { return settings.value("asm.bytes", false).toBool(); }
void setAsmBytes(bool v) { settings.setValue("asm.bytes", v); }
bool getAsmBytespace() const { return settings.value("asm.bytespace", false).toBool(); }
void setAsmBytespace(bool v) { settings.setValue("asm.bytespace", v); }
bool getAsmLBytes() const { return settings.value("asm.lbytes", true).toBool(); }
void setAsmLBytes(bool v) { settings.setValue("asm.lbytes", v); }
QString getAsmSyntax() const { return settings.value("asm.syntax", "intel").toString(); }
void setAsmSyntax(const QString &v) { settings.setValue("asm.syntax", v); }
bool getAsmUppercase() const { return settings.value("asm.ucase", false).toBool(); }
void setAsmUppercase(bool v) { settings.setValue("asm.ucase", v); }
bool getAsmBBLine() const { return settings.value("asm.bbline", false).toBool(); }
void setAsmBBLine(bool v) { settings.setValue("asm.bbline", v); }
};
#endif // SETTINGS_H

View File

@ -104,20 +104,8 @@ MemoryWidget::MemoryWidget(MainWindow *main) :
QMenu *memMenu = new QMenu();
ui->memSettingsButton_2->addAction(ui->actionSettings_menu_1);
memMenu->addAction(ui->actionSettings_menu_1);
QMenu *hideSide = memMenu->addMenu("Show/Hide");
hideSide->addAction(ui->actionDisas_ShowHideBytes);
hideSide->addAction(ui->actionSeparate_bytes);
hideSide->addAction(ui->actionRight_align_bytes);
hideSide->addSeparator();
hideSide->addAction(ui->actionDisasSwitch_case);
hideSide->addAction(ui->actionSeparate_disasm_calls);
hideSide->addAction(ui->actionShow_stack_pointer);
ui->memSettingsButton_2->setMenu(memMenu);
// Disable bytes options by default as bytes are not shown
ui->actionSeparate_bytes->setDisabled(true);
ui->actionRight_align_bytes->setDisabled(true);
// Event filter to intercept double clicks in the textbox
ui->disasTextEdit_2->viewport()->installEventFilter(this);
@ -200,6 +188,7 @@ MemoryWidget::MemoryWidget(MainWindow *main) :
connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(on_cursorAddressChanged(RVA)));
connect(main->core, SIGNAL(flagsChanged()), this, SLOT(updateViews()));
connect(main->core, SIGNAL(commentsChanged()), this, SLOT(updateViews()));
connect(main->core, SIGNAL(asmOptionsChanged()), this, SLOT(updateViews()));
fillPlugins();
}
@ -889,15 +878,15 @@ void MemoryWidget::on_hexHexText_2_selectionChanged()
QString arch = ui->hexArchComboBox_2->currentText();
QString bits = ui->hexBitsComboBox_2->currentText();
QString oarch = this->main->core->config("asm.arch");
QString obits = this->main->core->config("asm.bits");
QString oarch = this->main->core->getConfig("asm.arch");
QString obits = this->main->core->getConfig("asm.bits");
this->main->core->config("asm.arch", arch);
this->main->core->config("asm.bits", bits);
this->main->core->setConfig("asm.arch", arch);
this->main->core->setConfig("asm.bits", bits);
QString str = this->main->core->cmd("pad " + sel_text);
this->hexDisasTextEdit->setPlainText(str);
this->main->core->config("asm.arch", oarch);
this->main->core->config("asm.bits", obits);
this->main->core->setConfig("asm.arch", oarch);
this->main->core->setConfig("asm.bits", obits);
//qDebug() << "Selected Arch: " << arch;
//qDebug() << "Selected Bits: " << bits;
//qDebug() << "Selected Text: " << sel_text;
@ -1040,14 +1029,6 @@ void MemoryWidget::showDisasContextMenu(const QPoint &pt)
menu->addSeparator();
menu->addAction(ui->actionXRefs);
menu->addSeparator();
menu->addAction(ui->actionDisas_ShowHideBytes);
menu->addAction(ui->actionSeparate_bytes);
menu->addAction(ui->actionRight_align_bytes);
menu->addSeparator();
menu->addAction(ui->actionDisasSwitch_case);
menu->addAction(ui->actionSeparate_disasm_calls);
menu->addAction(ui->actionShow_stack_pointer);
menu->addSeparator();
menu->addAction(ui->actionDisasCopy_All);
menu->addAction(ui->actionDisasCopy_Bytes);
menu->addAction(ui->actionDisasCopy_Disasm);
@ -1216,57 +1197,6 @@ void MemoryWidget::on_hexButton_2_clicked()
ui->memSideTabWidget_2->setCurrentIndex(1);
}
void MemoryWidget::on_actionDisas_ShowHideBytes_triggered()
{
this->main->core->cmd("e!asm.bytes");
if (this->main->core->cmd("e asm.bytes").trimmed() == "true")
{
ui->actionSeparate_bytes->setDisabled(false);
ui->actionRight_align_bytes->setDisabled(false);
this->main->core->config("asm.cmtcol", "100");
}
else
{
ui->actionSeparate_bytes->setDisabled(true);
ui->actionRight_align_bytes->setDisabled(true);
this->main->core->config("asm.cmtcol", "70");
}
this->refreshDisasm();
}
void MemoryWidget::on_actionDisasSwitch_case_triggered()
{
this->main->core->cmd("e!asm.ucase");
this->refreshDisasm();
}
void MemoryWidget::on_actionSeparate_bytes_triggered()
{
this->main->core->cmd("e!asm.bytespace");
this->refreshDisasm();
}
void MemoryWidget::on_actionRight_align_bytes_triggered()
{
this->main->core->cmd("e!asm.lbytes");
this->refreshDisasm();
}
void MemoryWidget::on_actionSeparate_disasm_calls_triggered()
{
this->main->core->cmd("e!asm.bbline");
this->refreshDisasm();
}
void MemoryWidget::on_actionShow_stack_pointer_triggered()
{
this->main->core->cmd("e!asm.stackptr");
this->refreshDisasm();
}
void MemoryWidget::on_graphButton_2_clicked()
{
ui->memTabWidget->setCurrentIndex(2);
@ -1357,43 +1287,43 @@ void MemoryWidget::on_actionFunctionsRename_triggered()
void MemoryWidget::on_action8columns_triggered()
{
this->main->core->config("hex.cols", "8");
this->main->core->setConfig("hex.cols", 8);
this->refreshHexdump();
}
void MemoryWidget::on_action16columns_triggered()
{
this->main->core->config("hex.cols", "16");
this->main->core->setConfig("hex.cols", 16);
this->refreshHexdump();
}
void MemoryWidget::on_action4columns_triggered()
{
this->main->core->config("hex.cols", "4");
this->main->core->setConfig("hex.cols", 4);
this->refreshHexdump();
}
void MemoryWidget::on_action32columns_triggered()
{
this->main->core->config("hex.cols", "32");
this->main->core->setConfig("hex.cols", 32);
this->refreshHexdump();
}
void MemoryWidget::on_action64columns_triggered()
{
this->main->core->config("hex.cols", "64");
this->main->core->setConfig("hex.cols", 64);
this->refreshHexdump();
}
void MemoryWidget::on_action2columns_triggered()
{
this->main->core->config("hex.cols", "2");
this->main->core->setConfig("hex.cols", 2);
this->refreshHexdump();
}
void MemoryWidget::on_action1column_triggered()
{
this->main->core->config("hex.cols", "1");
this->main->core->setConfig("hex.cols", 1);
this->refreshHexdump();
}
@ -1589,7 +1519,7 @@ void MemoryWidget::create_graph(QString off)
//QString fcn = this->main->core->cmdFunctionAt(off);
//this->main->add_debug_output("Graph Fcn: " + fcn);
ui->graphWebView->setUrl(QUrl("qrc:/graph/html/graph/index.html#" + off));
QString port = this->main->core->config("http.port");
QString port = this->main->core->getConfig("http.port");
ui->graphWebView->page()->runJavaScript(QString("r2.root=\"http://localhost:%1\"").arg(port));
QSettings settings;
if (settings.value("dark").toBool())
@ -1917,20 +1847,6 @@ void MemoryWidget::switchTheme(bool dark)
}
}
void MemoryWidget::on_opcodeDescButton_clicked()
{
if (ui->opcodeDescButton->isChecked())
{
ui->opcodeDescText->hide();
ui->opcodeDescButton->setArrowType(Qt::RightArrow);
}
else
{
ui->opcodeDescText->show();
ui->opcodeDescButton->setArrowType(Qt::DownArrow);
}
}
void MemoryWidget::selectHexPreview()
{
// Pre-select arch and bits in the hexdump sidebar
@ -2022,11 +1938,11 @@ void MemoryWidget::showOffsets(bool show)
if (show)
{
this->hexOffsetText->show();
main->core->config("asm.offset", 1);
main->core->setConfig("asm.offset", 1);
}
else
{
this->hexOffsetText->hide();
main->core->config("asm.offset", 0);
main->core->setConfig("asm.offset", 0);
}
}

View File

@ -149,7 +149,6 @@ private slots:
void on_actionDisasAdd_comment_triggered();
void on_actionAddFlag_triggered();
void on_actionFunctionsRename_triggered();
void on_actionDisas_ShowHideBytes_triggered();
void on_hexHexText_2_selectionChanged();
void on_hexArchComboBox_2_currentTextChanged(const QString &arg1);
@ -188,15 +187,9 @@ private slots:
void on_decoToolButton_clicked();
void on_previewToolButton_2_clicked();
void on_actionXRefs_triggered();
void on_actionDisasSwitch_case_triggered();
void on_actionSeparate_bytes_triggered();
void on_actionRight_align_bytes_triggered();
void on_actionSeparate_disasm_calls_triggered();
void on_actionShow_stack_pointer_triggered();
void on_copyMD5_clicked();
void on_copySHA1_clicked();
void on_simpleGrapgToolButton_clicked();
void on_opcodeDescButton_clicked();
void seek_back();
void on_memTabWidget_currentChanged(int index);
};

View File

@ -513,7 +513,7 @@ border-top: 0px;
<enum>QTabWidget::South</enum>
</property>
<property name="currentIndex">
<number>2</number>
<number>3</number>
</property>
<property name="documentMode">
<bool>false</bool>
@ -994,7 +994,7 @@ QToolTip {
<number>0</number>
</property>
<item>
<widget class="QWebEngineView" name="webSimpleGraph" native="true">
<widget class="QWebEngineView" name="webSimpleGraph">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -1015,7 +1015,7 @@ QToolTip {
font: 11pt &quot;Monaco&quot;;
}</string>
</property>
<property name="url" stdset="0">
<property name="url">
<url>
<string>about:blank</string>
</url>
@ -1290,16 +1290,16 @@ p, li { white-space: pre-wrap; }
<number>0</number>
</property>
<item>
<widget class="QWebEngineView" name="graphWebView" native="true">
<widget class="QWebEngineView" name="graphWebView">
<property name="contextMenuPolicy">
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="url" stdset="0">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
<property name="zoomFactor" stdset="0">
<property name="zoomFactor">
<double>1.000000000000000</double>
</property>
</widget>
@ -1394,7 +1394,7 @@ border-top: 0px;
<x>0</x>
<y>0</y>
<width>256</width>
<height>868</height>
<height>878</height>
</rect>
</property>
<property name="sizePolicy">
@ -1698,7 +1698,7 @@ QToolTip {
<number>0</number>
</property>
<item>
<widget class="QWebEngineView" name="fcnWebView" native="true">
<widget class="QWebEngineView" name="fcnWebView">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -1717,7 +1717,7 @@ QToolTip {
<height>250</height>
</size>
</property>
<property name="url" stdset="0">
<property name="url">
<url>
<string>qrc:/html/fcn_graph.html</string>
</url>
@ -1747,7 +1747,7 @@ QToolTip {
<number>0</number>
</property>
<item>
<widget class="QWebEngineView" name="radarGraphWebView" native="true">
<widget class="QWebEngineView" name="radarGraphWebView">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -1766,7 +1766,7 @@ QToolTip {
<height>250</height>
</size>
</property>
<property name="url" stdset="0">
<property name="url">
<url>
<string>qrc:/html/fcn_radar.html</string>
</url>
@ -2899,22 +2899,6 @@ QToolTip {
<string>Undefine</string>
</property>
</action>
<action name="actionDisas_ShowHideBytes">
<property name="text">
<string>Show/Hide bytes</string>
</property>
<property name="toolTip">
<string>Show/Hide bytes</string>
</property>
</action>
<action name="actionDisasSwitch_case">
<property name="text">
<string>Switch case</string>
</property>
<property name="toolTip">
<string>Switch case</string>
</property>
</action>
<action name="actionDisasCopy_All">
<property name="text">
<string>Copy all</string>
@ -3059,38 +3043,6 @@ QToolTip {
<string>XRefs</string>
</property>
</action>
<action name="actionSeparate_bytes">
<property name="text">
<string>Separate bytes</string>
</property>
<property name="toolTip">
<string>Separate bytes with space</string>
</property>
</action>
<action name="actionRight_align_bytes">
<property name="text">
<string>Right align bytes</string>
</property>
<property name="toolTip">
<string>Right align bytes</string>
</property>
</action>
<action name="actionSeparate_disasm_calls">
<property name="text">
<string>Separate disasm calls</string>
</property>
<property name="toolTip">
<string>Separate disasm calls</string>
</property>
</action>
<action name="actionShow_stack_pointer">
<property name="text">
<string>Show stack pointer</string>
</property>
<property name="toolTip">
<string>Show stack pointer</string>
</property>
</action>
<action name="actionAddFlag">
<property name="text">
<string>Add flag</string>

View File

@ -68,6 +68,8 @@ static const int invalidHistoryPos = -1;
static bool isForbidden(const QString &input)
{
return false;
static const QRegExp delimiters("[;&]");