WingHexExplorer2/src/dialog/mainwindow.cpp

4015 lines
136 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 "mainwindow.h"
#include "Qt-Advanced-Docking-System/src/DockAreaWidget.h"
#include "Qt-Advanced-Docking-System/src/DockFocusController.h"
#include "Qt-Advanced-Docking-System/src/DockSplitter.h"
#include "Qt-Advanced-Docking-System/src/DockWidgetTab.h"
#include "aboutsoftwaredialog.h"
#include "checksumdialog.h"
#include "class/appmanager.h"
#include "class/dockcomponentsfactory.h"
#include "class/eventfilter.h"
#include "class/inspectqtloghelper.h"
#include "class/languagemanager.h"
#include "class/layoutmanager.h"
#include "class/logger.h"
#include "class/pluginsystem.h"
#include "class/qkeysequences.h"
#include "class/richtextitemdelegate.h"
#include "class/scriptmachine.h"
#include "class/settingmanager.h"
#include "class/wingfiledialog.h"
#include "class/winginputdialog.h"
#include "class/wingmessagebox.h"
#include "class/wingupdater.h"
#include "control/toast.h"
#include "define.h"
#include "encodingdialog.h"
#include "fileinfodialog.h"
#include "finddialog.h"
#include "metadialog.h"
#include "settings/editorsettingdialog.h"
#include "settings/generalsettingdialog.h"
#include "settings/othersettingsdialog.h"
#include "settings/pluginsettingdialog.h"
#include "settings/scriptsettingdialog.h"
#include <QAction>
#include <QActionGroup>
#include <QClipboard>
#include <QDesktopServices>
#include <QGridLayout>
#include <QHeaderView>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QKeyEvent>
#include <QPainter>
#include <QPicture>
#include <QPushButton>
#include <QRadioButton>
#include <QScopeGuard>
#include <QScrollBar>
#include <QStatusBar>
#include <QTimer>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QStringDecoder>
#else
#include <QTextCodec>
#endif
constexpr auto EMPTY_FUNC = [] {};
MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
this->setUpdatesEnabled(false);
this->setMinimumSize(900, 800);
// recent file manager init
if (splash)
splash->setInfoText(tr("SetupRecent"));
m_recentMenu = new QMenu(this);
m_recentmanager = new RecentFileManager(m_recentMenu, false);
connect(m_recentmanager, &RecentFileManager::triggered, this,
[=](const RecentFileManager::RecentInfo &rinfo) {
AppManager::instance()->openFile(rinfo.fileName,
rinfo.isWorkSpace);
});
m_recentmanager->apply(this, SettingManager::instance().recentHexFiles());
if (splash)
splash->setInfoText(tr("SetupUI"));
// build up UI
buildUpRibbonBar();
auto cw = new QWidget(this);
cw->setSizePolicy(
QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
auto layout = new QVBoxLayout(cw);
layout->setContentsMargins(1, 0, 1, 0);
layout->setSpacing(0);
layout->addWidget(q_check_ptr(m_ribbon));
if (splash)
splash->setInfoText(tr("SetupDocking"));
buildUpDockSystem(cw);
layout->addWidget(m_dock, 1);
m_status = new QStatusBar(this);
// init statusbar
{
m_lblloc = new QLabel(QStringLiteral("(0,0)"), this);
auto l = new QLabel(tr("loc:"), this);
l->setMinimumWidth(50);
l->setAlignment(Qt::AlignCenter);
m_status->addWidget(l);
m_status->addWidget(m_lblloc);
l = new QLabel(tr("sel:"), this);
l->setMinimumWidth(50);
l->setAlignment(Qt::AlignCenter);
m_lblsellen = new QLabel(QStringLiteral("0 - 0x0"), this);
m_status->addWidget(l);
m_status->addWidget(m_lblsellen);
_status = new ScrollableLabel(m_status);
m_status->addPermanentWidget(_status);
auto separator = new QFrame(m_status);
separator->setFrameShape(QFrame::VLine);
separator->setFrameShadow(QFrame::Sunken);
m_status->addPermanentWidget(separator);
auto disableStyle =
QStringLiteral("border:none;background:transparent;");
m_sSaved = new QToolButton(this);
m_sSaved->setStyleSheet(disableStyle);
m_sSaved->setToolTip(tr("InfoSave"));
m_sSaved->setIcon(_infoSaved);
m_sSaved->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_status->addPermanentWidget(m_sSaved);
m_editStateWidgets << m_sSaved;
m_sReadWrite = new QToolButton(this);
m_sReadWrite->setStyleSheet(disableStyle);
m_sReadWrite->setToolTip(tr("ReadOnly"));
m_sReadWrite->setIcon(_infoWriteable);
m_sReadWrite->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_status->addPermanentWidget(m_sReadWrite);
m_editStateWidgets << m_sReadWrite;
auto ev = new EventFilter(QEvent::MouseButtonDblClick, m_status);
connect(ev, &EventFilter::eventTriggered, this,
[this](QObject *obj, QEvent *) {
if (obj == m_sLocked) {
if (m_sLocked->isEnabled()) {
m_iLocked->click();
}
} else if (obj == m_sCanOver) {
if (m_sCanOver->isEnabled()) {
m_iCanOver->click();
}
}
});
m_sLocked = new QToolButton(this);
m_sLocked->setStyleSheet(disableStyle);
m_sLocked->setToolTip(tr("SetLocked"));
m_sLocked->setIcon(_infoUnLock);
m_sLocked->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_sLocked->installEventFilter(ev);
m_status->addPermanentWidget(m_sLocked);
m_editStateWidgets << m_sLocked;
m_sCanOver = new QToolButton(this);
m_sCanOver->setStyleSheet(disableStyle);
m_sCanOver->setToolTip(tr("SetOver"));
m_sCanOver->setIcon(_infoCannotOver);
m_sCanOver->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_sCanOver->installEventFilter(ev);
m_status->addPermanentWidget(m_sCanOver);
m_editStateWidgets << m_sCanOver;
}
layout->addWidget(m_status);
buildUpContent(cw);
m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS)->setEnabled(false);
// ok, preparing for starting...
this->setWindowTitle(tr("WingHexExplorer"));
this->setWindowIcon(Utilities::isRoot()
? ICONRES(QStringLiteral("iconroot"))
: ICONRES(QStringLiteral("icon")));
auto &set = SettingManager::instance();
// launch logging system
if (splash)
splash->setInfoText(tr("LaunchingLog"));
auto &log = Logger::instance();
log.setLogLevel(Logger::Level(set.logLevel()));
connect(&log, &Logger::log, m_logbrowser, &QTextBrowser::append);
// check config writable
set.checkWriteableAndWarn();
// launch plugin system
if (splash)
splash->setInfoText(tr("SetupPluginSystem"));
auto &plg = PluginSystem::instance();
connect(&plg, &PluginSystem::pluginLoading, this,
[=](const QString &plgName) {
if (splash)
splash->setInfoText(tr("LoadingPlg:") + plgName);
});
plg.setMainWindow(this);
plg.loadAllPlugin();
// Don't setup it too early, because the plugin can register script
// functions. Code completions of them will be not worked out.
if (set.scriptEnabled()) {
auto &sm = ScriptMachine::instance();
auto smr = sm.init();
if (smr) {
ScriptMachine::RegCallBacks callbacks;
callbacks.getInputFn = [this]() -> QString {
return m_scriptConsole->getInput();
};
callbacks.clearFn = [this]() { m_scriptConsole->clearConsole(); };
callbacks.printMsgFn =
[this](const ScriptMachine::MessageInfo &message) {
m_scriptConsole->onOutput(message);
};
sm.registerCallBack(ScriptMachine::Interactive, callbacks);
callbacks.getInputFn = [this]() -> QString {
return WingInputDialog::getText(this, tr("InputRequest"),
tr("PleaseInput"));
};
callbacks.clearFn = [this]() { m_bgScriptOutput->clear(); };
callbacks.printMsgFn =
std::bind(&MainWindow::onOutputBgScriptOutput, this,
std::placeholders::_1);
sm.registerCallBack(ScriptMachine::Background, callbacks);
} else {
QMessageBox::critical(this, qAppName(),
tr("ScriptEngineInitFailed"));
set.setScriptEnabled(false);
set.save(SettingManager::SCRIPT);
throw CrashCode::ScriptInitFailed;
}
// At this time, AngelScript service plugin has started
if (splash)
splash->setInfoText(tr("SetupConsole"));
m_scriptConsole->init();
if (splash)
splash->setInfoText(tr("SetupScriptManager"));
if (splash)
splash->setInfoText(tr("SetupScriptService"));
m_scriptConsole->initOutput();
m_scriptConsole->setMode(QConsoleWidget::Input);
if (splash)
splash->setInfoText(tr("SetupScriptEditor"));
m_scriptDialog = new ScriptingDialog(this);
m_scriptDialog->initConsole();
}
// connect settings signals
connect(&set, &SettingManager::sigEditorfontSizeChanged, this,
[this](int v) {
auto views = m_views.keys();
for (auto &p : views) {
p->setFontSize(qreal(v));
}
});
connect(&set, &SettingManager::sigCopylimitChanged, this, [this](int v) {
auto views = m_views.keys();
for (auto &p : views) {
p->setCopyLimit(v);
}
});
connect(&set, &SettingManager::sigDecodeStrlimitChanged, this,
[this](int v) { _decstrlim = v; });
// ok, build up the dialog of setting
if (splash)
splash->setInfoText(tr("SetupSetDialog"));
buildUpSettingDialog();
// we start to installing plugin widgets
if (splash)
splash->setInfoText(tr("SetupPlgWidgets"));
installPluginEditorWidgets();
auto plgview = m_toolBtneditors.value(PLUGIN_VIEWS);
plgview->setEnabled(!plgview->menu()->isEmpty());
finishBuildDockSystem();
// load saved docking layout
if (splash)
splash->setInfoText(tr("SetupDockingLayout"));
_defaultLayout = m_dock->saveState();
m_leftViewArea = nullptr;
m_rightViewArea = nullptr;
m_topViewArea = nullptr;
m_bottomViewArea = nullptr;
m_dock->restoreState(set.dockLayout());
m_lastusedpath = set.lastUsedPath();
if (splash)
splash->setInfoText(tr("SetupWaiting"));
// others
_showtxt = new ShowTextDialog(this);
qApp->processEvents();
// update status
updateEditModeEnabled();
qApp->installEventFilter(this);
this->setUpdatesEnabled(true);
plg.dispatchEvent(IWingPlugin::RegisteredEvent::AppReady, {});
if (splash)
splash->setInfoText(tr("SetupFinished"));
}
MainWindow::~MainWindow() { Logger::instance().disconnect(); }
void MainWindow::buildUpRibbonBar() {
m_ribbon = new Ribbon(this);
loadCacheIcon();
using RibbonCatagories = WingHex::WingRibbonToolBoxInfo::RibbonCatagories;
RibbonCatagories catagories;
m_ribbonMaps[catagories.FILE] = buildFilePage(m_ribbon->addTab(tr("File")));
qApp->processEvents();
m_ribbonMaps[catagories.EDIT] = buildEditPage(m_ribbon->addTab(tr("Edit")));
qApp->processEvents();
m_ribbonMaps[catagories.VIEW] = buildViewPage(m_ribbon->addTab(tr("View")));
qApp->processEvents();
auto &set = SettingManager::instance();
if (set.scriptEnabled()) {
m_ribbonMaps[catagories.SCRIPT] =
buildScriptPage(m_ribbon->addTab(tr("Script")));
qApp->processEvents();
}
if (set.enablePlugin()) {
m_ribbonMaps[catagories.PLUGIN] =
buildPluginPage(m_ribbon->addTab(tr("Plugin")));
qApp->processEvents();
}
m_ribbonMaps[catagories.SETTING] =
buildSettingPage(m_ribbon->addTab(tr("Setting")));
qApp->processEvents();
m_ribbonMaps[catagories.ABOUT] =
buildAboutPage(m_ribbon->addTab(tr("About")));
qApp->processEvents();
connect(m_ribbon, &Ribbon::onDragDropFiles, this,
[=](const QStringList &files) {
auto app = AppManager::instance();
for (auto &f : files) {
app->openFile(f);
}
});
// check update if set
if (set.checkUpdate()) {
ExecAsync<int>(
[]() -> int {
bool ok = false;
auto newest = WingUpdater::checkUpdate(&ok);
if (ok) {
return newest ? 1 : 0;
} else {
return -1;
}
},
[this](int status) {
if (status == 0) {
WingMessageBox::warning(this, qAppName(),
tr("OlderVersion"));
}
});
}
}
void MainWindow::buildUpDockSystem(QWidget *container) {
Q_ASSERT(container);
using namespace ads;
CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig);
CDockManager::setConfigFlag(CDockManager::DragPreviewIsDynamic, true);
CDockManager::setConfigFlag(CDockManager::DragPreviewShowsContentPixmap,
false);
CDockManager::setConfigFlag(CDockManager::DragPreviewHasWindowFrame, false);
CDockManager::setConfigFlag(CDockManager::EqualSplitOnInsertion, true);
CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
CDockManager::setConfigFlag(CDockManager::DockAreaHideDisabledButtons,
true);
CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig);
qApp->processEvents();
ads::CDockComponentsFactory::setFactory(new DockComponentsFactory);
m_dock = new CDockManager;
m_dock->setStyleSheet(QString());
m_dock->setParent(this);
connect(m_dock, &CDockManager::focusedDockWidgetChanged, this,
[this](CDockWidget *old, CDockWidget *now) {
Q_UNUSED(old);
auto editview = qobject_cast<EditorView *>(now);
if (editview) {
_editorLock.lockForWrite();
swapEditor(m_curEditor, editview);
_editorLock.unlock();
} else {
m_findresult->setModel(_findEmptyResult);
m_bookmarks->setModel(_bookMarkEmpty);
m_metadatas->setModel(_metadataEmpty);
m_aDelBookMark->setEnabled(false);
m_aDelMetaData->setEnabled(false);
}
updateEditModeEnabled();
});
connect(m_dock, &CDockManager::stateRestored, this, [this]() {
// no allowing floating widgets
QList<CDockWidget *> _dws;
for (auto &dw : m_dock->dockWidgetsMap()) {
if (dw->dockAreaWidget() == nullptr) {
_dws.append(dw);
}
}
if (_dws.isEmpty()) {
return;
}
auto replaceDW = [this](CDockWidget *dw,
CDockAreaWidget *darea) -> CDockAreaWidget * {
m_dock->blockSignals(true);
m_dock->removeDockWidget(dw);
auto area =
m_dock->addDockWidget(ads::BottomDockWidgetArea, dw, darea);
m_dock->blockSignals(false);
dw->toggleView(false);
return area;
};
auto darea = m_dock->centralWidget()->dockAreaWidget();
auto dw = _dws.takeFirst();
darea = replaceDW(dw, darea);
for (auto &dw : _dws) {
replaceDW(dw, darea);
}
});
qApp->processEvents();
// add empty area
auto label = new QLabel(this);
// background image that idicates whether it's
// running under the admin/root previlige
QPicture backimg;
QPainter painter(&backimg);
painter.setOpacity(0.15);
painter.drawPixmap(0, 0,
QPixmap(Utilities::isRoot()
? NAMEICONRES(QStringLiteral("iconroot"))
: NAMEICONRES(QStringLiteral("icon"))));
label->setPicture(backimg);
label->setAlignment(Qt::AlignCenter);
qApp->processEvents();
CDockWidget *CentralDockWidget =
m_dock->createDockWidget(QStringLiteral("CentralWidget"));
CentralDockWidget->setWidget(label);
CentralDockWidget->setFeature(ads::CDockWidget::DockWidgetFocusable, false);
CentralDockWidget->setFeature(ads::CDockWidget::NoTab, true);
auto editorViewArea = m_dock->setCentralWidget(CentralDockWidget);
qApp->processEvents();
// build up basic docking widgets
auto bottomLeftArea =
buildUpFindResultDock(m_dock, ads::BottomDockWidgetArea);
qApp->processEvents();
auto splitter =
ads::internal::findParent<ads::CDockSplitter *>(editorViewArea);
if (splitter) {
constexpr auto bottomHeight = 300;
splitter->setSizes({height() - bottomHeight, bottomHeight});
}
qApp->processEvents();
auto rightArea =
buildUpLogDock(m_dock, ads::RightDockWidgetArea, editorViewArea);
qApp->processEvents();
splitter = ads::internal::findParent<ads::CDockSplitter *>(editorViewArea);
if (splitter) {
constexpr auto rightHeight = 450;
splitter->setSizes({width() - rightHeight, rightHeight});
}
m_rightViewArea = rightArea;
qApp->processEvents();
buildUpNumberShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
qApp->processEvents();
buildUpHexBookMarkDock(m_dock, ads::CenterDockWidgetArea, rightArea);
qApp->processEvents();
buildUpHexMetaDataDock(m_dock, ads::CenterDockWidgetArea, rightArea);
qApp->processEvents();
buildUpDecodingStrShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
qApp->processEvents();
ads::CDockAreaWidget *bottomRightArea;
if (SettingManager::instance().scriptEnabled()) {
bottomRightArea = buildUpScriptConsoleDock(
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
qApp->processEvents();
buildUpScriptBgOutputDock(m_dock, ads::CenterDockWidgetArea,
bottomRightArea);
qApp->processEvents();
buildUpHashResultDock(m_dock, ads::CenterDockWidgetArea,
bottomRightArea);
qApp->processEvents();
} else {
bottomRightArea = buildUpHashResultDock(
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
qApp->processEvents();
}
qApp->processEvents();
m_bottomViewArea = bottomRightArea;
}
void MainWindow::finishBuildDockSystem() {
// add empty action to ext
auto menu = m_toolBtneditors[MainWindow::ToolButtonIndex::OPEN_EXT]->menu();
if (menu->isEmpty()) {
auto a = newAction(tr("NoExtension"), EMPTY_FUNC);
a->setEnabled(false);
menu->addAction(a);
}
// set the first tab visible
for (auto &item : m_dock->openedDockAreas()) {
for (int i = 0; i < item->dockWidgetsCount(); ++i) {
qApp->processEvents();
auto d = item->dockWidget(i);
if (d->features().testFlag(ads::CDockWidget::NoTab)) {
continue;
}
item->setCurrentIndex(i);
break;
}
}
}
ads::CDockAreaWidget *MainWindow::buildUpLogDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
m_logbrowser = new QTextBrowser(this);
m_logbrowser->setFocusPolicy(Qt::StrongFocus);
m_logbrowser->setOpenExternalLinks(true);
m_logbrowser->setUndoRedoEnabled(false);
m_logbrowser->addAction(newAction(
ICONRES("copy"), tr("Copy"), [=]() { m_logbrowser->copy(); },
QKeySequence::Copy));
auto a = new QAction(this);
a->setSeparator(true);
m_logbrowser->addAction(a);
m_logbrowser->addAction(newAction(ICONRES(QStringLiteral("log")),
tr("ExportLog"),
&MainWindow::on_exportlog));
m_logbrowser->addAction(newAction(ICONRES(QStringLiteral("clearhis")),
tr("ClearLog"), &MainWindow::on_clslog));
m_logbrowser->setContextMenuPolicy(Qt::ActionsContextMenu);
auto dw =
buildDockWidget(dock, QStringLiteral("Log"), tr("Log"), m_logbrowser);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
_findEmptyResult = new FindResultModel(this);
m_findresult = new QTableViewExt(this);
m_findresult->setProperty("EditorView", quintptr(0));
Utilities::applyTableViewProperty(m_findresult);
m_findresult->setContextMenuPolicy(
Qt::ContextMenuPolicy::CustomContextMenu);
auto se = [=]() {
auto model = qobject_cast<FindResultModel *>(m_findresult->model());
if (model) {
m_find->setWindowTitle(tr("FindResult") + QStringLiteral(" (") +
model->encoding() + QStringLiteral(")"));
}
};
auto menu = new QMenu(tr("Encoding"), this);
menu->setIcon(ICONRES(QStringLiteral("encoding")));
auto aGroup = new QActionGroup(this);
auto langs = Utilities::getEncodings();
for (auto &l : langs) {
auto a = newCheckableAction(menu, l, [=]() {
auto model = qobject_cast<FindResultModel *>(m_findresult->model());
if (model) {
model->setEncoding(l);
se();
}
});
aGroup->addAction(a);
menu->addAction(a);
m_findEncoding.insert(l, a);
}
m_menuFind = new QMenu(m_findresult);
m_menuFind->addMenu(menu);
m_menuFind->addAction(
newAction(QStringLiteral("copy"), tr("Copy"), [this]() {
auto idx = m_findresult->currentIndex();
if (idx.isValid()) {
auto model =
qobject_cast<FindResultModel *>(m_findresult->model());
if (model) {
auto content = model->copyContent(idx);
qApp->clipboard()->setText(content);
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("CopyToClipBoard"));
}
}
}));
m_menuFind->addAction(newAction(QStringLiteral("export"),
tr("ExportFindResult"),
&MainWindow::on_exportfindresult));
m_menuFind->addAction(newAction(QStringLiteral("del"),
tr("ClearFindResult"),
&MainWindow::on_clearfindresult));
connect(m_findresult, &QTableViewExt::customContextMenuRequested, this,
[=](const QPoint &pos) {
m_menuFind->popup(m_findresult->viewport()->mapToGlobal(pos));
});
m_findresult->setItemDelegate(new RichTextItemDelegate(m_findresult));
m_findresult->setModel(_findEmptyResult);
m_findEncoding.value(_findEmptyResult->encoding())->setChecked(true);
connect(m_findresult, &QTableView::doubleClicked, this,
[=](const QModelIndex &index) {
auto editor =
m_findresult->property("EditorView").value<EditorView *>();
auto hexeditor = currentEditor();
if (hexeditor != editor) {
editor->raise();
editor->setFocus();
}
auto e = editor->hexEditor();
auto fm = editor->findResultModel();
auto cursor = e->cursor();
cursor->moveTo(fm->resultAt(index.row()).offset);
if (cursor->selectionCount() <= 1 && index.column() >= 3) {
cursor->select(fm->lastFindData().second);
}
});
auto header = m_findresult->horizontalHeader();
auto font = QFontMetrics(m_findresult->font());
auto len = font.horizontalAdvance('F') * (15 + 16 * 2);
if (header->sectionSize(3) < len) {
header->resizeSection(3, len);
}
auto dw = buildDockWidget(dock, QStringLiteral("FindResult"),
tr("FindResult") + QStringLiteral(" (ASCII)"),
m_findresult);
m_find = dw;
connect(m_findresult, &QTableViewExt::modelChanged, this, se);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpNumberShowDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
_numsitem = new NumShowModel(this);
m_numshowtable = new QTableViewExt(this);
Utilities::applyTableViewProperty(m_numshowtable);
m_numshowtable->setModel(_numsitem);
auto a = new QAction(this);
a->setText(tr("Copy"));
a->setIcon(ICONRES("copy"));
connect(a, &QAction::triggered, this, [=] {
auto r = m_numshowtable->currentIndex().row();
qApp->clipboard()->setText(
_numsitem->numData(NumShowModel::NumTableIndex(r)));
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("CopyToClipBoard"));
});
m_numshowtable->addAction(a);
connect(m_numshowtable->selectionModel(),
&QItemSelectionModel::currentRowChanged, a,
[=](const QModelIndex &current, const QModelIndex &) {
a->setEnabled(current.isValid());
});
a = new QAction(this);
a->setSeparator(true);
m_numshowtable->addAction(a);
auto actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true);
auto le = Utilities::checkIsLittleEndian();
auto aLittleEndian = new QAction(actionGroup);
aLittleEndian->setText(tr("LittleEndian"));
aLittleEndian->setCheckable(true);
aLittleEndian->setChecked(le);
connect(aLittleEndian, &QAction::triggered, this, [=] {
m_islittle = true;
this->on_locChanged();
});
m_numshowtable->addAction(aLittleEndian);
auto aBigEndian = new QAction(actionGroup);
aBigEndian->setText(tr("BigEndian"));
aBigEndian->setCheckable(true);
aBigEndian->setChecked(!le);
connect(aBigEndian, &QAction::triggered, this, [=] {
m_islittle = false;
this->on_locChanged();
});
m_numshowtable->addAction(aBigEndian);
a = new QAction(this);
a->setSeparator(true);
m_numshowtable->addAction(a);
auto aUnsignedHex = new QAction(this);
aUnsignedHex->setText(tr("UnsignedHex"));
aUnsignedHex->setCheckable(true);
aUnsignedHex->setChecked(false);
connect(aUnsignedHex, &QAction::toggled, this, [=](bool b) {
m_unsignedHex = b;
this->on_locChanged();
});
m_numshowtable->addAction(aUnsignedHex);
m_numshowtable->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu);
auto dw = buildDockWidget(dock, QStringLiteral("Number"), tr("Number"),
m_numshowtable);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpHashResultDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
m_hashtable = new QTableViewExt(this);
Utilities::applyTableViewProperty(m_hashtable);
m_hashtable->setColumnWidth(0, 350);
_hashModel = new CheckSumModel(this);
m_hashtable->setModel(_hashModel);
m_hashtable->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu);
auto a = newAction(ICONRES(QStringLiteral("copy")), tr("Copy"), [=] {
auto r = m_hashtable->currentIndex();
qApp->clipboard()->setText(
_hashModel->checkSumData(QCryptographicHash::Algorithm(r.row())));
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("CopyToClipBoard"));
});
m_hashtable->addAction(a);
a = newAction(QStringLiteral("del"), tr("Clear"),
[=]() { _hashModel->clearData(); });
m_hashtable->addAction(a);
connect(m_hashtable->selectionModel(),
&QItemSelectionModel::currentRowChanged, a,
[=](const QModelIndex &current, const QModelIndex &) {
a->setEnabled(current.isValid());
});
auto dw = buildDockWidget(dock, QStringLiteral("CheckSum"), tr("CheckSum"),
m_hashtable);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpHexBookMarkDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
_bookMarkEmpty = new BookMarksModel(nullptr);
m_bookmarks = new QTableViewExt(this);
Utilities::applyTableViewProperty(m_bookmarks);
m_bookmarks->setSelectionMode(QTableViewExt::ExtendedSelection);
m_bookmarks->setModel(_bookMarkEmpty);
connect(m_bookmarks, &QTableView::doubleClicked, this,
[=](const QModelIndex &index) {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->renderer()->enableCursor(true);
auto model = m_bookmarks->model();
auto offIndex = model->index(index.row(), 0);
auto offset = model->data(offIndex).value<qsizetype>();
hexeditor->cursor()->moveTo(offset);
});
m_bookmarks->addAction(
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
auto model = m_bookmarks->model();
saveTableContent(model);
}));
auto sep = new QAction(m_bookmarks);
sep->setSeparator(true);
m_bookmarks->addAction(sep);
m_aDelBookMark = new QAction(ICONRES(QStringLiteral("bookmarkdel")),
tr("DeleteBookMark"), m_bookmarks);
connect(m_aDelBookMark, &QAction::triggered, this, [=] {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto s = m_bookmarks->selectionModel()->selectedRows();
auto doc = hexeditor->document();
auto model = m_bookmarks->model();
QList<qsizetype> pos;
for (auto &item : s) {
auto offIndex = model->index(item.row(), 0);
auto offset = model->data(offIndex).value<qsizetype>();
pos.append(offset);
}
m_bookmarks->clearSelection();
doc->RemoveBookMarks(pos);
emit model->layoutChanged();
});
m_aDelBookMark->setEnabled(false);
m_bookmarks->addAction(m_aDelBookMark);
auto a = new QAction(ICONRES(QStringLiteral("bookmarkcls")),
tr("ClearBookMark"), m_bookmarks);
connect(a, &QAction::triggered, this, &MainWindow::on_bookmarkcls);
m_bookmarks->addAction(a);
m_bookmarks->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu);
auto dw = buildDockWidget(dock, QStringLiteral("BookMark"), tr("BookMark"),
m_bookmarks);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpHexMetaDataDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
_metadataEmpty = new MetaDataModel(nullptr);
m_metadatas = new QTableViewExt(this);
Utilities::applyTableViewProperty(m_metadatas);
m_metadatas->setSelectionMode(QTableViewExt::ExtendedSelection);
m_metadatas->setModel(_metadataEmpty);
connect(m_metadatas, &QTableView::doubleClicked, this,
[=](const QModelIndex &index) {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->renderer()->enableCursor(true);
auto model = m_metadatas->model();
auto offIndex = model->index(index.row(), 0);
auto offset =
model->data(offIndex, Qt::UserRole).value<qsizetype>();
hexeditor->cursor()->moveTo(offset);
});
m_metadatas->addAction(
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
auto model = m_metadatas->model();
saveTableContent(model);
}));
auto sep = new QAction(m_metadatas);
sep->setSeparator(true);
m_metadatas->addAction(sep);
m_aDelMetaData = new QAction(ICONRES(QStringLiteral("metadatadel")),
tr("DeleteMetadata"), m_metadatas);
connect(m_aDelMetaData, &QAction::triggered, this, [=] {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto s = m_metadatas->selectionModel()->selectedRows();
auto doc = hexeditor->document();
const auto &mds = doc->metadata()->getAllMetadata();
QList<QHexMetadataItem> pmetas;
for (auto &item : s) {
pmetas.push_back(mds.at(item.row()));
}
m_metadatas->clearSelection();
hexeditor->document()->metadata()->RemoveMetadatas(pmetas);
emit m_metadatas->model()->layoutChanged();
});
m_aDelMetaData->setEnabled(false);
m_metadatas->addAction(m_aDelMetaData);
auto a = new QAction(ICONRES(QStringLiteral("metadatacls")),
tr("ClearMetadata"), m_metadatas);
connect(a, &QAction::triggered, this, &MainWindow::on_metadatacls);
m_metadatas->addAction(a);
m_metadatas->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu);
auto dw = buildDockWidget(dock, QStringLiteral("MetaData"), tr("MetaData"),
m_metadatas);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpDecodingStrShowDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
m_txtDecode = new QTextBrowser(this);
m_txtDecode->setUndoRedoEnabled(false);
m_txtDecode->setProperty("__NAME__", tr("DecodeText"));
auto dw = buildDockWidget(dock, QStringLiteral("DecodeText"),
tr("DecodeText") + QStringLiteral(" (ASCII)"),
m_txtDecode);
auto menu = m_txtDecode->createStandardContextMenu();
menu->addSeparator();
auto a = new QAction(tr("Encoding"), this);
a->setIcon(ICONRES(QStringLiteral("encoding")));
connect(a, &QAction::triggered, this, &MainWindow::on_encoding);
menu->addAction(a);
m_txtDecode->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_txtDecode, &QTextBrowser::customContextMenuRequested, this,
[=](const QPoint &pos) {
menu->popup(m_txtDecode->viewport()->mapToGlobal(pos));
});
connect(m_txtDecode, &QTextBrowser::windowTitleChanged, dw,
&QDockWidget::setWindowTitle);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpScriptConsoleDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
m_scriptConsole = new ScriptingConsole(this);
connect(m_scriptConsole, &ScriptingConsole::consoleCommand, this,
[this] { showStatus({}); });
connect(m_scriptConsole, &ScriptingConsole::onFunctionTip, this,
[this](const QString &content) {
showStatus(QStringLiteral("<b><font color=\"gold\">") +
content + QStringLiteral("</font></b>"));
});
connect(m_scriptConsole, &ScriptingConsole::abortEvaluation, this,
[this]() {
auto &sm = ScriptMachine::instance();
if (sm.isRunning(ScriptMachine::Interactive)) {
sm.abortScript(ScriptMachine::Interactive);
} else {
m_scriptConsole->abortCurrentCode();
}
});
auto dw = buildDockWidget(dock, QStringLiteral("ScriptConsole"),
tr("ScriptConsole"), m_scriptConsole);
return dock->addDockWidget(area, dw, areaw);
}
ads::CDockAreaWidget *
MainWindow::buildUpScriptBgOutputDock(ads::CDockManager *dock,
ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) {
m_bgScriptOutput = new QPlainTextEdit(this);
m_bgScriptOutput->setPlaceholderText(tr("BgScriptOutputHere"));
m_bgScriptOutput->setReadOnly(true);
auto a = newAction(
ICONRES(QStringLiteral("mStr")), tr("SelectAll"),
[this]() { m_bgScriptOutput->selectAll(); }, QKeySequence::SelectAll);
m_bgScriptOutput->addAction(a);
a = newAction(
ICONRES(QStringLiteral("copy")), tr("Copy"),
[this]() { m_bgScriptOutput->copy(); }, QKeySequence::Copy);
m_bgScriptOutput->addAction(a);
a = newAction(ICONRES(QStringLiteral("del")), tr("Clear"),
[this]() { m_bgScriptOutput->clear(); });
m_bgScriptOutput->addAction(a);
a = new QAction(this);
a->setSeparator(true);
m_bgScriptOutput->addAction(a);
a = newAction(
ICONRES(QStringLiteral("dbgstop")), tr("AbortScript"),
[]() {
ScriptMachine::instance().abortScript(ScriptMachine::Background);
},
QKeySequence(Qt::ControlModifier | Qt::Key_Q));
m_bgScriptOutput->addAction(a);
m_bgScriptOutput->setContextMenuPolicy(Qt::ActionsContextMenu);
auto dw = buildDockWidget(dock, QStringLiteral("BgScriptOutput"),
tr("BgScriptOutput"), m_bgScriptOutput);
return dock->addDockWidget(area, dw, areaw);
}
RibbonTabContent *MainWindow::buildFilePage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
{
auto pannel = tab->addGroup(tr("Basic"));
addPannelAction(pannel, QStringLiteral("new"), tr("New"),
&MainWindow::on_newfile, QKeySequence::New);
addPannelAction(pannel, QStringLiteral("open"), tr("OpenF"),
&MainWindow::on_openfile, QKeySequence::Open);
addPannelAction(
pannel, QStringLiteral("workspace"), tr("OpenWorkSpace"),
&MainWindow::on_openworkspace,
shortcuts.keySequence(QKeySequences::Key::OPEN_WORKSPACE));
auto menu = new QMenu(this);
m_toolBtneditors.insert(
ToolButtonIndex::OPEN_EXT,
addPannelAction(pannel, QStringLiteral("openother"), tr("OpenExt"),
EMPTY_FUNC, {}, menu));
addPannelAction(pannel, QStringLiteral("recent"), tr("RecentFiles"),
EMPTY_FUNC, {}, m_recentMenu);
auto a = addPannelAction(pannel, QStringLiteral("reload"), tr("Reload"),
&MainWindow::on_reload);
m_editStateWidgets << a;
}
{
auto pannel = tab->addGroup(tr("Save"));
auto a = addPannelAction(pannel, QStringLiteral("save"), tr("Save"),
&MainWindow::on_save, QKeySequence::Save);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("saveas"), tr("SaveAs"),
&MainWindow::on_saveas,
shortcuts.keySequence(QKeySequences::Key::SAVE_AS));
m_driverStateWidgets << a;
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("export"), tr("Export"),
&MainWindow::on_exportfile,
shortcuts.keySequence(QKeySequences::Key::EXPORT));
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("convpro"), tr("ConvertWS"),
&MainWindow::on_convpro);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("savesel"), tr("SaveSel"),
&MainWindow::on_savesel);
m_editStateWidgets << a;
}
return tab;
}
RibbonTabContent *MainWindow::buildEditPage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
{
auto pannel = tab->addGroup(tr("General"));
auto a = addPannelAction(pannel, QStringLiteral("undo"), tr("Undo"),
&MainWindow::on_undofile, QKeySequence::Undo);
m_toolBtneditors.insert(ToolButtonIndex::UNDO_ACTION, a);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("redo"), tr("Redo"),
&MainWindow::on_redofile,
shortcuts.keySequence(QKeySequences::Key::REDO));
m_toolBtneditors.insert(ToolButtonIndex::REDO_ACTION, a);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("cut"), tr("Cut"),
&MainWindow::on_cutfile, QKeySequence::Cut);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("copy"), tr("Copy"),
&MainWindow::on_copyfile, QKeySequence::Copy);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("paste"), tr("Paste"),
&MainWindow::on_pastefile, QKeySequence::Paste);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("del"), tr("Delete"),
&MainWindow::on_delete, QKeySequence::Delete);
m_editStateWidgets << a;
a = addPannelAction(pannel, QStringLiteral("clone"), tr("Clone"),
&MainWindow::on_clone);
m_editStateWidgets << a;
}
{
auto pannel = tab->addGroup(tr("Lookup"));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("find"), tr("Find"),
&MainWindow::on_findfile, QKeySequence::Find);
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("jmp"), tr("Goto"), &MainWindow::on_gotoline,
shortcuts.keySequence(QKeySequences::Key::GOTO));
m_editStateWidgets << addPannelAction(pannel, QStringLiteral("sum"),
tr("CheckSum"),
&MainWindow::on_checksum);
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("info"), tr("FileInfo"),
&MainWindow::on_fileInfo,
shortcuts.keySequence(QKeySequences::Key::FILE_INFO));
}
{
auto pannel = tab->addGroup(tr("Hex"));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("cuthex"), tr("CutHex"),
&MainWindow::on_cuthex,
shortcuts.keySequence(QKeySequences::Key::CUT_HEX));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("copyhex"), tr("CopyHex"),
&MainWindow::on_copyhex,
shortcuts.keySequence(QKeySequences::Key::COPY_HEX));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("pastehex"), tr("PasteHex"),
&MainWindow::on_pastehex,
shortcuts.keySequence(QKeySequences::Key::PASTE_HEX));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("fill"), tr("Fill"), &MainWindow::on_fill,
shortcuts.keySequence(QKeySequences::Key::HEX_FILL));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("fillZero"), tr("FillZero"),
&MainWindow::on_fillzero,
shortcuts.keySequence(QKeySequences::Key::HEX_FILL0));
}
{
auto pannel = tab->addGroup(tr("MetaData"));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("bookmark"), tr("BookMark"),
&MainWindow::on_bookmark,
shortcuts.keySequence(QKeySequences::Key::BOOKMARK));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("bookmarkdel"), tr("DeleteBookMark"),
&MainWindow::on_bookmarkdel,
shortcuts.keySequence(QKeySequences::Key::BOOKMARK_DEL));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("bookmarkcls"), tr("ClearBookMark"),
&MainWindow::on_bookmarkcls,
shortcuts.keySequence(QKeySequences::Key::BOOKMARK_CLS));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metadata"), tr("MetaData"),
&MainWindow::on_metadata,
shortcuts.keySequence(QKeySequences::Key::METADATA));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metadataedit"), tr("MetaDataEdit"),
&MainWindow::on_metadataedit,
shortcuts.keySequence(QKeySequences::Key::METADATA_EDIT));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metadatadel"), tr("DeleteMetaData"),
&MainWindow::on_metadatadel,
shortcuts.keySequence(QKeySequences::Key::METADATA_DEL));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metadatacls"), tr("ClearMetaData"),
&MainWindow::on_metadatacls,
shortcuts.keySequence(QKeySequences::Key::METADATA_CLS));
}
return tab;
}
RibbonTabContent *MainWindow::buildViewPage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
{
auto pannel = tab->addGroup(tr("Display"));
auto menu = new QMenu(this);
menu->addAction(newAction(QStringLiteral("80%"), [this] {
this->setCurrentHexEditorScale(0.8);
}));
menu->addAction(newAction(QStringLiteral("90%"), [this] {
this->setCurrentHexEditorScale(0.9);
}));
menu->addAction(newAction(QStringLiteral("100%"), [this] {
this->setCurrentHexEditorScale(1.0);
}));
menu->addSeparator();
menu->addAction(newAction(QStringLiteral("120%"), [this] {
this->setCurrentHexEditorScale(1.2);
}));
menu->addAction(newAction(QStringLiteral("150%"), [this] {
this->setCurrentHexEditorScale(1.5);
}));
menu->addAction(newAction(QStringLiteral("200%"), [this] {
this->setCurrentHexEditorScale(2.0);
}));
menu->addAction(newAction(QStringLiteral("250%"), [this] {
this->setCurrentHexEditorScale(2.5);
}));
menu->addAction(newAction(QStringLiteral("300%"), [this] {
this->setCurrentHexEditorScale(3.0);
}));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("scale"), tr("Scale"), EMPTY_FUNC, {}, menu);
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("scalereset"), tr("ResetScale"),
[this] { this->setCurrentHexEditorScale(1.0); });
m_editStateWidgets << addPannelAction(pannel, QStringLiteral("viewtxt"),
tr("ViewText"),
&MainWindow::on_viewtxt);
}
{
auto pannel = tab->addGroup(tr("MetaData"));
auto menu = new QMenu(this);
menu->addAction(
m_aShowMetafg = newCheckableAction(
menu, tr("ShowMetafg"), &MainWindow::on_metadatafg,
shortcuts.keySequence(QKeySequences::Key::METADATA_FG)));
menu->addAction(
m_aShowMetabg = newCheckableAction(
menu, tr("ShowMetabg"), &MainWindow::on_metadatabg,
shortcuts.keySequence(QKeySequences::Key::METADATA_BG)));
menu->addAction(
m_aShowMetaComment = newCheckableAction(
menu, tr("ShowMetaComment"), &MainWindow::on_metadatacomment,
shortcuts.keySequence(QKeySequences::Key::METADATA_COMMENT)));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metadata"), tr("MetaData"), EMPTY_FUNC, {},
menu);
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metashow"), tr("MetaShowAll"),
&MainWindow::on_metashowall,
shortcuts.keySequence(QKeySequences::Key::METADATA_SHOW));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("metahide"), tr("MetaHideAll"),
&MainWindow::on_metahideall,
shortcuts.keySequence(QKeySequences::Key::METADATA_HIDE));
}
{
auto pannel = tab->addGroup(tr("FileStatus"));
auto disableStyle =
QStringLiteral("border:none;background:transparent;");
m_iSaved =
addPannelAction(pannel, _infoSaved, tr("InfoSave"), EMPTY_FUNC);
m_iSaved->setStyleSheet(disableStyle);
m_editStateWidgets << m_iSaved;
m_iReadWrite =
addPannelAction(pannel, _infoReadonly, tr("ReadOnly"), EMPTY_FUNC);
m_iReadWrite->setStyleSheet(disableStyle);
m_editStateWidgets << m_iReadWrite;
m_iLocked =
addPannelAction(pannel, _infoLock, tr("SetLocked"), [this]() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (!hexeditor->setLockedFile(!hexeditor->isLocked())) {
Toast::toast(this, _pixLock, tr("ErrUnLock"));
}
});
m_editStateWidgets << m_iLocked;
m_iCanOver =
addPannelAction(pannel, _infoCanOver, tr("SetOver"), [this]() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
auto b = !hexeditor->isKeepSize();
if (!hexeditor->setKeepSize(b)) {
Toast::toast(this, _pixCannotOver, tr("ErrUnOver"));
}
});
m_editStateWidgets << m_iCanOver;
}
{
auto pannel = tab->addGroup(tr("Window"));
m_toolBtneditors.insert(ToolButtonIndex::EDITOR_VIEWS,
addPannelAction(pannel, QStringLiteral("file"),
tr("Editor"), EMPTY_FUNC, {},
new QMenu(this)));
auto edwins = new QMenu(this);
edwins->addAction(newAction(QStringLiteral("file"), tr("Hex"), [this] {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
editor->switchView({});
}));
m_toolBtneditors.insert(ToolButtonIndex::EDITOR_WINS,
addPannelAction(pannel, QStringLiteral("win"),
tr("View"), EMPTY_FUNC, {},
edwins));
m_toolBtneditors.insert(
ToolButtonIndex::TOOL_VIEWS,
addPannelAction(pannel, QStringLiteral("general"), tr("Tools"),
EMPTY_FUNC, {}, new QMenu(this)));
m_toolBtneditors.insert(ToolButtonIndex::PLUGIN_VIEWS,
addPannelAction(pannel, QStringLiteral("edit"),
tr("Plugin"), EMPTY_FUNC, {},
new QMenu(this)));
m_editStateWidgets << m_toolBtneditors.value(
ToolButtonIndex::EDITOR_WINS);
}
{
auto pannel = tab->addGroup(tr("HexEditorLayout"));
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("mAddr"), tr("SetBaseAddr"), [this]() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
bool b;
auto num = WingInputDialog::getText(
this, tr("addressBase"), tr("inputAddressBase"),
QLineEdit::Normal, QString(), &b);
if (b) {
quintptr qnum = num.toULongLong(&b, 0);
if (b) {
auto r = qnum + quintptr(hexeditor->documentBytes());
if (qnum > r ||
quintptr(hexeditor->documentBytes()) > r) {
Toast::toast(this,
NAMEICONRES(QStringLiteral("mAddr")),
tr("WarnBigBaseAddress"));
}
hexeditor->setAddressBase(qnum);
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("mAddr")),
tr("ErrBaseAddress"));
}
}
});
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("mColInfo"), tr("SetColInfo"), [this]() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->setAddressVisible(!hexeditor->addressVisible());
});
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("mLineInfo"), tr("SetHeaderInfo"), [this]() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->setHeaderVisible(!hexeditor->headerVisible());
});
m_editStateWidgets << addPannelAction(
pannel, QStringLiteral("mStr"), tr("SetAsciiString"), [this]() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->setAsciiVisible(!hexeditor->asciiVisible());
});
}
{
auto pannel = tab->addGroup(tr("Layout"));
addPannelAction(pannel, QStringLiteral("fullscreen"), tr("Fullscreen"),
&MainWindow::on_fullScreen);
auto &l = LayoutManager::instance().layouts();
auto menu = new QMenu(this);
menu->addAction(newAction(tr("Default"), [this]() {
showStatus(tr("LayoutRestoring..."));
qApp->processEvents();
m_dock->restoreState(_defaultLayout);
showStatus({});
}));
if (!l.isEmpty()) {
menu->addSeparator();
}
for (auto p = l.constKeyValueBegin(); p != l.constKeyValueEnd(); ++p) {
auto layout = p->second;
menu->addAction(newAction(p->first, [this, layout]() {
showStatus(tr("LayoutRestoring..."));
qApp->processEvents();
m_dock->restoreState(layout);
showStatus({});
}));
}
m_toolBtneditors.insert(
ToolButtonIndex::LAYOUT_ACTION,
addPannelAction(pannel, QStringLiteral("layout"),
tr("RestoreLayout"), EMPTY_FUNC, {}, menu));
addPannelAction(pannel, QStringLiteral("layoutexport"),
tr("SaveLayout"), &MainWindow::on_saveLayout);
}
{
auto pannel = tab->addGroup(tr("Log"));
addPannelAction(pannel, QStringLiteral("log"), tr("ExportLog"),
&MainWindow::on_exportlog);
addPannelAction(pannel, QStringLiteral("clearhis"), tr("ClearLog"),
&MainWindow::on_clslog);
addPannelAction(pannel, QStringLiteral("qtloginspect"), tr("InsepctQt"),
&MainWindow::on_inspectQt);
}
return tab;
}
RibbonTabContent *MainWindow::buildScriptPage(RibbonTabContent *tab) {
{
auto pannel = tab->addGroup(tr("Basic"));
addPannelAction(pannel, QStringLiteral("script"), tr("ScriptEditor"),
&MainWindow::on_scriptwindow);
}
{
auto pannel = tab->addGroup(tr("Scripts"));
pannel->setVisible(false);
connect(pannel, &RibbonButtonGroup::emptyStatusChanged, this,
[pannel](bool isEmpty) { pannel->setVisible(!isEmpty); });
_scriptContexts =
ScriptManager::buildUpScriptRunnerContext(pannel, this);
m_scriptDBGroup = pannel;
}
return tab;
}
RibbonTabContent *MainWindow::buildPluginPage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
{
auto pannel = tab->addGroup(tr("General"));
addPannelAction(
pannel, QStringLiteral("settingplugin"), tr("Plugin"),
&MainWindow::on_settingPlugin,
shortcuts.keySequence(QKeySequences::Key::SETTING_PLUGIN));
}
{
auto pannel = tab->addGroup(tr("PluginFunctions"));
pannel->setVisible(false);
connect(pannel, &RibbonButtonGroup::emptyStatusChanged, this,
[pannel](bool isEmpty) { pannel->setVisible(!isEmpty); });
m_pluginSettingsGroup = pannel;
}
return tab;
}
RibbonTabContent *MainWindow::buildSettingPage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
auto &set = SettingManager::instance();
{
auto pannel = tab->addGroup(tr("General"));
addPannelAction(
pannel, QStringLiteral("general"), tr("General"),
&MainWindow::on_settingGeneral,
shortcuts.keySequence(QKeySequences::Key::SETTING_GENERAL));
if (set.scriptEnabled()) {
addPannelAction(pannel, QStringLiteral("scriptset"),
tr("ScriptSetting"), &MainWindow::on_settingScript);
}
}
if (set.enablePlugin()) {
auto pannel = tab->addGroup(tr("PluginSettings"));
pannel->setVisible(false);
connect(pannel, &RibbonButtonGroup::emptyStatusChanged, this,
[pannel](bool isEmpty) { pannel->setVisible(!isEmpty); });
}
return tab;
}
RibbonTabContent *MainWindow::buildAboutPage(RibbonTabContent *tab) {
auto pannel = tab->addGroup(tr("Info"));
addPannelAction(pannel, QStringLiteral("soft"), tr("Software"),
&MainWindow::on_about);
addPannelAction(pannel, QStringLiteral("sponsor"), tr("Sponsor"),
&MainWindow::on_sponsor);
addPannelAction(pannel, QStringLiteral("wiki"), tr("Wiki"),
&MainWindow::on_wiki);
addPannelAction(pannel, QStringLiteral("qt"), tr("AboutQT"),
[this] { WingMessageBox::aboutQt(this); });
addPannelAction(pannel, QStringLiteral("update"), tr("CheckUpdate"),
&MainWindow::on_update);
return tab;
}
void MainWindow::buildUpSettingDialog() {
QStringList usedIDs;
QString id;
m_setdialog = new SettingDialog(this);
qApp->processEvents();
auto generalPage = new GeneralSettingDialog(m_setdialog);
connect(generalPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(generalPage);
id = generalPage->id();
Q_ASSERT(!id.isEmpty());
Q_ASSERT(usedIDs.indexOf(id) < 0);
usedIDs.append(id);
qApp->processEvents();
auto editorPage = new EditorSettingDialog(m_setdialog);
connect(editorPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(editorPage);
id = editorPage->id();
Q_ASSERT(!id.isEmpty());
Q_ASSERT(usedIDs.indexOf(id) < 0);
usedIDs.append(id);
qApp->processEvents();
auto plgPage = new PluginSettingDialog(m_setdialog);
connect(plgPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
plgPage->buildUp(m_plgPages);
m_setdialog->addPage(plgPage);
id = plgPage->id();
Q_ASSERT(!id.isEmpty());
Q_ASSERT(usedIDs.indexOf(id) < 0);
usedIDs.append(id);
qApp->processEvents();
auto scriptPage = new ScriptSettingDialog(m_setdialog);
connect(scriptPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(scriptPage);
id = scriptPage->id();
Q_ASSERT(!id.isEmpty());
Q_ASSERT(usedIDs.indexOf(id) < 0);
usedIDs.append(id);
qApp->processEvents();
auto otherPage = new OtherSettingsDialog(m_setdialog);
id = otherPage->id();
Q_ASSERT(!id.isEmpty());
Q_ASSERT(usedIDs.indexOf(id) < 0);
usedIDs.append(id);
qApp->processEvents();
for (auto page_p = m_settingPages.constKeyValueBegin();
page_p != m_settingPages.constKeyValueEnd(); ++page_p) {
auto page = page_p->first;
auto name = page->name();
auto id = page->id();
// check
if (id.isEmpty()) {
id = name;
auto plg = page->property("__plg__").value<IWingPlugin *>();
Logger::warning(
QStringLiteral("[") + plg->metaObject()->className() +
QStringLiteral("::") + name + QStringLiteral("] ") +
QStringLiteral(":") + tr("SetPageIDEmptyTryUseName"));
}
if (usedIDs.contains(id)) {
auto plg = page->property("__plg__").value<IWingPlugin *>();
Logger::critical(
QStringLiteral("[") + plg->metaObject()->className() +
QStringLiteral("::") + name + QStringLiteral("] ") +
QStringLiteral(":") + tr("SetPageDupNameIgnored"));
continue;
}
connect(page, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(page);
if (page_p->second) {
auto icon = page->categoryIcon();
addPannelAction(m_pluginSettingsGroup, icon, name,
[=] { m_setdialog->showConfig(id); });
}
usedIDs.append(id);
qApp->processEvents();
}
connect(otherPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(otherPage);
qApp->processEvents();
m_setdialog->build();
}
void MainWindow::installPluginEditorWidgets() {
QHash<QString, IWingPlugin *> names;
auto &log = Logger::instance();
auto menu = m_toolBtneditors.value(EDITOR_WINS)->menu();
decltype(m_editorViewWidgets) newEditorViewWidgets;
for (auto p = m_editorViewWidgets.constKeyValueBegin();
p != m_editorViewWidgets.constKeyValueEnd(); ++p) {
decltype(newEditorViewWidgets)::mapped_type newCreatorList;
for (auto &wctor : p->second) {
qApp->processEvents();
auto id = wctor->id();
if (names.contains(id)) {
log.critical(tr("Plugin %1 contains a duplicate ID (%2) that "
"is already registered by plugin %3")
.arg(p->first->pluginName(), id,
names.value(id)->pluginName()));
continue;
}
auto a = newAction(wctor->icon(), wctor->name(), [this, id] {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
editor->switchView(id);
});
a->setProperty("__ID__", id);
menu->addAction(a);
names.insert(id, p->first);
newCreatorList.append(wctor);
}
newEditorViewWidgets.insert(p->first, newCreatorList);
qApp->processEvents();
}
m_editorViewWidgets = newEditorViewWidgets;
}
void MainWindow::showStatus(const QString &status) {
if (status.isEmpty() && m_isfinding) {
_status->setText(tr("Finding..."));
} else {
_status->setText(status);
}
}
EditorView *MainWindow::newfileGUI() {
if (!newOpenFileSafeCheck()) {
return nullptr;
}
auto editor = new EditorView(this);
auto index = m_newIndex++;
editor->newFile(index);
registerEditorView(editor);
m_dock->addDockWidget(ads::CenterDockWidgetArea, editor, editorViewArea());
editor->setFocus();
return editor;
}
void MainWindow::on_newfile() { newfileGUI(); }
void MainWindow::on_openfile() {
showStatus(tr("Opening..."));
QScopeGuard g([this]() { showStatus({}); });
auto filename =
WingFileDialog::getOpenFileName(this, tr("ChooseFile"), m_lastusedpath);
if (!filename.isEmpty()) {
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
EditorView *editor = nullptr;
auto res = openFile(filename, &editor);
if (res == ErrFile::NotExist) {
WingMessageBox::critical(this, tr("Error"), tr("FileNotExist"));
return;
}
if (res == ErrFile::Permission) {
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
return;
}
if (res == ErrFile::AlreadyOpened) {
Q_ASSERT(editor);
editor->raise();
editor->setFocus();
return;
}
RecentFileManager::RecentInfo info;
info.fileName = filename;
m_recentmanager->addRecentFile(info);
}
}
void MainWindow::on_openworkspace() {
showStatus(tr("WorkSpaceOpening..."));
QScopeGuard g([this]() { showStatus({}); });
auto filename = WingFileDialog::getOpenFileName(
this, tr("ChooseFile"), m_lastusedpath, tr("ProjectFile (*.wingpro)"));
if (filename.isEmpty()) {
return;
}
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
EditorView *editor = nullptr;
auto res = openWorkSpace(filename, &editor);
if (res == ErrFile::NotExist) {
WingMessageBox::critical(this, tr("Error"), tr("FileNotExist"));
return;
}
if (res == ErrFile::Permission) {
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
return;
}
if (res == ErrFile::AlreadyOpened) {
Q_ASSERT(editor);
editor->raise();
editor->setFocus();
return;
}
RecentFileManager::RecentInfo info;
info.fileName = filename;
info.isWorkSpace = true;
m_recentmanager->addRecentFile(info);
showStatus({});
}
void MainWindow::on_reload() {
showStatus(tr("Reloading..."));
QScopeGuard g([this]() { showStatus({}); });
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto res = editor->reload();
switch (res) {
case ErrFile::Success: {
Toast::toast(this, NAMEICONRES(QStringLiteral("reload")),
tr("ReloadSuccessfully"));
break;
}
default: {
WingMessageBox::critical(this, tr("Error"), tr("ReloadUnSuccessfully"));
break;
}
}
}
void MainWindow::on_save() {
showStatus(tr("Saving..."));
QScopeGuard g([this]() { showStatus({}); });
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto changedTo = editor->change2WorkSpace();
QString ws;
auto res = saveEditor(editor, {}, false, false, &ws);
auto isNewFile = editor->isNewFile();
if (isNewFile) {
on_saveas();
return;
}
if (res == ErrFile::Permission) {
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
return;
}
if (res == ErrFile::WorkSpaceUnSaved) {
WingMessageBox::critical(this, tr("Error"), tr("SaveWSError"));
return;
}
if (changedTo) {
RecentFileManager::RecentInfo info;
info.fileName = ws;
info.isWorkSpace = true;
m_recentmanager->addRecentFile(info);
}
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
tr("SaveSuccessfully"));
}
void MainWindow::on_convpro() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
if (editor->isNewFile()) {
Toast::toast(this, NAMEICONRES("convpro"), tr("SaveNewFirst"));
return;
}
if (editor->isOriginWorkSpace()) {
Toast::toast(this, NAMEICONRES("convpro"), tr("AlreadyWorkSpace"));
return;
}
QString workspace;
auto ret = saveEditor(editor, {}, false, true, &workspace);
if (ret == ErrFile::WorkSpaceUnSaved) {
WingMessageBox::critical(this, tr("Error"), tr("ConvWorkSpaceFailed"));
} else if (ret == ErrFile::Success) {
// add to history
RecentFileManager::RecentInfo info;
info.fileName = workspace;
info.isWorkSpace = true;
m_recentmanager->addRecentFile(info);
Toast::toast(this, NAMEICONRES("convpro"), tr("ConvWorkSpaceSuccess"));
} else {
// should not go there
Q_ASSERT(false);
}
}
void MainWindow::on_saveas() {
showStatus(tr("SavingAs..."));
QScopeGuard g([this]() { showStatus({}); });
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
QString lastpath;
if (editor->isNewFile() || editor->isExtensionFile()) {
lastpath = m_lastusedpath;
} else {
lastpath = editor->fileName();
}
auto filename =
WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"), lastpath);
if (filename.isEmpty())
return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
bool isWorkspace = editor->isOriginWorkSpace();
auto res = saveEditor(editor, filename, false, isWorkspace);
switch (res) {
case ErrFile::Success: {
Toast::toast(this, NAMEICONRES(QStringLiteral("saveas")),
tr("SaveSuccessfully"));
RecentFileManager::RecentInfo info;
info.fileName = filename;
info.isWorkSpace = isWorkspace;
m_recentmanager->addRecentFile(info);
break;
}
case ErrFile::WorkSpaceUnSaved: {
WingMessageBox::critical(this, tr("Error"), tr("SaveWSError"));
break;
}
default: {
WingMessageBox::critical(this, tr("Error"), tr("SaveUnSuccessfully"));
break;
}
}
}
void MainWindow::on_exportfile() {
showStatus(tr("Exporting..."));
QScopeGuard g([this]() { showStatus({}); });
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto filename = WingFileDialog::getSaveFileName(
this, tr("ChooseExportFile"), m_lastusedpath);
if (filename.isEmpty())
return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
bool isWorkspace = editor->isOriginWorkSpace();
auto res = saveEditor(editor, filename, true, isWorkspace);
switch (res) {
case ErrFile::Success: {
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
tr("ExportSuccessfully"));
break;
}
default: {
WingMessageBox::critical(this, tr("Error"), tr("ExportUnSuccessfully"));
break;
}
}
}
void MainWindow::on_savesel() {
showStatus(tr("SavingSel..."));
QScopeGuard g([this]() { showStatus({}); });
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto filename = WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"),
m_lastusedpath);
if (filename.isEmpty())
return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
QFile qfile(filename);
if (qfile.open(QFile::WriteOnly)) {
auto buffer = hexeditor->selectedBytes().join();
qfile.write(buffer);
qfile.close();
Toast::toast(this, NAMEICONRES(QStringLiteral("savesel")),
tr("SaveSelSuccess"));
} else {
WingMessageBox::critical(this, tr("Error"), tr("SaveSelError"));
}
}
void MainWindow::on_undofile() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->document()->undo();
}
void MainWindow::on_redofile() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->document()->redo();
}
void MainWindow::on_cutfile() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (Q_LIKELY(hexeditor->Cut())) {
Toast::toast(this, NAMEICONRES(QStringLiteral("cut")),
tr("CutToClipBoard"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("cut")),
tr("UnCutToClipBoard"));
}
}
void MainWindow::on_copyfile() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (Q_LIKELY(hexeditor->copy())) {
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("CopyToClipBoard"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("UnCopyToClipBoard"));
}
}
void MainWindow::on_pastefile() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->Paste();
}
void MainWindow::on_delete() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (hexeditor->RemoveSelection()) {
Toast::toast(this, NAMEICONRES(QStringLiteral("del")),
tr("DeleteSuccess"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("del")),
tr("DeleteFailed"));
}
}
void MainWindow::on_clone() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->clone();
if (hexeditor == nullptr) {
Toast::toast(this, NAMEICONRES(QStringLiteral("clone")),
tr("NoMoreClone"));
return;
}
registerClonedEditorView(hexeditor);
m_dock->addDockWidget(ads::CenterDockWidgetArea, hexeditor,
editorViewArea());
}
void MainWindow::on_findfile() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
static FindDialog::FindInfo info;
info.isSel = hexeditor->selectionCount() == 1;
FindDialog fd(info, this);
if (fd.exec()) {
auto r = fd.getResult();
info.isStringFind = r.isStringFind;
info.encoding = r.encoding;
info.str = r.str;
showStatus(tr("Finding..."));
ExecAsync<EditorView::FindError>(
[this, r]() -> EditorView::FindError {
m_isfinding = true;
return currentEditor()->find(r);
},
[this](EditorView::FindError err) {
switch (err) {
case EditorView::FindError::Success:
Toast::toast(this, NAMEICONRES(QStringLiteral("find")),
tr("FindFininish"));
break;
case EditorView::FindError::Busy:
Toast::toast(this, NAMEICONRES(QStringLiteral("find")),
tr("FindFininishBusy"));
break;
case EditorView::FindError::MayOutOfRange:
Toast::toast(this, NAMEICONRES(QStringLiteral("find")),
tr("MayTooMuchFindResult"));
break;
}
auto result =
qobject_cast<FindResultModel *>(m_findresult->model());
if (result) {
m_findEncoding.value(result->encoding())->setChecked(true);
}
auto header = m_findresult->horizontalHeader();
auto font = QFontMetrics(m_findresult->font());
auto len = font.horizontalAdvance('F') * (15 + 16 * 2);
if (header->sectionSize(3) < len) {
header->resizeSection(3, len);
}
m_find->raise();
m_isfinding = false;
this->showStatus({});
});
}
}
void MainWindow::on_gotoline() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
editor->triggerGoto();
}
void MainWindow::on_encoding() {
EncodingDialog d;
if (d.exec()) {
m_encoding = d.getResult();
m_txtDecode->setWindowTitle(
m_txtDecode->property("__NAME__").toString() +
QStringLiteral(" (") + m_encoding + QStringLiteral(")"));
on_selectionChanged();
}
}
void MainWindow::on_checksum() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
CheckSumDialog d;
if (d.exec()) {
auto cs = d.getResults();
auto hashes = Utilities::supportedHashAlgorithms();
if (editor->hexEditor()->hasSelection()) {
auto data = editor->hexEditor()->selectedBytes();
for (auto &c : cs) {
auto h = hashes.at(c);
QCryptographicHash hash(h);
hash.addData(data.join());
_hashModel->setCheckSumData(h, hash.result().toHex().toUpper());
}
} else {
if (editor->isNewFile()) {
auto bytes = editor->hexEditor()->document()->read(0);
for (auto &c : cs) {
auto h = hashes.at(c);
QCryptographicHash hash(h);
hash.addData(bytes);
_hashModel->setCheckSumData(
h, hash.result().toHex().toUpper());
}
} else {
QFile f(editor->fileName());
for (auto &c : cs) {
auto h = hashes.at(c);
QCryptographicHash hash(h);
hash.addData(&f);
_hashModel->setCheckSumData(
h, hash.result().toHex().toUpper());
}
}
}
}
}
void MainWindow::on_fileInfo() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
FileInfoDialog d(editor->fileName());
d.exec();
}
void MainWindow::on_cuthex() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (hexeditor->Cut(true)) {
Toast::toast(this, NAMEICONRES(QStringLiteral("cut")),
tr("CutToClipBoard"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("cut")),
tr("UnCutToClipBoard"));
}
}
void MainWindow::on_copyhex() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
if (hexeditor->copy(true)) {
Toast::toast(this, NAMEICONRES(QStringLiteral("copyhex")),
tr("CopyToClipBoard"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("copyhex")),
tr("UnCopyToClipBoard"));
}
}
void MainWindow::on_pastehex() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->Paste(true);
}
void MainWindow::on_fill() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
bool b;
auto in = WingInputDialog::getText(this, tr("Fill"), tr("PleaseInputFill"),
QLineEdit::Normal, QString(), &b);
if (b) {
auto v = in.toUInt(&b, 0);
auto limit = std::numeric_limits<uchar>().max();
if (v > limit) {
Toast::toast(this, NAMEICONRES(QStringLiteral("fill")),
tr("FillInputTruncWarn"));
}
auto ch = uchar(v);
if (b) {
auto doc = hexeditor->document();
if (doc->isEmpty() || !hexeditor->hasSelection())
return;
auto total = hexeditor->selectionCount();
doc->beginMarco(QStringLiteral("FillBytes"));
for (int i = 0; i < total; ++i) {
auto cursor = hexeditor->cursor();
auto pos = cursor->selectionStart(i).offset();
hexeditor->Replace(
pos, QByteArray(cursor->selectionLength(i), char(ch)));
}
doc->endMarco();
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("fill")),
tr("FillInputError"));
}
}
}
void MainWindow::on_fillzero() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
if (doc->isEmpty() || !hexeditor->hasSelection())
return;
auto cur = hexeditor->cursor();
auto total = cur->selectionCount();
doc->beginMarco(QStringLiteral("FillZero"));
for (int i = 0; i < total; ++i) {
auto pos = cur->selectionStart(i).offset();
hexeditor->Replace(pos, QByteArray(cur->selectionLength(i), char(0)));
}
doc->endMarco();
}
void MainWindow::on_bookmark() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
auto pos = hexeditor->currentOffset();
if (doc->existBookMark(pos)) {
auto bcomment = doc->bookMark(pos);
bool ok;
hexeditor->renderer()->enableCursor();
auto comment =
WingInputDialog::getText(this, tr("BookMark"), tr("InputComment"),
QLineEdit::Normal, bcomment, &ok);
if (ok) {
doc->ModBookMark(pos, comment);
}
} else {
bool ok;
auto comment =
WingInputDialog::getText(this, tr("BookMark"), tr("InputComment"),
QLineEdit::Normal, QString(), &ok);
if (ok) {
doc->AddBookMark(pos, comment);
}
}
}
void MainWindow::on_bookmarkdel() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
auto cursor = hexeditor->cursor();
if (cursor->hasSelection()) {
QList<qsizetype> rmOff;
auto total = cursor->selectionCount();
for (int i = 0; i < total; ++i) {
rmOff.append(doc->bookMarkRange(cursor->selectionStart(i).offset(),
cursor->selectionEnd(i).offset()));
}
if (!rmOff.isEmpty()) {
doc->beginMarco(QStringLiteral("BookMarkRmRange"));
for (auto &pos : rmOff) {
doc->RemoveBookMark(pos);
}
doc->endMarco();
Toast::toast(this, NAMEICONRES("bookmarkdel"),
tr("BookmarkDelSuccess"));
return;
}
} else {
auto pos = cursor->position().offset();
if (doc->bookMarkExists(pos)) {
if (doc->RemoveBookMark(pos)) {
Toast::toast(this, NAMEICONRES("bookmarkdel"),
tr("BookmarkDelSuccess"));
return;
}
}
}
Toast::toast(this, NAMEICONRES("bookmarkdel"), tr("BookmarkDelNoItem"));
}
void MainWindow::on_bookmarkcls() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
doc->ClearBookMark();
Toast::toast(this, NAMEICONRES("bookmarkdel"), tr("BookmarkClearSuccess"));
}
void MainWindow::on_metadata() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
if (hexeditor->documentBytes() > 0) {
MetaDialog m(this);
auto cur = hexeditor->cursor();
if (cur->hasSelection()) {
if (m.exec()) {
auto total = cur->selectionCount();
auto meta = doc->metadata();
meta->beginMarco(QStringLiteral("MetaData"));
for (int i = 0; i < total; ++i) {
auto begin = cur->selectionStart(i).offset();
auto end = cur->selectionEnd(i).offset();
meta->Metadata(begin, end, m.foreGroundColor(),
m.backGroundColor(), m.comment());
}
meta->endMarco();
cur->clearSelection();
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
tr("NoSelection"));
}
}
}
void MainWindow::on_metadataedit() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
if (hexeditor->documentBytes() > 0) {
MetaDialog m(this);
auto cur = hexeditor->cursor();
if (cur->currentSelectionLength() > 0) {
auto mc = doc->metadata()->get(cur->position().offset());
if (mc.has_value()) {
auto meta = mc.value();
auto begin = meta.begin;
auto end = meta.end;
m.setForeGroundColor(meta.foreground);
m.setBackGroundColor(meta.background);
m.setComment(meta.comment);
if (m.exec()) {
auto mi = hexeditor->document()->metadata();
QHexMetadataItem o;
o.begin = begin;
o.end = end;
o.foreground = m.foreGroundColor();
o.background = m.backGroundColor();
o.comment = m.comment();
mi->ModifyMetadata(meta, o);
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
tr("NoMetaData"));
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
tr("NoSelection"));
}
}
}
void MainWindow::on_metadatadel() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
auto meta = doc->metadata();
auto cursor = hexeditor->cursor();
if (cursor->hasSelection()) {
Toast::toast(this, NAMEICONRES("metadatadel"), tr("PleaseClearSel"));
return;
}
auto pos = cursor->position().offset();
if (meta->RemoveMetadata(pos)) {
Toast::toast(this, NAMEICONRES("metadatadel"), tr("MetaDelSuccess"));
} else {
Toast::toast(this, NAMEICONRES("metadatadel"), tr("MetaDelNoItem"));
}
}
void MainWindow::on_metadatacls() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
doc->metadata()->Clear();
Toast::toast(this, NAMEICONRES("metadatacls"), tr("MetaClearSuccess"));
}
void MainWindow::on_metadatafg(bool checked) {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
doc->setMetafgVisible(checked);
}
void MainWindow::on_metadatabg(bool checked) {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
doc->setMetabgVisible(checked);
}
void MainWindow::on_metadatacomment(bool checked) {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
doc->setMetaCommentVisible(checked);
}
void MainWindow::on_metashowall() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
doc->setMetafgVisible(true);
doc->setMetabgVisible(true);
doc->setMetaCommentVisible(true);
}
void MainWindow::on_metahideall() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
doc->setMetafgVisible(false);
doc->setMetabgVisible(false);
doc->setMetaCommentVisible(false);
}
void MainWindow::on_clearfindresult() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
editor->clearFindResult();
}
void MainWindow::on_exportfindresult() {
showStatus(tr("FindResultExporting..."));
QScopeGuard g([this]() { showStatus({}); });
auto editor = currentEditor();
if (editor == nullptr) {
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
tr("EmptyFindResult"));
return;
}
auto findresitem = editor->findResultModel();
auto c = findresitem->size();
if (c == 0) {
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
tr("EmptyFindResult"));
return;
}
auto filename = WingFileDialog::getSaveFileName(
this, tr("ChooseSaveFile"), m_lastusedpath, {"Json (*.json)"});
if (filename.isEmpty())
return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
QFile f(filename);
if (f.open(QFile::WriteOnly)) {
QJsonObject fobj;
fobj.insert(QStringLiteral("file"), editor->fileName());
auto d = findresitem->lastFindData();
fobj.insert(QStringLiteral("find"), d.first);
QJsonArray arr;
for (int i = 0; i < c; i++) {
auto data = findresitem->resultAt(i);
QJsonObject jobj;
jobj.insert(QStringLiteral("line"), QString::number(data.line));
jobj.insert(QStringLiteral("col"), QString::number(data.col));
jobj.insert(QStringLiteral("offset"), QString::number(data.offset));
QTextDocument doc;
doc.setHtml(
findresitem->data(findresitem->index(i, 3), Qt::DisplayRole)
.toString());
jobj.insert(QStringLiteral("range"), doc.toPlainText());
doc.setHtml(
findresitem->data(findresitem->index(i, 4), Qt::DisplayRole)
.toString());
jobj.insert(QStringLiteral("encoding"), doc.toPlainText());
arr.append(jobj);
}
fobj.insert(QStringLiteral("data"), arr);
QJsonDocument doc(fobj);
if (f.write(doc.toJson(QJsonDocument::JsonFormat::Indented)) >= 0) {
f.close();
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
tr("SaveFindResult"));
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
tr("SaveFindResultError"));
}
}
void MainWindow::on_locChanged() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
m_lblloc->setText(QStringLiteral("(%1,%2)")
.arg(hexeditor->currentRow())
.arg(hexeditor->currentColumn()));
auto sellen = hexeditor->currentSelectionLength();
m_lblsellen->setText(QStringLiteral("%1 - 0x%2")
.arg(sellen)
.arg(QString::number(sellen, 16).toUpper()));
// number analyse
auto off = hexeditor->currentOffset();
auto d = hexeditor->document();
constexpr auto maxlen = 32;
auto tmp = d->read(off, maxlen);
quint64 n = *reinterpret_cast<const quint64 *>(tmp.constData());
auto len = size_t(tmp.length());
if (len >= sizeof(quint64)) {
auto s = processEndian(n);
_numsitem->setNumData(
NumShowModel::NumTableIndex::Uint64,
m_unsignedHex
? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())
: QString::number(s));
auto s1 = processEndian(qsizetype(n));
_numsitem->setNumData(NumShowModel::NumTableIndex::Int64,
QString::number(s1));
double s2 = *(double *)(&n);
auto s3 = processEndian(s2);
_numsitem->setNumData(NumShowModel::NumTableIndex::Double64,
qIsNaN(s3) ? QStringLiteral("NAN")
: QString::number(s3));
} else {
_numsitem->setNumData(NumShowModel::NumTableIndex::Uint64, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Int64, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Double64, QString());
}
if (len >= sizeof(quint32)) {
auto s = processEndian(quint32(n));
_numsitem->setNumData(
NumShowModel::NumTableIndex::Uint32,
m_unsignedHex
? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())
: QString::number(s));
auto s1 = processEndian(qint32(n));
_numsitem->setNumData(NumShowModel::NumTableIndex::Int32,
QString::number(s1));
float s2 = *(float *)(&n);
auto s3 = processEndian(s2);
_numsitem->setNumData(NumShowModel::NumTableIndex::Float32,
qIsNaN(s3) ? QStringLiteral("NAN")
: QString::number(s3));
} else {
_numsitem->setNumData(NumShowModel::NumTableIndex::Uint32, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Int32, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Float32, QString());
}
if (len >= sizeof(quint16)) {
auto s = processEndian(quint16(n));
_numsitem->setNumData(
NumShowModel::NumTableIndex::Ushort,
m_unsignedHex
? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())
: QString::number(s));
auto s1 = processEndian(qint16(n));
_numsitem->setNumData(NumShowModel::NumTableIndex::Short,
QString::number(s1));
} else {
_numsitem->setNumData(NumShowModel::NumTableIndex::Ushort, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Short, QString());
}
if (len >= sizeof(uchar)) {
auto s1 = tmp.at(0);
auto s = uchar(s1);
_numsitem->setNumData(
NumShowModel::NumTableIndex::Byte,
m_unsignedHex
? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())
: QString::number(s));
_numsitem->setNumData(NumShowModel::NumTableIndex::Char,
QString::number(s1));
} else {
_numsitem->setNumData(NumShowModel::NumTableIndex::Byte, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::Char, QString());
}
// str
if (len > 0) {
_numsitem->setNumData(NumShowModel::NumTableIndex::ASCII_STR,
QString::fromLatin1(tmp));
_numsitem->setNumData(NumShowModel::NumTableIndex::UTF8_STR,
QString::fromUtf8(tmp));
auto re = processEndian(tmp);
_numsitem->setNumData(
NumShowModel::NumTableIndex::UTF16_STR,
QString::fromUtf16(reinterpret_cast<const char16_t *>(re.data()),
re.length() / sizeof(char16_t)));
_numsitem->setNumData(
NumShowModel::NumTableIndex::UTF32_STR,
QString::fromUcs4(reinterpret_cast<const char32_t *>(re.data()),
re.length() / sizeof(char32_t)));
} else {
_numsitem->setNumData(NumShowModel::NumTableIndex::ASCII_STR,
QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::UTF8_STR, QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::UTF16_STR,
QString());
_numsitem->setNumData(NumShowModel::NumTableIndex::UTF32_STR,
QString());
}
auto cursor = hexeditor->cursor();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::CursorPositionChanged,
{QVariant::fromValue(cursor->position())});
}
void MainWindow::on_selectionChanged() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
on_locChanged();
auto cursor = hexeditor->cursor();
QByteArrayList buffer;
bool isPreview = false;
if (cursor->previewSelectionMode() != QHexCursor::SelectionRemove &&
cursor->hasPreviewSelection()) {
buffer.append(hexeditor->previewSelectedBytes());
isPreview = true;
}
if (buffer.isEmpty()) {
if (hexeditor->selectionCount() > 0) {
buffer = hexeditor->selectedBytes();
}
}
auto total = buffer.size();
m_txtDecode->clear();
for (int i = 0; i < total; i++) {
auto b = buffer.at(i);
if (!isPreview) {
m_txtDecode->insertHtml(
QStringLiteral("<font color=\"gold\">[ %1 / %2 ]</font><br />")
.arg(i + 1)
.arg(total));
}
if (buffer.length() <= 1024 * _decstrlim) {
m_txtDecode->insertPlainText(
Utilities::decodingString(b, m_encoding));
m_txtDecode->insertPlainText(QStringLiteral("\n"));
} else {
m_txtDecode->insertHtml(
QStringLiteral("<font color=\"red\">%1</font><br />")
.arg(tr("TooManyBytesDecode")));
}
}
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::SelectionChanged,
{QVariant::fromValue(buffer), isPreview});
}
void MainWindow::on_viewtxt() {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
auto hexeditor = editor->hexEditor();
auto filename = editor->fileName();
QMimeDatabase db;
auto mime = db.mimeTypeForFile(filename);
auto ret = Utilities::isTextFile(mime);
if (!ret) {
auto ret = WingMessageBox::warning(
this, tr("Warn"), tr("NoTextFileMayInvalid"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (ret == QMessageBox::No) {
return;
}
}
_showtxt->load(hexeditor->document()->buffer(), mime.name());
}
void MainWindow::on_fullScreen() {
if (this->isFullScreen()) {
this->showMaximized();
} else {
this->showFullScreen();
}
}
void MainWindow::on_saveLayout() {
showStatus(tr("LayoutSaving..."));
QScopeGuard g([this]() { showStatus({}); });
static auto suffix = QStringLiteral(".wing-layout");
bool ok;
auto fileID = WingInputDialog::getText(
this, tr("SaveLayout"), tr("PleaseInput"), QLineEdit::Normal, {}, &ok);
if (ok) {
auto layoutDir = LayoutManager::layoutDir();
QFile f(layoutDir.absoluteFilePath(fileID + suffix));
if (f.open(QFile::WriteOnly)) {
auto layout = m_dock->saveState();
f.write(layout);
f.close();
// append saved layout
auto &lm = LayoutManager::instance();
auto menu =
m_toolBtneditors[ToolButtonIndex::LAYOUT_ACTION]->menu();
Q_ASSERT(menu);
menu->addAction(
newAction(lm.getSavedLayoutName(fileID), [this, layout]() {
showStatus(tr("LayoutRestoring..."));
qApp->processEvents();
m_dock->restoreState(layout);
showStatus({});
}));
Toast::toast(this, NAMEICONRES(QStringLiteral("layoutexport")),
tr("SaveLayoutSuccess"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("layoutexport")),
tr("SaveLayoutError"));
}
}
}
void MainWindow::on_exportlog() {
showStatus(tr("LogExporting..."));
QScopeGuard g([this]() { showStatus({}); });
auto nfile = saveLog();
if (nfile.isEmpty()) {
Toast::toast(this, NAMEICONRES(QStringLiteral("log")),
tr("ExportLogError"));
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("log")),
tr("ExportLogSuccess") + nfile);
}
}
void MainWindow::on_clslog() {
Q_ASSERT(m_logbrowser);
m_logbrowser->clear();
Toast::toast(this, NAMEICONRES(QStringLiteral("clearhis")),
tr("ClearLogSuccess"));
}
void MainWindow::on_inspectQt() {
InspectQtLogHelper::instance().showLogWidget();
}
void MainWindow::on_scriptwindow() {
Q_ASSERT(m_scriptDialog);
m_scriptDialog->show();
m_scriptDialog->raise();
}
void MainWindow::on_settingGeneral() { m_setdialog->showConfig(0); }
void MainWindow::on_settingScript() {
m_scriptDialog->settingDialog()->showConfig();
}
void MainWindow::on_settingPlugin() { m_setdialog->showConfig(2); }
void MainWindow::on_about() { AboutSoftwareDialog().exec(); }
void MainWindow::on_sponsor() {
// Github is not easy to access for Chinese people,
// Gitee mirror instead
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
if (LanguageManager::instance().defaultLocale().territory() ==
#else
if (LanguageManager::instance().defaultLocale().country() ==
#endif
QLocale::China) {
QDesktopServices::openUrl(
QUrl(QStringLiteral("https://gitee.com/wing-cloud/"
"WingHexExplorer2#%E6%8D%90%E5%8A%A9")));
} else {
QDesktopServices::openUrl(
QUrl(QStringLiteral("https://github.com/Wing-summer/"
"WingHexExplorer2#%E6%8D%90%E5%8A%A9")));
}
}
void MainWindow::on_wiki() {
QDesktopServices::openUrl(
QUrl(QStringLiteral("https://www.cnblogs.com/wingsummer/p/18286419")));
}
void MainWindow::on_update() {
showStatus(tr("CheckingUpdate"));
ExecAsync<int>(
[]() -> int {
bool ok = false;
auto newest = WingUpdater::checkUpdate(&ok);
if (ok) {
return newest ? 1 : 0;
} else {
return -1;
}
},
[this](int status) {
if (status < 0) {
WingMessageBox::critical(this, qAppName(), tr("BadNetwork"));
} else if (status == 0) {
WingMessageBox::warning(this, qAppName(), tr("OlderVersion"));
} else {
WingMessageBox::information(this, qAppName(),
tr("NewestVersion"));
}
this->showStatus({});
});
}
QString MainWindow::saveLog() {
QDir ndir(Utilities::getAppDataPath());
ndir.mkpath(QStringLiteral("log"));
QFile lfile(ndir.absolutePath() + QDir::separator() +
QStringLiteral("log") + QDir::separator() +
QDateTime::currentDateTime().toString(
QStringLiteral("yyyyMMddhhmmsszzz")) +
".log");
if (lfile.open(QFile::WriteOnly | QFile::NewOnly)) {
lfile.write(m_logbrowser->toPlainText().toUtf8());
lfile.close();
return lfile.fileName();
}
return QString();
}
ads::CDockWidget *MainWindow::buildDockWidget(ads::CDockManager *dock,
const QString &widgetName,
const QString &displayName,
QWidget *content,
ToolButtonIndex index) {
using namespace ads;
auto dw = dock->createDockWidget(displayName, dock);
dw->setObjectName(widgetName);
dw->setFeatures(CDockWidget::DockWidgetMovable |
CDockWidget::DockWidgetClosable |
CDockWidget::DockWidgetPinnable);
dw->setWidget(content);
m_toolBtneditors.value(index)->menu()->addAction(dw->toggleViewAction());
return dw;
}
EditorView *MainWindow::findEditorView(const QString &filename) {
auto views = m_views.keys();
for (auto &p : views) {
#ifdef Q_OS_WIN
if (p->fileName().compare(filename, Qt::CaseInsensitive) == 0) {
#else
if (p->fileName() == filename) {
#endif
return p;
}
}
return nullptr;
}
bool MainWindow::newOpenFileSafeCheck() {
if (m_views.size() >=
std::numeric_limits<decltype(m_views)::size_type>::max() - 1) {
WingMessageBox::critical(this, tr("Error"),
tr("Too much opened files"));
return false;
}
return true;
}
void MainWindow::registerEditorView(EditorView *editor, const QString &ws) {
for (auto p = m_editorViewWidgets.constKeyValueBegin();
p != m_editorViewWidgets.constKeyValueEnd(); p++) {
for (auto &w : p->second) {
auto v = w->create(editor);
auto id = w->id();
editor->registerView(id, v);
connect(v, &WingEditorViewWidget::savedStateChanged, this,
[editor](bool saved) {
editor->hexEditor()->document()->setDocSaved(saved);
});
}
}
for (auto &m : _scriptContexts) {
editor->registerQMenu(m);
}
for (auto &m : m_hexContextMenu) {
editor->registerQMenu(m);
}
auto &set = SettingManager::instance();
editor->setCopyLimit(set.copylimit());
editor->setFontSize(set.editorfontSize());
connectEditorView(editor);
connect(editor, &EditorView::closeRequested, this, [this] {
auto editor = qobject_cast<EditorView *>(sender());
Q_ASSERT(editor);
Q_ASSERT(m_views.contains(editor));
// the plugin view should explain itself why preventing closing
if (!editor->processWingEditorViewClosing()) {
return;
}
if (editor->hasCloneChildren()) {
auto ret =
WingMessageBox::question(this, tr("Warn"), tr("HasClonedView"));
if (ret == QMessageBox::Yes) {
editor->closeAllClonedChildren();
} else {
return;
}
}
auto ret = closeEditor(editor, false);
if (ret == ErrFile::UnSaved || ret == ErrFile::WorkSpaceUnSaved) {
auto ret = this->saveRequest();
if (ret == QMessageBox::Cancel) {
return;
} else if (ret == QMessageBox::Yes) {
auto ret = saveEditor(editor, {});
switch (ret) {
case WingHex::Success:
// ok, no need to report
closeEditor(editor, false);
break;
case WingHex::Permission: {
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("FilePermissionSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
case WingHex::Error:
case WingHex::UnSaved:
case WingHex::NotExist:
case WingHex::AlreadyOpened:
case WingHex::IsNewFile:
case WingHex::ClonedFile:
case WingHex::InvalidFormat:
case WingHex::TooManyOpenedFile:
case WingHex::DevNotFound:
case WingHex::NotAllowedInNoneGUIThread: {
// unknown error
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("UnknownErrorSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
case WingHex::WorkSpaceUnSaved: {
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("WorkSpaceUnSavedSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
break;
}
} else {
closeEditor(editor, true);
}
}
if (m_views.isEmpty()) {
updateEditModeEnabled();
}
});
m_views.insert(editor, ws);
auto ev = m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS);
auto menu = ev->menu();
Q_ASSERT(menu);
auto ta = editor->toggleViewAction();
menu->addAction(ta);
ev->setEnabled(true);
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileOpened,
{editor->fileName(),
QVariant::fromValue(getEditorViewFileType(editor))});
}
void MainWindow::registerClonedEditorView(EditorView *editor) {
for (auto &m : m_hexContextMenu) {
editor->registerQMenu(m);
}
auto ev = m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS);
auto menu = ev->menu();
Q_ASSERT(menu);
auto ta = editor->toggleViewAction();
menu->addAction(ta);
ev->setEnabled(true);
connect(editor, &EditorView::closeRequested, this, [=]() {
adjustEditorFocus(editor);
editor->closeDockWidget();
});
}
void MainWindow::connectEditorView(EditorView *editor) {
Q_ASSERT(editor);
connect(editor, &EditorView::sigOnFill, this, &MainWindow::on_fill);
connect(editor, &EditorView::sigOnCutHex, this, &MainWindow::on_cuthex);
connect(editor, &EditorView::sigOnDelete, this, &MainWindow::on_delete);
connect(editor, &EditorView::sigOnCopyHex, this, &MainWindow::on_copyhex);
connect(editor, &EditorView::sigOnCutFile, this, &MainWindow::on_cutfile);
connect(editor, &EditorView::sigOnBookMark, this, &MainWindow::on_bookmark);
connect(editor, &EditorView::sigOnCopyFile, this, &MainWindow::on_copyfile);
connect(editor, &EditorView::sigOnFindFile, this, &MainWindow::on_findfile);
connect(editor, &EditorView::sigOnGoToLine, this, &MainWindow::on_gotoline);
connect(editor, &EditorView::sigOnMetadata, this, [=] {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
auto doc = hexeditor->document();
if (hexeditor->documentBytes() > 0) {
MetaDialog m(this);
auto cur = hexeditor->cursor();
if (cur->hasSelection()) {
auto total = hexeditor->selectionCount();
if (m.exec()) {
auto meta = doc->metadata();
meta->beginMarco(QStringLiteral("OnMetaData"));
for (int i = 0; i < total; ++i) {
auto begin = cur->selectionStart(i).offset();
auto end = cur->selectionEnd(i).offset();
meta->Metadata(begin, end, m.foreGroundColor(),
m.backGroundColor(), m.comment());
}
meta->endMarco();
cur->clearSelection();
}
} else {
auto md = doc->metadata()->get(cur->position().offset());
if (md.has_value()) {
auto meta = md.value();
auto begin = meta.begin;
auto end = meta.end;
m.setForeGroundColor(meta.foreground);
m.setBackGroundColor(meta.background);
m.setComment(meta.comment);
if (m.exec()) {
auto mi = hexeditor->document()->metadata();
QHexMetadataItem o;
o.begin = begin;
o.end = end;
o.foreground = m.foreGroundColor();
o.background = m.backGroundColor();
o.comment = m.comment();
mi->ModifyMetadata(o, meta);
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
tr("NoSelection"));
}
}
}
});
connect(editor, &EditorView::sigOnPasteHex, this, &MainWindow::on_pastehex);
connect(editor, &EditorView::sigOnPasteFile, this,
&MainWindow::on_pastefile);
editor->setProperty("__RELOAD__", false);
connect(editor, &EditorView::need2Reload, this, [editor, this]() {
if (editor->isBigFile()) {
auto fileName = editor->fileName();
if (!QFile::exists(fileName)) {
activateWindow();
raise();
editor->raise();
WingMessageBox::critical(this, tr("Error"),
tr("FileCloseBigFile"));
closeEditor(editor, true);
}
if (currentEditor() == editor) {
editor->reload();
} else {
editor->setProperty("__RELOAD__", true);
}
} else {
editor->hexEditor()->document()->setDocSaved(false);
if (currentEditor() == editor) {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
editor->reload();
}
} else {
editor->setProperty("__RELOAD__", true);
}
}
});
}
void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
if (old == cur) {
return;
}
if (old != nullptr) {
auto hexeditor = old->hexEditor();
hexeditor->disconnect(SIGNAL(cursorLocationChanged()), this);
hexeditor->disconnect(SIGNAL(cursorSelectionChanged()), this);
hexeditor->disconnect(SIGNAL(canUndoChanged(bool)), this);
hexeditor->disconnect(SIGNAL(canRedoChanged(bool)), this);
hexeditor->disconnect(SIGNAL(documentSaved(bool)), this);
hexeditor->disconnect(SIGNAL(documentKeepSize(bool)), this);
hexeditor->disconnect(SIGNAL(documentLockedFile(bool)), this);
hexeditor->disconnect(SIGNAL(copyLimitRaised()), this);
hexeditor->disconnect(SIGNAL(scaleRateChanged()), this);
auto doc = hexeditor->document();
doc->disconnect(m_aShowMetabg);
doc->disconnect(m_aShowMetafg);
doc->disconnect(m_aShowMetaComment);
}
Q_ASSERT(cur);
auto hexeditor = cur->hexEditor();
auto needReload = cur->property("__RELOAD__").toBool();
if (needReload) {
if (cur->isBigFile()) {
cur->reload();
} else {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
cur->reload();
}
}
cur->setProperty("__RELOAD__", false);
}
connect(hexeditor, &QHexView::cursorLocationChanged, this,
&MainWindow::on_locChanged);
connect(hexeditor, &QHexView::cursorSelectionChanged, this,
&MainWindow::on_selectionChanged);
connect(hexeditor, &QHexView::canUndoChanged, this, [this](bool b) {
m_toolBtneditors[ToolButtonIndex::UNDO_ACTION]->setEnabled(b);
});
connect(hexeditor, &QHexView::canRedoChanged, this, [this](bool b) {
m_toolBtneditors[ToolButtonIndex::REDO_ACTION]->setEnabled(b);
});
connect(hexeditor, &QHexView::documentSaved, this, [this](bool b) {
m_iSaved->setIcon(b ? _infoSaved : _infoUnsaved);
m_sSaved->setIcon(b ? _infoSaved : _infoUnsaved);
});
connect(hexeditor, &QHexView::documentKeepSize, this, [this](bool b) {
m_iCanOver->setIcon(b ? _infoCannotOver : _infoCanOver);
m_sCanOver->setIcon(b ? _infoCannotOver : _infoCanOver);
});
connect(hexeditor, &QHexView::documentLockedFile, this, [this](bool b) {
m_iLocked->setIcon(b ? _infoLock : _infoUnLock);
m_sLocked->setIcon(b ? _infoLock : _infoUnLock);
});
connect(hexeditor, &QHexView::copyLimitRaised, this, [this] {
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
tr("CopyLimit"));
});
connect(hexeditor, &QHexView::scaleRateChanged, this, [this] {
auto hexeditor = qobject_cast<QHexView *>(QObject::sender());
Q_ASSERT(hexeditor);
Toast::toast(this, NAMEICONRES(QStringLiteral("scale")),
QString::number(hexeditor->scaleRate() * 100) +
QStringLiteral("%"));
});
auto menu = m_toolBtneditors.value(EDITOR_WINS)->menu();
for (auto &a : menu->actions()) {
auto id = a->property("__ID__").toString();
if (id.isEmpty()) {
continue;
}
a->setEnabled(cur->isWingEditorViewEnabled(id));
}
auto doc = hexeditor->document().get();
m_aShowMetabg->setChecked(doc->metabgVisible());
m_aShowMetafg->setChecked(doc->metafgVisible());
m_aShowMetaComment->setChecked(doc->metaCommentVisible());
connect(doc, &QHexDocument::metabgVisibleChanged, m_aShowMetabg,
&QAction::setChecked);
connect(doc, &QHexDocument::metafgVisibleChanged, m_aShowMetafg,
&QAction::setChecked);
connect(doc, &QHexDocument::metaCommentVisibleChanged, m_aShowMetaComment,
&QAction::setChecked);
auto icon = hexeditor->isReadOnly() ? _infoReadonly : _infoWriteable;
m_iReadWrite->setIcon(icon);
m_sReadWrite->setIcon(icon);
loadFindResult(cur);
auto bm = cur->bookmarksModel();
m_bookmarks->setModel(bm);
connect(m_bookmarks->selectionModel(),
&QItemSelectionModel::selectionChanged, m_aDelBookMark,
[=](const QItemSelection &, const QItemSelection &) {
m_aDelBookMark->setEnabled(
m_bookmarks->selectionModel()->hasSelection());
});
auto md = cur->metadataModel();
m_metadatas->setModel(md);
connect(m_metadatas->selectionModel(),
&QItemSelectionModel::selectionChanged, m_aDelMetaData,
[=](const QItemSelection &, const QItemSelection &) {
m_aDelMetaData->setEnabled(
m_metadatas->selectionModel()->hasSelection());
});
m_curEditor = cur;
hexeditor->getStatus();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileSwitched,
{cur->fileName(), (old ? old->fileName() : QString())});
}
void MainWindow::loadFindResult(EditorView *view) {
auto result = view->findResultModel();
m_findresult->setModel(result);
m_findEncoding.value(result->encoding())->setChecked(true);
m_findresult->setProperty("EditorView", QVariant::fromValue(view));
}
void MainWindow::openFiles(const QStringList &files) {
bool err = false;
QStringList errof;
for (auto &file : files) {
if (openFile(file, nullptr)) {
err = true;
errof << file;
}
}
show();
raise();
activateWindow();
if (err) {
WingMessageBox::critical(this, tr("Error"),
tr("ErrOpenFileBelow") + QStringLiteral("\n") +
errof.join('\n'));
}
}
ErrFile MainWindow::openFile(const QString &file, EditorView **editor) {
auto e = findEditorView(file);
if (e) {
if (editor) {
*editor = e;
}
return ErrFile::AlreadyOpened;
}
// ok, going on
if (!newOpenFileSafeCheck()) {
return ErrFile::Error;
}
QFileInfo finfo(file);
auto filename = finfo.absoluteFilePath();
auto ev = new EditorView(this);
auto res = ev->openFile(filename);
if (res != ErrFile::Success) {
delete ev;
return res;
}
registerEditorView(ev);
if (editor) {
*editor = ev;
}
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
ev->setFocus();
return ErrFile::Success;
}
ErrFile MainWindow::openExtFile(const QString &ext, const QString &file,
EditorView **editor) {
auto e = findEditorView(EditorView::getDeviceFileName(ext, file));
if (e) {
if (editor) {
*editor = e;
}
return ErrFile::AlreadyOpened;
}
auto ev = new EditorView(this);
auto res = ev->openExtFile(ext, file);
if (res != ErrFile::Success) {
delete ev;
return res;
}
registerEditorView(ev);
if (editor) {
*editor = ev;
}
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
ev->setFocus();
return ErrFile::Success;
}
ErrFile MainWindow::openWorkSpace(const QString &file, EditorView **editor) {
// different from other common files
for (auto p = m_views.constKeyValueBegin(); p != m_views.constKeyValueEnd();
++p) {
#ifdef Q_OS_WIN
if (p->second.compare(file, Qt::CaseInsensitive) == 0) {
#else
if (p->second == file) {
#endif
if (editor) {
*editor = p->first;
}
return ErrFile::AlreadyOpened;
}
}
// ok, going on
if (!newOpenFileSafeCheck()) {
return ErrFile::Error;
}
QFileInfo finfo(file);
auto filename = finfo.absoluteFilePath();
auto ev = new EditorView(this);
auto res = ev->openWorkSpace(filename);
if (res != ErrFile::Success) {
delete ev;
return res;
}
registerEditorView(ev, file);
if (editor) {
*editor = ev;
}
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
ev->setFocus();
return ErrFile::Success;
}
ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
bool isExport, bool forceWorkspace,
QString *ws) {
if (editor == nullptr) {
return ErrFile::Error;
}
auto isNewFile = editor->isNewFile();
if (isNewFile && filename.isEmpty()) {
return ErrFile::IsNewFile;
}
auto oldName = editor->fileName();
auto newName = filename.isEmpty() ? oldName : filename;
QString workspace = m_views.value(editor);
if (forceWorkspace || workspace.isEmpty()) {
if (forceWorkspace || editor->change2WorkSpace()) {
QString curFile;
if (!editor->isExtensionFile()) {
curFile = newName + PROEXT;
}
auto wsfile = getWorkSpaceFileName(curFile);
if (wsfile.isEmpty()) {
return ErrFile::WorkSpaceUnSaved;
}
workspace = wsfile;
}
}
if (ws) {
*ws = workspace;
}
auto ret = editor->save(workspace, filename, isExport,
forceWorkspace
? EditorView::SaveWorkSpaceAttr::ForceWorkSpace
: EditorView::SaveWorkSpaceAttr::AutoWorkSpace);
if (ret == ErrFile::Success) {
m_views[editor] = workspace;
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileSaved,
{newName, oldName, isExport,
QVariant::fromValue(getEditorViewFileType(editor))});
}
return ret;
}
ErrFile MainWindow::closeEditor(EditorView *editor, bool force) {
if (editor == nullptr) {
return ErrFile::Error;
}
if (!editor->isCloneFile()) {
auto hexeditor = editor->hexEditor();
if (!force) {
if (!hexeditor->isSaved()) {
return ErrFile::UnSaved;
}
}
}
auto cret = editor->closeFile();
if (cret != ErrFile::Success) {
return cret;
}
m_views.remove(editor);
if (currentEditor() == editor) {
_editorLock.lockForWrite();
m_curEditor = nullptr;
_editorLock.unlock();
}
auto fileName = editor->fileName();
auto &plgsys = PluginSystem::instance();
plgsys.cleanUpEditorViewHandle(editor);
plgsys.dispatchEvent(
IWingPlugin::RegisteredEvent::FileClosed,
{fileName, QVariant::fromValue(getEditorViewFileType(editor))});
editor->closeDockWidget();
m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS)
->setEnabled(m_views.size() != 0);
adjustEditorFocus(editor);
return ErrFile::Success;
}
IWingPlugin::FileType MainWindow::getEditorViewFileType(EditorView *view) {
Q_ASSERT(view);
switch (view->documentType()) {
case EditorView::DocumentType::File:
return IWingPlugin::FileType::File;
case EditorView::DocumentType::Extension:
return IWingPlugin::FileType::Extension;
case EditorView::DocumentType::Cloned:
return getEditorViewFileType(view->cloneParent());
break;
default:
Q_ASSERT(false);
break;
}
return IWingPlugin::FileType::Invalid;
}
void MainWindow::updateEditModeEnabled() {
auto editor = currentEditor();
auto b = (editor != nullptr);
for (auto &item : m_editStateWidgets) {
item->setEnabled(b);
}
if (b) {
auto hexeditor = editor->hexEditor();
auto doc = hexeditor->document();
m_toolBtneditors[ToolButtonIndex::REDO_ACTION]->setEnabled(
doc->canRedo());
m_toolBtneditors[ToolButtonIndex::UNDO_ACTION]->setEnabled(
doc->canUndo());
} else {
m_lblloc->setText(QStringLiteral("(0,0)"));
m_lblsellen->setText(QStringLiteral("0 - 0x0"));
_numsitem->clear();
}
}
void MainWindow::setCurrentHexEditorScale(qreal rate) {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
hexeditor->setScaleRate(rate);
}
EditorView *MainWindow::currentEditor() {
if (QThread::currentThread() != this->thread()) {
_editorLock.lockForRead();
auto ret = m_curEditor;
_editorLock.unlock();
return ret;
}
return m_curEditor;
}
void MainWindow::adjustEditorFocus(EditorView *closedEditor) {
if (m_dock->focusedDockWidget() == closedEditor) {
if (!m_views.isEmpty()) {
for (auto p = m_views.keyBegin(); p != m_views.keyEnd(); ++p) {
auto ev = *p;
if (ev != closedEditor && ev->isCurrentTab()) {
ev->setFocus();
}
}
}
}
}
QString MainWindow::getWorkSpaceFileName(const QString &curFile) {
return WingFileDialog::getSaveFileName(this, tr("SaveWorkSpace"), curFile,
tr("WingHexWorkSpace (*.wingpro)"));
}
void MainWindow::saveTableContent(QAbstractItemModel *model) {
if (!model || model->rowCount() == 0) {
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
tr("NothingToSave"));
return;
}
QString selFilter;
auto filename = WingFileDialog::getSaveFileName(
this, tr("ChooseSaveFile"), m_lastusedpath,
QStringLiteral("Json (*.json);;CSV (*.csv)"), &selFilter);
if (filename.isEmpty()) {
return;
}
if (selFilter.startsWith(QStringLiteral("Json"))) {
QJsonArray tableData;
// Add header row
QJsonArray headers;
for (int col = 0; col < model->columnCount(); ++col) {
headers.append(model->headerData(col, Qt::Horizontal).toString());
}
tableData.append(headers);
// Add data rows
for (int row = 0; row < model->rowCount(); ++row) {
QJsonArray rowData;
for (int col = 0; col < model->columnCount(); ++col) {
QModelIndex index = model->index(row, col);
rowData.append(model->data(index).toString());
}
tableData.append(rowData);
}
// Create JSON document
QJsonDocument jsonDocument(tableData);
// Write to file
QFile file(filename);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
return;
}
file.write(jsonDocument.toJson(QJsonDocument::Indented));
file.close();
} else {
QFile file(filename);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
return;
}
QTextStream stream(&file);
// Write headers
QStringList headers;
for (int col = 0; col < model->columnCount(); ++col) {
auto content = model->headerData(col, Qt::Horizontal).toString();
content.prepend('"').append('"');
headers << content;
}
stream << headers.join(',') << Qt::endl;
// Write data rows
for (int row = 0; row < model->rowCount(); ++row) {
QStringList rowData;
for (int col = 0; col < model->columnCount(); ++col) {
QModelIndex index = model->index(row, col);
auto content = model->data(index).toString();
content.prepend('"').append('"');
rowData << content;
}
stream << rowData.join(',') << Qt::endl;
}
file.close();
}
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
tr("SaveSuccessfully"));
}
QHexView *MainWindow::currentHexView() {
auto editor = currentEditor();
if (editor == nullptr) {
return nullptr;
}
return editor->hexEditor();
}
void MainWindow::loadCacheIcon() {
_infoSaved = ICONRES(QStringLiteral("saved"));
_infoUnsaved = ICONRES(QStringLiteral("unsaved"));
_infoWriteable = ICONRES(QStringLiteral("writable"));
_infoReadonly = ICONRES(QStringLiteral("readonly"));
_infoUnLock = ICONRES(QStringLiteral("unlock"));
_infoLock = ICONRES(QStringLiteral("lock"));
_infoCanOver = ICONRES(QStringLiteral("canover"));
_infoCannotOver = ICONRES(QStringLiteral("unover"));
_pixLock = QPixmap(NAMEICONRES("lock"));
_pixCanOver = QPixmap(NAMEICONRES("canover"));
_pixCannotOver = QPixmap(NAMEICONRES("unover"));
}
QMessageBox::StandardButton MainWindow::saveRequest() {
auto ret = WingMessageBox::warning(this, qAppName(), tr("ConfirmSave"),
QMessageBox::Yes | QMessageBox::No |
QMessageBox::Cancel);
return ret;
}
ads::CDockAreaWidget *MainWindow::editorViewArea() const {
return m_dock->centralWidget()->dockAreaWidget();
}
void MainWindow::onOutputBgScriptOutput(
const ScriptMachine::MessageInfo &message) {
static QPair<ScriptMachine::MessageType, QPair<int, int>> lastInfo{
ScriptMachine::MessageType::Print, {-1, -1}};
auto doc = m_bgScriptOutput->document();
auto lastLine = doc->lastBlock();
auto isNotBlockStart = !lastLine.text().isEmpty();
auto cursor = m_bgScriptOutput->textCursor();
cursor.movePosition(QTextCursor::End);
auto fmtMsg = [](const ScriptMachine::MessageInfo &message) -> QString {
if (message.row <= 0 || message.col <= 0) {
return message.message;
} else {
return QStringLiteral("(") + QString::number(message.row) +
QStringLiteral(", ") + QString::number(message.col) +
QStringLiteral(")") + message.message;
}
};
auto isMatchLast = [](const ScriptMachine::MessageInfo &message) -> bool {
if (message.row < 0 || message.col < 0) {
return false;
}
return lastInfo.first == message.type &&
lastInfo.second.first == message.row &&
lastInfo.second.second == message.col;
};
switch (message.type) {
case ScriptMachine::MessageType::Info:
if (isMatchLast(message)) {
cursor.insertText(message.message);
} else {
if (isNotBlockStart) {
cursor.insertBlock();
}
cursor.insertText(tr("[Info]") + fmtMsg(message));
}
break;
case ScriptMachine::MessageType::Warn:
if (isMatchLast(message)) {
auto fmt = cursor.charFormat();
fmt.setForeground(QColorConstants::Svg::gold);
cursor.insertText(message.message, fmt);
} else {
if (isNotBlockStart) {
m_bgScriptOutput->appendPlainText({});
}
auto fmt = cursor.charFormat();
fmt.setForeground(QColorConstants::Svg::gold);
cursor.insertText(tr("[Warn]") + fmtMsg(message), fmt);
}
break;
case ScriptMachine::MessageType::Error:
if (isMatchLast(message)) {
auto fmt = cursor.charFormat();
fmt.setForeground(Qt::red);
cursor.insertText(message.message, fmt);
} else {
if (isNotBlockStart) {
cursor.insertBlock();
}
auto fmt = cursor.charFormat();
fmt.setForeground(Qt::red);
cursor.insertText(tr("[Error]") + fmtMsg(message), fmt);
}
break;
case ScriptMachine::MessageType::Print:
if (lastInfo.first != message.type) {
cursor.insertBlock();
}
cursor.insertText(message.message);
break;
}
lastInfo.first = message.type;
lastInfo.second = qMakePair(message.row, message.col);
}
void MainWindow::closeEvent(QCloseEvent *event) {
// plugin first checking
auto closing = PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::AppClosing, {});
if (!closing) {
event->ignore();
return;
}
// then checking the scripting dialog
if (m_scriptDialog) {
if (!m_scriptDialog->about2Close()) {
event->ignore();
return;
}
// then abort all script running
ScriptMachine::instance().abortScript();
}
// then checking itself
if (!m_views.isEmpty()) {
QStringList unSavedFiles;
QList<EditorView *> need2CloseView;
for (auto p = m_views.keyBegin(); p != m_views.keyEnd(); p++) {
auto editor = *p;
bool saved = editor->hexEditor()->isSaved();
if (saved) {
need2CloseView << editor;
} else {
unSavedFiles << editor->fileName();
}
}
for (auto &view : need2CloseView) {
view->requestCloseDockWidget();
}
auto ret =
unSavedFiles.isEmpty()
? QMessageBox::No
: WingMessageBox::warning(
this, qAppName(), tr("ConfirmAPPSave"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (ret == QMessageBox::Yes) {
for (auto pview = m_views.constKeyValueBegin();
pview != m_views.constKeyValueEnd(); ++pview) {
pview->first->save(pview->second, {});
pview->first->requestCloseDockWidget();
}
if (!m_views.isEmpty()) {
event->ignore();
return;
}
} else if (ret == QMessageBox::No) {
auto views = m_views.keys();
for (auto &p : views) {
p->closeDockWidget(); // force close
}
} else {
event->ignore();
return;
}
}
auto &set = SettingManager::instance();
set.setDockLayout(m_dock->saveState());
if (m_scriptDialog) {
m_scriptDialog->saveDockLayout();
set.setRecentFiles(m_recentmanager->saveRecent());
set.save();
}
PluginSystem::instance().destory();
FramelessMainWindow::closeEvent(event);
emit closed();
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event) {
Q_UNUSED(watched);
if (isVisible()) {
if (event->type() == QEvent::Shortcut) {
auto e = reinterpret_cast<QShortcutEvent *>(event);
if (m_scriptConsole) {
if (m_scriptConsole->hasFocus()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto k = e->key()[0];
QKeyEvent ev(QEvent::KeyPress, k.key(),
k.keyboardModifiers());
m_scriptConsole->processKeyEvent(&ev);
#else
auto key = e->key()[0];
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
// Determine modifiers (simplified logic)
if (key & Qt::SHIFT)
modifiers |= Qt::ShiftModifier;
if (key & Qt::CTRL)
modifiers |= Qt::ControlModifier;
if (key & Qt::ALT)
modifiers |= Qt::AltModifier;
if (key & Qt::META)
modifiers |= Qt::MetaModifier;
// Filter out the modifiers from the key itself
key &= ~Qt::KeyboardModifierMask;
QKeyEvent ev(QEvent::KeyPress, key, modifiers);
m_scriptConsole->processKeyEvent(&ev);
#endif
return true;
}
}
}
}
return FramelessMainWindow::eventFilter(watched, event);
}