WingHexExplorer2/src/dialog/finddialog.cpp

237 lines
7.5 KiB
C++

/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "finddialog.h"
#include "utilities.h"
#include <QButtonGroup>
#include <QDialogButtonBox>
#include <QLabel>
#include <QPushButton>
#include <QShortcut>
#include <QVBoxLayout>
#include "control/toast.h"
FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
: FramelessDialogBase(parent) {
_hexvalidator = new HexStringValidator(this);
auto widget = new QWidget(this);
auto layout = new QVBoxLayout(widget);
layout->addWidget(new QLabel(tr("Mode:"), this));
m_findMode = new QComboBox(this);
m_findMode->addItem(QStringLiteral("HEX"));
m_findMode->addItems(Utilities::getEncodings());
m_findMode->setCurrentIndex(1);
layout->addWidget(m_findMode);
layout->addSpacing(3);
layout->addWidget(new QLabel(tr("Content:"), this));
m_lineeditor = new QLineEdit(this);
layout->addWidget(m_lineeditor);
layout->addSpacing(3);
layout->addWidget(new QLabel(tr("EncBytes:"), this));
m_preview = new QTextEdit(this);
m_preview->setFocusPolicy(Qt::NoFocus);
m_preview->setReadOnly(true);
m_preview->setUndoRedoEnabled(false);
m_preview->setWordWrapMode(QTextOption::WordWrap);
m_preview->setAcceptRichText(false);
m_preview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
layout->addWidget(m_preview);
connect(m_lineeditor, &QLineEdit::textChanged, this,
[this](const QString &text) {
if (m_findMode->currentIndex()) {
auto encoding = m_findMode->currentText();
auto dbytes = Utilities::encodingString(text, encoding);
m_preview->setText(dbytes.toHex(' '));
} else {
m_preview->setText(text);
}
});
connect(m_findMode, &QComboBox::currentIndexChanged, this,
[this](int index) {
auto oldva = m_lineeditor->validator();
auto newva = index > 0 ? nullptr : _hexvalidator;
m_lineeditor->setValidator(newva);
if (oldva != newva) {
m_lineeditor->clear();
} else {
// force update
emit m_lineeditor->textChanged(m_lineeditor->text());
}
});
if (info.isStringFind) {
if (!info.encoding.isEmpty()) {
m_findMode->setCurrentText(info.encoding);
}
} else {
m_findMode->setCurrentIndex(0);
}
m_lineeditor->setText(info.str);
auto regionw = new QWidget(this);
auto regionLayout = new QHBoxLayout(regionw);
regionLayout->addWidget(new QLabel(tr("Region:"), regionw));
m_regionStart = new QtLongLongSpinBox(regionw);
Q_ASSERT(info.stop >= info.start);
m_regionStart->setRange(info.start, info.stop);
m_regionStart->setEnabled(false);
m_regionStart->setValue(info.start);
m_regionStart->setDisplayIntegerBase(16);
m_regionStart->setPrefix(QStringLiteral("0x"));
regionLayout->addWidget(m_regionStart, 1);
regionLayout->addWidget(new QLabel(QStringLiteral(" - "), regionw));
m_regionStop = new QtLongLongSpinBox(regionw);
m_regionStop->setRange(info.start, info.stop);
connect(m_regionStart, &QtLongLongSpinBox::valueChanged, m_regionStop,
&QtLongLongSpinBox::setMinimum);
m_regionStop->setEnabled(false);
m_regionStop->setValue(qMin(info.start + 1024 * 1024, info.stop));
m_regionStop->setDisplayIntegerBase(16);
m_regionStop->setPrefix(QStringLiteral("0x"));
regionLayout->addWidget(m_regionStop, 1);
auto group = new QButtonGroup(this);
group->setExclusive(true);
auto btnBox = new QWidget(this);
auto buttonLayout = new QHBoxLayout(btnBox);
buttonLayout->setSpacing(0);
int id = 0;
auto b = new QPushButton(tr("None"), this);
b->setCheckable(true);
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::None;
}
});
group->addButton(b, id++);
b->setEnabled(!info.isBigFile);
buttonLayout->addWidget(b);
b = new QPushButton(tr("Region"), this);
b->setCheckable(true);
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::Region;
}
regionw->setVisible(b);
regionw->setEnabled(b);
});
group->addButton(b, id++);
buttonLayout->addWidget(b);
b = new QPushButton(tr("BeforeCursor"), this);
b->setCheckable(true);
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::Foreword;
}
});
group->addButton(b, id++);
buttonLayout->addWidget(b);
b = new QPushButton(tr("AfterCursor"), this);
b->setCheckable(true);
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::Backword;
}
});
group->addButton(b, id++);
buttonLayout->addWidget(b);
b = new QPushButton(tr("Selection"), this);
b->setCheckable(true);
if (info.isSel) {
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::Selection;
}
});
} else {
b->setEnabled(false);
}
group->addButton(b, id++);
buttonLayout->addWidget(b);
group->button(info.isBigFile ? 1 : 0)->setChecked(true);
layout->addWidget(btnBox);
auto dbbox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(dbbox, &QDialogButtonBox::accepted, this, &FindDialog::on_accept);
connect(dbbox, &QDialogButtonBox::rejected, this, &FindDialog::on_reject);
auto key = QKeySequence(Qt::Key_Return);
auto s = new QShortcut(key, this);
connect(s, &QShortcut::activated, this, &FindDialog::on_accept);
layout->addWidget(regionw);
regionw->hide();
layout->addSpacing(20);
layout->addWidget(dbbox);
buildUpContent(widget);
this->setWindowTitle(tr("find"));
m_lineeditor->setFocus();
}
FindDialog::Result FindDialog::getResult() const { return _result; }
void FindDialog::on_accept() {
_result.isStringFind = m_findMode->currentIndex() > 0;
_result.str = m_lineeditor->text();
if (!_result.isStringFind) {
// check the last byte nibbles
if (std::next(_result.str.rbegin())->isSpace()) {
Toast::toast(this, NAMEICONRES("find"), tr("InvalidHexSeq"));
return;
}
}
if (m_regionStart->isEnabled()) {
_result.start = m_regionStart->value();
_result.stop = m_regionStop->value();
} else {
_result.start = 0;
_result.stop = 0;
}
_result.encoding = m_findMode->currentText();
done(1);
}
void FindDialog::on_reject() { done(0); }