3654 lines
124 KiB
C++
3654 lines
124 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/eventfilter.h"
|
|
#include "class/langservice.h"
|
|
#include "class/languagemanager.h"
|
|
#include "class/layoutmanager.h"
|
|
#include "class/logger.h"
|
|
#include "class/qkeysequences.h"
|
|
#include "class/richtextitemdelegate.h"
|
|
#include "class/scriptconsolemachine.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 "driverselectordialog.h"
|
|
#include "encodingdialog.h"
|
|
#include "fileinfodialog.h"
|
|
#include "finddialog.h"
|
|
#include "metadialog.h"
|
|
#include "openregiondialog.h"
|
|
#include "plugin/pluginsystem.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 <QKeyEvent>
|
|
#include <QPainter>
|
|
#include <QPicture>
|
|
#include <QPushButton>
|
|
#include <QRadioButton>
|
|
#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, rinfo.start, rinfo.stop);
|
|
});
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
// 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.LoadPlugin();
|
|
|
|
if (set.scriptEnabled()) {
|
|
// At this time, AngelScript service plugin has started
|
|
if (splash)
|
|
splash->setInfoText(tr("SetupConsole"));
|
|
m_scriptConsole->init();
|
|
if (splash)
|
|
splash->setInfoText(tr("SetupScriptManager"));
|
|
ScriptManager::instance().attach(m_scriptConsole);
|
|
|
|
if (splash)
|
|
splash->setInfoText(tr("SetupScriptService"));
|
|
auto &langins = LangService::instance();
|
|
langins.init(m_scriptConsole->machine()->engine());
|
|
langins.applyLanguageSerivce(m_scriptConsole);
|
|
|
|
m_scriptConsole->initOutput();
|
|
m_scriptConsole->machine()->setInsteadFoundDisabled(true);
|
|
|
|
if (splash)
|
|
splash->setInfoText(tr("SetupScriptEditor"));
|
|
m_scriptDialog = new ScriptingDialog(this);
|
|
m_scriptDialog->initConsole();
|
|
|
|
// load the model
|
|
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
|
|
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
|
|
|
|
plg.angelApi()->setBindingConsole(m_scriptConsole);
|
|
}
|
|
|
|
// 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_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_editStateWidgets << (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();
|
|
|
|
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();
|
|
});
|
|
|
|
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();
|
|
buildUpScriptObjShowDock(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();
|
|
}
|
|
|
|
buildUpVisualDataDock(m_dock, ads::CenterDockWidgetArea, bottomLeftArea);
|
|
qApp->processEvents();
|
|
|
|
m_bottomViewArea = bottomRightArea;
|
|
}
|
|
|
|
void MainWindow::finishBuildDockSystem() {
|
|
// 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);
|
|
|
|
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);
|
|
auto header = m_findresult->horizontalHeader();
|
|
|
|
m_findresult->setContextMenuPolicy(
|
|
Qt::ContextMenuPolicy::CustomContextMenu);
|
|
|
|
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);
|
|
}
|
|
});
|
|
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);
|
|
|
|
header->setSectionResizeMode(3, QHeaderView::Stretch);
|
|
header->setSectionResizeMode(4, QHeaderView::Stretch);
|
|
|
|
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().length());
|
|
}
|
|
});
|
|
|
|
auto dw = buildDockWidget(dock, QStringLiteral("FindResult"),
|
|
tr("FindResult"), m_findresult);
|
|
m_find = dw;
|
|
|
|
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"));
|
|
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 ¤t, 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();
|
|
m_littleEndian = new QAction(actionGroup);
|
|
m_littleEndian->setText(tr("LittleEndian"));
|
|
m_littleEndian->setCheckable(true);
|
|
m_littleEndian->setChecked(le);
|
|
connect(m_littleEndian, &QAction::triggered, this, [=] {
|
|
m_islittle = true;
|
|
this->on_locChanged();
|
|
});
|
|
m_numshowtable->addAction(m_littleEndian);
|
|
|
|
m_bigEndian = new QAction(actionGroup);
|
|
m_bigEndian->setText(tr("BigEndian"));
|
|
m_bigEndian->setCheckable(true);
|
|
m_bigEndian->setChecked(!le);
|
|
connect(m_bigEndian, &QAction::triggered, this, [=] {
|
|
m_islittle = false;
|
|
this->on_locChanged();
|
|
});
|
|
m_numshowtable->addAction(m_bigEndian);
|
|
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 = new QAction(m_hashtable);
|
|
a->setText(tr("Copy"));
|
|
connect(a, &QAction::triggered, this, [=] {
|
|
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);
|
|
connect(m_hashtable->selectionModel(),
|
|
&QItemSelectionModel::currentRowChanged, a,
|
|
[=](const QModelIndex ¤t, 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->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_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);
|
|
}
|
|
|
|
doc->RemoveBookMarks(pos);
|
|
});
|
|
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->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_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()));
|
|
}
|
|
|
|
hexeditor->document()->metadata()->RemoveMetadatas(pmetas);
|
|
});
|
|
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);
|
|
|
|
auto dw = buildDockWidget(dock, QStringLiteral("DecodeText"),
|
|
tr("DecodeText"), m_txtDecode);
|
|
return dock->addDockWidget(area, dw, areaw);
|
|
}
|
|
|
|
ads::CDockAreaWidget *
|
|
MainWindow::buildUpScriptConsoleDock(ads::CDockManager *dock,
|
|
ads::DockWidgetArea area,
|
|
ads::CDockAreaWidget *areaw) {
|
|
m_scriptConsole = new ScriptingConsole(this);
|
|
|
|
auto dw = buildDockWidget(dock, QStringLiteral("ScriptConsole"),
|
|
tr("ScriptConsole"), m_scriptConsole);
|
|
return dock->addDockWidget(area, dw, areaw);
|
|
}
|
|
|
|
ads::CDockAreaWidget *
|
|
MainWindow::buildUpScriptObjShowDock(ads::CDockManager *dock,
|
|
ads::DockWidgetArea area,
|
|
ads::CDockAreaWidget *areaw) {
|
|
m_varshowtable = new QTableViewExt(this);
|
|
m_varshowtable->setEditTriggers(QTableView::EditTrigger::DoubleClicked);
|
|
m_varshowtable->setSelectionBehavior(
|
|
QAbstractItemView::SelectionBehavior::SelectRows);
|
|
m_varshowtable->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
auto dw = buildDockWidget(dock, QStringLiteral("ScriptObjShow"),
|
|
tr("ScriptObjShow"), m_varshowtable);
|
|
return dock->addDockWidget(area, dw, areaw);
|
|
}
|
|
|
|
ads::CDockAreaWidget *
|
|
MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
|
|
ads::DockWidgetArea area,
|
|
ads::CDockAreaWidget *areaw) {
|
|
using namespace ads;
|
|
|
|
auto efilter = new EventFilter(QEvent::DynamicPropertyChange, this);
|
|
connect(efilter, &EventFilter::eventTriggered, this,
|
|
[this](QObject *obj, QEvent *event) {
|
|
auto e = static_cast<QDynamicPropertyChangeEvent *>(event);
|
|
constexpr auto ppname = "__TITLE__";
|
|
if (e->propertyName() == QByteArray(ppname)) {
|
|
auto title = obj->property(ppname).toString();
|
|
auto display = obj->property("__DISPLAY__").toString();
|
|
auto dock = reinterpret_cast<QDockWidget *>(
|
|
obj->property("__DOCK__").value<quintptr>());
|
|
if (dock) {
|
|
if (!title.isEmpty()) {
|
|
display += QStringLiteral("(") % title %
|
|
QStringLiteral(")");
|
|
}
|
|
dock->setWindowTitle(display);
|
|
}
|
|
}
|
|
});
|
|
|
|
constexpr auto dpname = "__DISPLAY__";
|
|
constexpr auto dockpname = "__DOCK__";
|
|
|
|
m_infolist = new QListView(this);
|
|
m_infolist->setEditTriggers(QListView::EditTrigger::NoEditTriggers);
|
|
connect(m_infolist, &QListView::clicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infoclickfn) {
|
|
m_infoclickfn(index);
|
|
}
|
|
});
|
|
connect(m_infolist, &QListView::doubleClicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infodblclickfn) {
|
|
m_infodblclickfn(index);
|
|
}
|
|
});
|
|
auto dw = buildDockWidget(dock, QStringLiteral("DVList"), tr("DVList"),
|
|
m_infolist);
|
|
m_infolist->setProperty(dpname, tr("DVList"));
|
|
m_infolist->setProperty(dockpname, quintptr(dw));
|
|
m_infolist->installEventFilter(efilter);
|
|
m_infolist->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
m_infolist->addAction(
|
|
newAction(QStringLiteral("copy"), tr("Copy"), [this]() {
|
|
auto idx = m_infolist->currentIndex();
|
|
if (idx.isValid()) {
|
|
qApp->clipboard()->setText(
|
|
m_infolist->model()->data(idx).toString());
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
|
|
tr("CopyToClipBoard"));
|
|
}
|
|
}));
|
|
m_infolist->addAction(
|
|
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
|
|
auto model = m_infotable->model();
|
|
if (!model) {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("NothingToSave"));
|
|
return;
|
|
}
|
|
|
|
auto filename = WingFileDialog::getSaveFileName(
|
|
this, tr("ChooseSaveFile"), m_lastusedpath,
|
|
QStringLiteral("TXT (*.txt)"));
|
|
if (filename.isEmpty()) {
|
|
return;
|
|
}
|
|
QFile f(filename);
|
|
if (!f.open(QFile::WriteOnly | QFile::Text)) {
|
|
WingMessageBox::critical(this, tr("Error"),
|
|
tr("FilePermission"));
|
|
return;
|
|
}
|
|
|
|
auto total = model->rowCount();
|
|
for (int i = 0; i < total; ++i) {
|
|
f.write(model->data(model->index(i, 0)).toString().toUtf8());
|
|
f.write("\n");
|
|
}
|
|
f.close();
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSuccessfully"));
|
|
}));
|
|
m_infolist->addAction(
|
|
newAction(QStringLiteral("del"), tr("ClearResult"), [this]() {
|
|
auto model = m_infolist->model();
|
|
model->removeRows(0, model->rowCount());
|
|
}));
|
|
auto ar = dock->addDockWidget(area, dw, areaw);
|
|
|
|
m_infotree = new QTreeView(this);
|
|
m_infotree->setEditTriggers(QTreeView::EditTrigger::NoEditTriggers);
|
|
connect(m_infotree, &QTreeView::clicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infotreeclickfn) {
|
|
m_infotreeclickfn(index);
|
|
}
|
|
});
|
|
connect(m_infotree, &QTreeView::doubleClicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infotreedblclickfn) {
|
|
m_infotreedblclickfn(index);
|
|
}
|
|
});
|
|
dw = buildDockWidget(dock, QStringLiteral("DVTree"), tr("DVTree"),
|
|
m_infotree);
|
|
m_infotree->setProperty(dpname, tr("DVTree"));
|
|
m_infotree->setProperty(dockpname, quintptr(dw));
|
|
m_infotree->installEventFilter(efilter);
|
|
m_infotree->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
m_infotree->addAction(
|
|
newAction(QStringLiteral("copy"), tr("Copy"), [this]() {
|
|
auto idx = m_infotree->currentIndex();
|
|
if (idx.isValid()) {
|
|
qApp->clipboard()->setText(
|
|
m_infotree->model()->data(idx).toString());
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
|
|
tr("CopyToClipBoard"));
|
|
}
|
|
}));
|
|
m_infotree->addAction(
|
|
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
|
|
auto model = m_infotable->model();
|
|
if (!model) {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("NothingToSave"));
|
|
return;
|
|
}
|
|
|
|
auto filename = WingFileDialog::getSaveFileName(
|
|
this, tr("ChooseSaveFile"), m_lastusedpath,
|
|
QStringLiteral("Json (*.json)"));
|
|
if (filename.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QJsonArray rootArray;
|
|
for (int row = 0; row < model->rowCount(); ++row) {
|
|
QModelIndex index = model->index(row, 0);
|
|
rootArray.append(extractModelData(model, index));
|
|
}
|
|
|
|
QJsonDocument jsonDocument(rootArray);
|
|
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();
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSuccessfully"));
|
|
}));
|
|
m_infotree->addAction(
|
|
newAction(QStringLiteral("del"), tr("ClearResult"), [this]() {
|
|
auto model = m_infotree->model();
|
|
model->removeRows(0, model->rowCount());
|
|
}));
|
|
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
|
|
|
|
m_infotable = new QTableView(this);
|
|
m_infotable->setEditTriggers(QTableView::EditTrigger::NoEditTriggers);
|
|
connect(m_infotable, &QTableView::clicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infotableclickfn) {
|
|
m_infotableclickfn(index);
|
|
}
|
|
});
|
|
connect(m_infotable, &QTableView::doubleClicked, this,
|
|
[this](const QModelIndex &index) {
|
|
if (m_infotabledblclickfn) {
|
|
m_infotabledblclickfn(index);
|
|
}
|
|
});
|
|
dw = buildDockWidget(dock, QStringLiteral("DVTable"), tr("DVTable"),
|
|
m_infotable);
|
|
m_infotable->setProperty(dpname, tr("DVTable"));
|
|
m_infotable->setProperty(dockpname, quintptr(dw));
|
|
m_infotable->installEventFilter(efilter);
|
|
m_infotable->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
m_infotable->addAction(
|
|
newAction(QStringLiteral("copy"), tr("Copy"), [this]() {
|
|
auto idx = m_infotable->currentIndex();
|
|
if (idx.isValid()) {
|
|
qApp->clipboard()->setText(
|
|
m_infotable->model()->data(idx).toString());
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("copy")),
|
|
tr("CopyToClipBoard"));
|
|
}
|
|
}));
|
|
m_infotable->addAction(
|
|
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
|
|
auto model = m_infotable->model();
|
|
if (!model) {
|
|
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"));
|
|
}));
|
|
m_infotable->addAction(
|
|
newAction(QStringLiteral("del"), tr("ClearResult"), [this]() {
|
|
auto model = m_infotable->model();
|
|
model->removeRows(0, model->rowCount());
|
|
}));
|
|
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
|
|
|
|
m_infotxt = new QTextBrowser(this);
|
|
dw = buildDockWidget(dock, QStringLiteral("DVText"), tr("DVText"),
|
|
m_infotxt);
|
|
m_infotxt->setProperty(dpname, tr("DVText"));
|
|
m_infotxt->setProperty(dockpname, quintptr(dw));
|
|
m_infotxt->installEventFilter(efilter);
|
|
m_infotxt->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
auto menu = m_infotxt->createStandardContextMenu();
|
|
menu->addSeparator();
|
|
menu->addAction(
|
|
newAction(QStringLiteral("export"), tr("ExportResult"), [this]() {
|
|
auto filename = WingFileDialog::getSaveFileName(
|
|
this, tr("ChooseSaveFile"), m_lastusedpath,
|
|
QStringLiteral("TXT (*.txt)"));
|
|
if (filename.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QFile file(filename);
|
|
if (!file.open(QFile::WriteOnly | QFile::Text)) {
|
|
WingMessageBox::critical(this, tr("Error"),
|
|
tr("FilePermission"));
|
|
return;
|
|
}
|
|
|
|
file.write(m_infotxt->toPlainText().toUtf8());
|
|
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSuccessfully"));
|
|
}));
|
|
menu->addAction(newAction(QStringLiteral("del"), tr("ClearResult"),
|
|
[this]() { m_infotxt->clear(); }));
|
|
connect(m_infotxt, &QTextBrowser::customContextMenuRequested, this,
|
|
[=](const QPoint &pos) {
|
|
menu->popup(m_infotxt->viewport()->mapToGlobal(pos));
|
|
});
|
|
|
|
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
|
|
|
|
return ar;
|
|
}
|
|
|
|
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("openr"), tr("OpenFR"),
|
|
&MainWindow::on_openregion,
|
|
shortcuts.keySequence(QKeySequences::Key::OPEN_REGION_FILE));
|
|
|
|
addPannelAction(
|
|
pannel, QStringLiteral("workspace"), tr("OpenWorkSpace"),
|
|
&MainWindow::on_openworkspace,
|
|
shortcuts.keySequence(QKeySequences::Key::OPEN_WORKSPACE));
|
|
|
|
addPannelAction(pannel, QStringLiteral("opendriver"), tr("OpenD"),
|
|
&MainWindow::on_opendriver);
|
|
|
|
addPannelAction(pannel, QStringLiteral("recent"), tr("RecentFiles"),
|
|
EMPTY_FUNC, {}, m_recentMenu);
|
|
|
|
auto a = addPannelAction(pannel, QStringLiteral("reload"), tr("Reload"),
|
|
&MainWindow::on_reload);
|
|
m_editStateWidgets << a;
|
|
m_cloneFileStateWidgets << 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("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"));
|
|
m_toolBtneditors.insert(
|
|
ToolButtonIndex::UNDO_ACTION,
|
|
addPannelAction(pannel, QStringLiteral("undo"), tr("Undo"),
|
|
&MainWindow::on_undofile, QKeySequence::Undo));
|
|
m_toolBtneditors.insert(
|
|
ToolButtonIndex::REDO_ACTION,
|
|
addPannelAction(pannel, QStringLiteral("redo"), tr("Redo"),
|
|
&MainWindow::on_redofile,
|
|
shortcuts.keySequence(QKeySequences::Key::REDO)));
|
|
addPannelAction(pannel, QStringLiteral("cut"), tr("Cut"),
|
|
&MainWindow::on_cutfile, QKeySequence::Cut);
|
|
addPannelAction(pannel, QStringLiteral("copy"), tr("Copy"),
|
|
&MainWindow::on_copyfile, QKeySequence::Copy);
|
|
addPannelAction(pannel, QStringLiteral("paste"), tr("Paste"),
|
|
&MainWindow::on_pastefile, QKeySequence::Paste);
|
|
addPannelAction(pannel, QStringLiteral("del"), tr("Delete"),
|
|
&MainWindow::on_delete, QKeySequence::Delete);
|
|
addPannelAction(pannel, QStringLiteral("clone"), tr("Clone"),
|
|
&MainWindow::on_clone);
|
|
}
|
|
|
|
{
|
|
auto pannel = tab->addGroup(tr("Lookup"));
|
|
addPannelAction(pannel, QStringLiteral("find"), tr("Find"),
|
|
&MainWindow::on_findfile, QKeySequence::Find);
|
|
|
|
addPannelAction(pannel, QStringLiteral("jmp"), tr("Goto"),
|
|
&MainWindow::on_gotoline,
|
|
shortcuts.keySequence(QKeySequences::Key::GOTO));
|
|
|
|
addPannelAction(pannel, QStringLiteral("encoding"), tr("Encoding"),
|
|
&MainWindow::on_encoding,
|
|
shortcuts.keySequence(QKeySequences::Key::ENCODING));
|
|
addPannelAction(pannel, QStringLiteral("sum"), tr("CheckSum"),
|
|
&MainWindow::on_checksum);
|
|
addPannelAction(pannel, QStringLiteral("info"), tr("FileInfo"),
|
|
&MainWindow::on_fileInfo,
|
|
shortcuts.keySequence(QKeySequences::Key::FILE_INFO));
|
|
}
|
|
|
|
{
|
|
auto pannel = tab->addGroup(tr("Hex"));
|
|
addPannelAction(pannel, QStringLiteral("cuthex"), tr("CutHex"),
|
|
&MainWindow::on_cuthex,
|
|
shortcuts.keySequence(QKeySequences::Key::CUT_HEX));
|
|
|
|
addPannelAction(pannel, QStringLiteral("copyhex"), tr("CopyHex"),
|
|
&MainWindow::on_copyhex,
|
|
shortcuts.keySequence(QKeySequences::Key::COPY_HEX));
|
|
addPannelAction(pannel, QStringLiteral("pastehex"), tr("PasteHex"),
|
|
&MainWindow::on_pastehex,
|
|
shortcuts.keySequence(QKeySequences::Key::PASTE_HEX));
|
|
addPannelAction(pannel, QStringLiteral("fill"), tr("Fill"),
|
|
&MainWindow::on_fill,
|
|
shortcuts.keySequence(QKeySequences::Key::HEX_FILL));
|
|
addPannelAction(pannel, QStringLiteral("fillZero"), tr("FillZero"),
|
|
&MainWindow::on_fillzero,
|
|
shortcuts.keySequence(QKeySequences::Key::HEX_FILL0));
|
|
}
|
|
|
|
{
|
|
auto pannel = tab->addGroup(tr("MetaData"));
|
|
addPannelAction(pannel, QStringLiteral("bookmark"), tr("BookMark"),
|
|
&MainWindow::on_bookmark,
|
|
shortcuts.keySequence(QKeySequences::Key::BOOKMARK));
|
|
addPannelAction(
|
|
pannel, QStringLiteral("bookmarkdel"), tr("DeleteBookMark"),
|
|
&MainWindow::on_bookmarkdel,
|
|
shortcuts.keySequence(QKeySequences::Key::BOOKMARK_DEL));
|
|
addPannelAction(
|
|
pannel, QStringLiteral("bookmarkcls"), tr("ClearBookMark"),
|
|
&MainWindow::on_bookmarkcls,
|
|
shortcuts.keySequence(QKeySequences::Key::BOOKMARK_CLS));
|
|
addPannelAction(pannel, QStringLiteral("metadata"), tr("MetaData"),
|
|
&MainWindow::on_metadata,
|
|
shortcuts.keySequence(QKeySequences::Key::METADATA));
|
|
addPannelAction(
|
|
pannel, QStringLiteral("metadataedit"), tr("MetaDataEdit"),
|
|
&MainWindow::on_metadataedit,
|
|
shortcuts.keySequence(QKeySequences::Key::METADATA_EDIT));
|
|
addPannelAction(
|
|
pannel, QStringLiteral("metadatadel"), tr("DeleteMetaData"),
|
|
&MainWindow::on_metadatadel,
|
|
shortcuts.keySequence(QKeySequences::Key::METADATA_DEL));
|
|
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);
|
|
}));
|
|
addPannelAction(pannel, QStringLiteral("scale"), tr("Scale"),
|
|
EMPTY_FUNC, {}, menu);
|
|
addPannelAction(pannel, QStringLiteral("scalereset"), tr("ResetScale"),
|
|
[this] { this->setCurrentHexEditorScale(1.0); });
|
|
addPannelAction(pannel, QStringLiteral("viewtxt"), tr("ViewText"),
|
|
&MainWindow::on_viewtxt);
|
|
m_editStateWidgets << pannel;
|
|
}
|
|
|
|
{
|
|
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)));
|
|
|
|
addPannelAction(pannel, QStringLiteral("metadata"), tr("MetaData"),
|
|
EMPTY_FUNC, {}, menu);
|
|
|
|
addPannelAction(
|
|
pannel, QStringLiteral("metashow"), tr("MetaShowAll"),
|
|
&MainWindow::on_metashowall,
|
|
shortcuts.keySequence(QKeySequences::Key::METADATA_SHOW));
|
|
addPannelAction(
|
|
pannel, QStringLiteral("metahide"), tr("MetaHideAll"),
|
|
&MainWindow::on_metahideall,
|
|
shortcuts.keySequence(QKeySequences::Key::METADATA_HIDE));
|
|
m_editStateWidgets << pannel;
|
|
}
|
|
|
|
{
|
|
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_iReadWrite =
|
|
addPannelAction(pannel, _infoReadonly, tr("ReadOnly"), EMPTY_FUNC);
|
|
m_iReadWrite->setStyleSheet(disableStyle);
|
|
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_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 ((!b && editor->documentType() ==
|
|
EditorView::DocumentType::RegionFile) ||
|
|
!hexeditor->setKeepSize(b)) {
|
|
Toast::toast(this, _pixCannotOver, tr("ErrUnOver"));
|
|
} else {
|
|
if (b) {
|
|
Toast::toast(this, _pixCannotOver,
|
|
tr("InfoCanOverLimit"));
|
|
}
|
|
}
|
|
});
|
|
m_editStateWidgets << pannel;
|
|
}
|
|
|
|
{
|
|
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(-1);
|
|
}));
|
|
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"));
|
|
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"));
|
|
}
|
|
}
|
|
});
|
|
addPannelAction(
|
|
pannel, QStringLiteral("mColInfo"), tr("SetColInfo"), [this]() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
hexeditor->setAddressVisible(!hexeditor->addressVisible());
|
|
});
|
|
addPannelAction(
|
|
pannel, QStringLiteral("mLineInfo"), tr("SetHeaderInfo"), [this]() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
hexeditor->setHeaderVisible(!hexeditor->headerVisible());
|
|
});
|
|
addPannelAction(
|
|
pannel, QStringLiteral("mStr"), tr("SetAsciiString"), [this]() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
hexeditor->setAsciiVisible(!hexeditor->asciiVisible());
|
|
});
|
|
m_editStateWidgets << pannel;
|
|
}
|
|
|
|
{
|
|
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]() { m_dock->restoreState(_defaultLayout); }));
|
|
|
|
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]() { m_dock->restoreState(layout); }));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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); });
|
|
_scriptMaps = ScriptManager::buildUpRibbonScriptRunner(pannel);
|
|
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_setting_plugin,
|
|
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_setting_general,
|
|
shortcuts.keySequence(QKeySequences::Key::SETTING_GENERAL));
|
|
|
|
if (set.scriptEnabled()) {
|
|
addPannelAction(pannel, QStringLiteral("scriptset"),
|
|
tr("ScriptSetting"),
|
|
&MainWindow::on_setting_script);
|
|
}
|
|
}
|
|
|
|
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();
|
|
for (auto p = m_editorViewWidgets.begin(); p != m_editorViewWidgets.end();
|
|
++p) {
|
|
for (auto &w : p.value()) {
|
|
qApp->processEvents();
|
|
if (names.contains(w->id())) {
|
|
log.critical(tr("Plugin %1 contains a duplicate ID (%2) that "
|
|
"is already registered by plugin %3")
|
|
.arg(p.key()->pluginName(), w->id(),
|
|
names.value(w->id())->pluginName()));
|
|
continue;
|
|
}
|
|
|
|
menu->addAction(newAction(w->icon(), w->name(), [this, w] {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
editor->switchView(w);
|
|
}));
|
|
|
|
names.insert(w->id(), p.key());
|
|
m_editorViewWidgetsBuffer.append(w);
|
|
}
|
|
qApp->processEvents();
|
|
}
|
|
|
|
// clear for no using
|
|
m_editorViewWidgets.clear();
|
|
}
|
|
|
|
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());
|
|
return editor;
|
|
}
|
|
|
|
void MainWindow::on_newfile() { newfileGUI(); }
|
|
|
|
void MainWindow::on_openfile() {
|
|
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_openregion() {
|
|
OpenRegionDialog d(m_lastusedpath);
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
EditorView *editor = nullptr;
|
|
auto ret = openRegionFile(res.filename, &editor, res.start, res.length);
|
|
if (ret == ErrFile::NotExist) {
|
|
QMessageBox::critical(this, tr("Error"), tr("FileNotExist"));
|
|
return;
|
|
}
|
|
if (ret == ErrFile::Permission) {
|
|
QMessageBox::critical(this, tr("Error"), tr("FilePermission"));
|
|
return;
|
|
}
|
|
if (ret == ErrFile::AlreadyOpened) {
|
|
Q_ASSERT(editor);
|
|
editor->raise();
|
|
editor->setFocus();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_openworkspace() {
|
|
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);
|
|
}
|
|
|
|
void MainWindow::on_opendriver() {
|
|
DriverSelectorDialog ds;
|
|
if (ds.exec()) {
|
|
if (!Utilities::isRoot()) {
|
|
WingMessageBox::critical(this, tr("Error"), tr("Root Required!"));
|
|
return;
|
|
}
|
|
EditorView *editor = nullptr;
|
|
auto res = openDriver(ds.GetResult().device(), &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;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_reload() {
|
|
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() {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
|
|
auto res = saveEditor(editor, {}, false);
|
|
|
|
auto isNewFile = editor->isNewFile();
|
|
if (isNewFile) {
|
|
on_saveas();
|
|
return;
|
|
}
|
|
|
|
restart:
|
|
if (res == ErrFile::IsNewFile) {
|
|
on_saveas();
|
|
return;
|
|
}
|
|
if (res == ErrFile::Permission) {
|
|
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
|
|
return;
|
|
}
|
|
if (res == ErrFile::SourceFileChanged) {
|
|
if (WingMessageBox::warning(this, tr("Warn"), tr("SourceChanged"),
|
|
QMessageBox::Yes | QMessageBox::No) ==
|
|
QMessageBox::Yes) {
|
|
res = saveEditor(editor, {}, true);
|
|
goto restart;
|
|
} else {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSourceFileError"));
|
|
}
|
|
}
|
|
if (res == ErrFile::WorkSpaceUnSaved) {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveWSError"));
|
|
return;
|
|
}
|
|
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSuccessfully"));
|
|
}
|
|
|
|
void MainWindow::on_saveas() {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
|
|
auto filename = WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"),
|
|
m_lastusedpath);
|
|
if (filename.isEmpty())
|
|
return;
|
|
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
|
|
|
auto res = saveEditor(editor, filename, false);
|
|
|
|
restart:
|
|
switch (res) {
|
|
case ErrFile::Success: {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("saveas")),
|
|
tr("SaveSuccessfully"));
|
|
break;
|
|
}
|
|
case ErrFile::WorkSpaceUnSaved: {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("saveas")),
|
|
tr("SaveWSError"));
|
|
break;
|
|
}
|
|
case ErrFile::SourceFileChanged: {
|
|
if (WingMessageBox::warning(this, tr("Warn"), tr("SourceChanged"),
|
|
QMessageBox::Yes | QMessageBox::No) ==
|
|
QMessageBox::Yes) {
|
|
res = saveEditor(editor, filename, true);
|
|
goto restart;
|
|
} else {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
|
|
tr("SaveSourceFileError"));
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
WingMessageBox::critical(this, tr("Error"), tr("SaveUnSuccessfully"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_exportfile() {
|
|
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();
|
|
|
|
auto res = saveEditor(editor, filename, false, true);
|
|
restart:
|
|
switch (res) {
|
|
case ErrFile::Success: {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
|
|
tr("ExportSuccessfully"));
|
|
break;
|
|
}
|
|
case ErrFile::SourceFileChanged: {
|
|
if (QMessageBox::warning(this, tr("Warn"), tr("SourceChanged"),
|
|
QMessageBox::Yes | QMessageBox::No) ==
|
|
QMessageBox::Yes) {
|
|
res = saveEditor(editor, filename, true, true);
|
|
goto restart;
|
|
} else {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("export")),
|
|
tr("ExportSourceFileError"));
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
WingMessageBox::critical(this, tr("Error"), tr("ExportUnSuccessfully"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_savesel() {
|
|
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 {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("savesel")),
|
|
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;
|
|
}
|
|
hexeditor->RemoveSelection();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
registerEditorView(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.isBigFile = editor->isBigFile();
|
|
info.start = 0;
|
|
info.stop = hexeditor->documentBytes();
|
|
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.buffer = r.buffer;
|
|
info.str = r.str;
|
|
|
|
ExecAsync<EditorView::FindError>(
|
|
[this, r]() -> EditorView::FindError {
|
|
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);
|
|
}
|
|
m_find->raise();
|
|
});
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_gotoline() {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
editor->triggerGoto();
|
|
}
|
|
|
|
void MainWindow::on_encoding() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
EncodingDialog d;
|
|
if (d.exec()) {
|
|
auto res = d.getResult();
|
|
hexeditor->renderer()->SetEncoding(res);
|
|
}
|
|
}
|
|
|
|
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(),
|
|
editor->documentType() ==
|
|
EditorView::DocumentType::RegionFile);
|
|
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();
|
|
}
|
|
|
|
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 ch = char(in.toULongLong(&b, 0));
|
|
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 pos = hexeditor->cursor()->selectionStart(i).offset();
|
|
hexeditor->Replace(
|
|
pos, QByteArray(int(hexeditor->hasSelection()), 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(int(hexeditor->hasSelection()), 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 pos = hexeditor->currentOffset();
|
|
|
|
if (doc->bookMarkExists(pos)) {
|
|
doc->RemoveBookMark(pos);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_bookmarkcls() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
auto doc = hexeditor->document();
|
|
doc->ClearBookMark();
|
|
}
|
|
|
|
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() + 1;
|
|
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 pos = hexeditor->cursor()->position().offset();
|
|
meta->RemoveMetadata(pos);
|
|
}
|
|
|
|
void MainWindow::on_metadatacls() {
|
|
auto hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
auto doc = hexeditor->document();
|
|
doc->metadata()->Clear();
|
|
}
|
|
|
|
void MainWindow::on_metadatafg(bool checked) {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
auto hexeditor = editor->hexEditor();
|
|
auto doc = hexeditor->document();
|
|
if (editor->isOriginWorkSpace()) {
|
|
doc->SetMetafgVisible(checked);
|
|
} else {
|
|
doc->setMetafgVisible(checked);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_metadatabg(bool checked) {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
auto hexeditor = editor->hexEditor();
|
|
auto doc = hexeditor->document();
|
|
if (editor->isOriginWorkSpace()) {
|
|
doc->SetMetabgVisible(checked);
|
|
} else {
|
|
doc->setMetabgVisible(checked);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_metadatacomment(bool checked) {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
auto hexeditor = editor->hexEditor();
|
|
auto doc = hexeditor->document();
|
|
if (editor->isOriginWorkSpace()) {
|
|
doc->SetMetaCommentVisible(checked);
|
|
} else {
|
|
doc->setMetaCommentVisible(checked);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_metashowall() {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return;
|
|
}
|
|
auto hexeditor = editor->hexEditor();
|
|
auto doc = hexeditor->document();
|
|
if (editor->isOriginWorkSpace()) {
|
|
doc->SetMetaVisible(true);
|
|
} else {
|
|
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();
|
|
if (editor->isOriginWorkSpace()) {
|
|
doc->SetMetaVisible(false);
|
|
} else {
|
|
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() {
|
|
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"),
|
|
QString::fromLatin1(d.toHex(' ').toUpper()));
|
|
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();
|
|
|
|
auto tmp = d->read(off, sizeof(quint64));
|
|
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,
|
|
QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()));
|
|
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,
|
|
QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()));
|
|
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,
|
|
QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()));
|
|
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,
|
|
QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()));
|
|
_numsitem->setNumData(NumShowModel::NumTableIndex::Char,
|
|
QString::number(s1));
|
|
} else {
|
|
_numsitem->setNumData(NumShowModel::NumTableIndex::Byte, QString());
|
|
_numsitem->setNumData(NumShowModel::NumTableIndex::Char, 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;
|
|
}
|
|
|
|
// 解码字符串
|
|
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));
|
|
}
|
|
|
|
// 如果不超过 10KB (默认)那么解码,防止太多卡死
|
|
if (buffer.length() <= 1024 * _decstrlim) {
|
|
m_txtDecode->insertPlainText(Utilities::decodingString(
|
|
b, hexeditor->renderer()->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 hexeditor = currentHexView();
|
|
if (hexeditor == nullptr) {
|
|
return;
|
|
}
|
|
_showtxt->load(hexeditor->document()->buffer());
|
|
}
|
|
|
|
void MainWindow::on_fullScreen() {
|
|
if (this->isFullScreen()) {
|
|
this->showMaximized();
|
|
} else {
|
|
this->showFullScreen();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_saveLayout() {
|
|
auto filename = WingFileDialog::getSaveFileName(
|
|
this, tr("SaveLayout"), m_lastusedpath,
|
|
QStringLiteral("Layout (*.wing-layout)"));
|
|
if (!filename.isEmpty()) {
|
|
QFile f(filename);
|
|
if (f.open(QFile::WriteOnly)) {
|
|
f.write(m_dock->saveState());
|
|
f.close();
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("layoutexport")),
|
|
tr("SaveLayoutSuccess"));
|
|
} else {
|
|
Toast::toast(this, NAMEICONRES(QStringLiteral("layoutexport")),
|
|
tr("SaveLayoutError"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_exportlog() {
|
|
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_scriptwindow() {
|
|
Q_ASSERT(m_scriptDialog);
|
|
m_scriptDialog->show();
|
|
m_scriptDialog->raise();
|
|
}
|
|
|
|
void MainWindow::on_setting_general() { m_setdialog->showConfig(); }
|
|
|
|
void MainWindow::on_setting_script() {
|
|
m_scriptDialog->settingDialog()->showConfig();
|
|
}
|
|
|
|
void MainWindow::on_setting_plugin() { 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() {
|
|
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"));
|
|
}
|
|
},
|
|
tr("CheckingUpdate"));
|
|
}
|
|
|
|
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) {
|
|
for (auto &w : m_editorViewWidgetsBuffer) {
|
|
editor->registerView(w);
|
|
}
|
|
for (auto &m : m_hexContextMenu) {
|
|
editor->registerQMenu(m);
|
|
}
|
|
|
|
auto &set = SettingManager::instance();
|
|
editor->setCopyLimit(set.copylimit());
|
|
editor->setFontSize(set.editorfontSize());
|
|
|
|
connectEditorView(editor);
|
|
m_views.insert(editor, {});
|
|
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()});
|
|
}
|
|
|
|
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::sigOnEncoding, this, &MainWindow::on_encoding);
|
|
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() + 1;
|
|
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(meta, o);
|
|
}
|
|
} 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);
|
|
|
|
connect(editor, &EditorView::closeRequested, this, [this] {
|
|
auto editor = qobject_cast<EditorView *>(sender());
|
|
Q_ASSERT(editor);
|
|
Q_ASSERT(m_views.contains(editor));
|
|
|
|
if (closeEditor(editor, m_isOnClosing) == ErrFile::UnSaved) {
|
|
auto ret = this->saveRequest();
|
|
if (ret == QMessageBox::Cancel) {
|
|
return;
|
|
} else if (ret == QMessageBox::Yes) {
|
|
if (saveEditor(editor, {}, false) == ErrFile::Success) {
|
|
closeEditor(editor, m_isOnClosing);
|
|
}
|
|
} else {
|
|
closeEditor(editor, true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
|
|
if (old == cur) {
|
|
return;
|
|
}
|
|
|
|
if (old != nullptr) {
|
|
auto hexeditor = old->hexEditor();
|
|
hexeditor->disconnect(SIGNAL(cursorLocationChanged()));
|
|
hexeditor->disconnect(SIGNAL(cursorSelectionChanged()));
|
|
hexeditor->disconnect(SIGNAL(canUndoChanged(bool)));
|
|
hexeditor->disconnect(SIGNAL(canRedoChanged(bool)));
|
|
hexeditor->disconnect(SIGNAL(documentSaved(bool)));
|
|
hexeditor->disconnect(SIGNAL(documentKeepSize(bool)));
|
|
hexeditor->disconnect(SIGNAL(documentLockedFile(bool)));
|
|
hexeditor->disconnect(SIGNAL(copyLimitRaised()));
|
|
hexeditor->disconnect(SIGNAL(scaleRateChanged()));
|
|
hexeditor->document()->disconnect();
|
|
}
|
|
|
|
Q_ASSERT(cur);
|
|
auto hexeditor = cur->hexEditor();
|
|
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);
|
|
});
|
|
connect(hexeditor, &QHexView::documentKeepSize, this, [this](bool b) {
|
|
m_iCanOver->setIcon(b ? _infoCannotOver : _infoCanOver);
|
|
});
|
|
connect(hexeditor, &QHexView::documentLockedFile, this, [this](bool b) {
|
|
m_iLocked->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 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);
|
|
|
|
m_iReadWrite->setIcon(hexeditor->isReadOnly() ? _infoReadonly
|
|
: _infoWriteable);
|
|
|
|
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;
|
|
}
|
|
|
|
m_views.insert(ev, QString());
|
|
registerEditorView(ev);
|
|
if (editor) {
|
|
*editor = ev;
|
|
}
|
|
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
|
|
return ErrFile::Success;
|
|
}
|
|
|
|
ErrFile MainWindow::openDriver(const QString &driver, EditorView **editor) {
|
|
auto e = findEditorView(driver);
|
|
if (e) {
|
|
if (editor) {
|
|
*editor = e;
|
|
}
|
|
return ErrFile::AlreadyOpened;
|
|
}
|
|
|
|
// ok, going on
|
|
if (!newOpenFileSafeCheck()) {
|
|
return ErrFile::Error;
|
|
}
|
|
|
|
auto ev = new EditorView(this);
|
|
auto res = ev->openDriver(driver);
|
|
|
|
if (res != ErrFile::Success) {
|
|
delete ev;
|
|
return res;
|
|
}
|
|
|
|
m_views.insert(ev, QString());
|
|
registerEditorView(ev);
|
|
if (editor) {
|
|
*editor = ev;
|
|
}
|
|
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
|
|
return ErrFile::Success;
|
|
}
|
|
|
|
ErrFile MainWindow::openWorkSpace(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->openWorkSpace(filename);
|
|
|
|
if (res != ErrFile::Success) {
|
|
delete ev;
|
|
return res;
|
|
}
|
|
|
|
m_views.insert(ev, file);
|
|
registerEditorView(ev);
|
|
if (editor) {
|
|
*editor = ev;
|
|
}
|
|
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
|
|
return ErrFile::Success;
|
|
}
|
|
|
|
ErrFile MainWindow::openRegionFile(QString file, EditorView **editor,
|
|
qsizetype start, qsizetype length) {
|
|
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->openRegionFile(filename, start, length);
|
|
|
|
if (res != ErrFile::Success) {
|
|
delete ev;
|
|
return res;
|
|
}
|
|
|
|
registerEditorView(ev);
|
|
if (editor) {
|
|
*editor = ev;
|
|
}
|
|
m_dock->addDockWidget(ads::CenterDockWidgetArea, ev, editorViewArea());
|
|
return ErrFile::Success;
|
|
}
|
|
|
|
ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
|
|
bool ignoreMd5, bool isExport) {
|
|
if (editor == nullptr) {
|
|
return ErrFile::Error;
|
|
}
|
|
|
|
auto isNewFile = editor->isNewFile();
|
|
if (isNewFile && filename.isEmpty()) {
|
|
return ErrFile::IsNewFile;
|
|
}
|
|
|
|
if (!writeSafeCheck(false, {})) {
|
|
return ErrFile::Permission;
|
|
}
|
|
|
|
auto oldName = editor->fileName();
|
|
|
|
QString workspace = m_views.value(editor);
|
|
if (editor->change2WorkSpace()) {
|
|
workspace = editor->fileName() + PROEXT;
|
|
}
|
|
|
|
auto ret = editor->save(workspace, filename, ignoreMd5, isExport);
|
|
if (ret == ErrFile::Success) {
|
|
m_views[editor] = workspace;
|
|
|
|
PluginSystem::instance().dispatchEvent(
|
|
IWingPlugin::RegisteredEvent::FileSaved,
|
|
{filename.isEmpty() ? oldName : filename, oldName});
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_views.remove(editor);
|
|
if (currentEditor() == editor) {
|
|
_editorLock.lockForWrite();
|
|
m_curEditor = nullptr;
|
|
_editorLock.unlock();
|
|
}
|
|
|
|
auto fileName = editor->fileName();
|
|
PluginSystem::instance().cleanUpEditorViewHandle(editor);
|
|
editor->deleteDockWidget();
|
|
PluginSystem::instance().dispatchEvent(
|
|
IWingPlugin::RegisteredEvent::FileClosed, {fileName});
|
|
|
|
m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS)
|
|
->setEnabled(m_views.size() != 0);
|
|
|
|
if (m_dock->focusedDockWidget() == editor) {
|
|
if (!m_views.isEmpty()) {
|
|
for (auto p = m_views.keyBegin(); p != m_views.keyEnd(); ++p) {
|
|
auto ev = *p;
|
|
if (ev != editor && ev->isCurrentTab()) {
|
|
ev->setFocus();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ErrFile::Success;
|
|
}
|
|
|
|
void MainWindow::updateEditModeEnabled() {
|
|
auto editor = currentEditor();
|
|
auto b = (editor != nullptr);
|
|
|
|
for (auto &item : m_editStateWidgets) {
|
|
item->setEnabled(b);
|
|
}
|
|
|
|
if (b) {
|
|
auto hexeditor = editor->hexEditor();
|
|
enableDirverLimit(editor->isDriver());
|
|
enableCloneFileLimit(editor->isCloneFile());
|
|
auto doc = hexeditor->document();
|
|
emit doc->canRedoChanged(doc->canRedo());
|
|
emit doc->canUndoChanged(doc->canUndo());
|
|
} else {
|
|
m_lblloc->setText(QStringLiteral("(0,0)"));
|
|
m_lblsellen->setText(QStringLiteral("0 - 0x0"));
|
|
_numsitem->clear();
|
|
}
|
|
}
|
|
|
|
void MainWindow::enableDirverLimit(bool isDriver) {
|
|
auto e = !isDriver;
|
|
for (auto &item : m_driverStateWidgets) {
|
|
item->setEnabled(e);
|
|
}
|
|
}
|
|
|
|
void MainWindow::enableCloneFileLimit(bool isCloneFile) {
|
|
auto e = !isCloneFile;
|
|
for (auto &item : m_cloneFileStateWidgets) {
|
|
item->setEnabled(e);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
QHexView *MainWindow::currentHexView() {
|
|
auto editor = currentEditor();
|
|
if (editor == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return editor->hexEditor();
|
|
}
|
|
|
|
bool MainWindow::writeSafeCheck(bool isNewFile, const QString &savePath) {
|
|
if (Utilities::isRoot()) {
|
|
if (isNewFile || savePath.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
if (Utilities::isStorageDevice(savePath)) {
|
|
return false;
|
|
}
|
|
|
|
QFileInfo finfo(savePath);
|
|
if (!finfo.exists()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
QJsonObject MainWindow::extractModelData(const QAbstractItemModel *model,
|
|
const QModelIndex &parent) {
|
|
QJsonObject jsonObject;
|
|
|
|
// Add data for the current row
|
|
for (int col = 0; col < model->columnCount(parent); ++col) {
|
|
QVariant data =
|
|
model->data(model->index(parent.row(), col, parent.parent()));
|
|
QString header = model->headerData(col, Qt::Horizontal).toString();
|
|
jsonObject[header.isEmpty() ? tr("Column %1").arg(col) : header] =
|
|
data.toString();
|
|
}
|
|
|
|
// Recursively add child rows
|
|
QJsonArray children;
|
|
for (int row = 0; row < model->rowCount(parent); ++row) {
|
|
QModelIndex childIndex = model->index(row, 0, parent);
|
|
children.append(extractModelData(model, childIndex));
|
|
}
|
|
|
|
if (!children.isEmpty())
|
|
jsonObject["children"] = children;
|
|
|
|
return jsonObject;
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event) {
|
|
m_isOnClosing = true;
|
|
// first checking the scripting dialog
|
|
if (!m_scriptDialog->about2Close()) {
|
|
event->ignore();
|
|
m_isOnClosing = false;
|
|
return;
|
|
}
|
|
|
|
// 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) {
|
|
emit view->closeRequested();
|
|
}
|
|
|
|
auto ret =
|
|
unSavedFiles.isEmpty()
|
|
? QMessageBox::No
|
|
: WingMessageBox::warning(
|
|
this, qAppName(), tr("ConfirmAPPSave"),
|
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
|
if (ret == QMessageBox::Yes) {
|
|
auto views = m_views.keys();
|
|
for (auto &p : views) {
|
|
emit p->closeRequested();
|
|
}
|
|
m_isOnClosing = false;
|
|
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
|
|
}
|
|
m_isOnClosing = false;
|
|
} else {
|
|
event->ignore();
|
|
m_isOnClosing = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto &set = SettingManager::instance();
|
|
set.setDockLayout(m_dock->saveState());
|
|
|
|
m_scriptDialog->saveDockLayout();
|
|
set.setRecentFiles(m_recentmanager->saveRecent());
|
|
set.save();
|
|
|
|
LangService::instance().saveSnippets();
|
|
|
|
FramelessMainWindow::closeEvent(event);
|
|
}
|
|
|
|
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);
|
|
}
|