Compare commits

...

30 Commits

Author SHA1 Message Date
寂静的羽夏 c0be5c4b23 ci: 完善自动化部署测试 2024-12-16 19:59:28 +08:00
寂静的羽夏 f0a3ede44f feat: 增加 Linux 平台的通用打包支持; 2024-12-15 17:26:49 +08:00
寂静的羽夏 735298d850 feat: 十六进制编辑增加多选支持;修复程序单例问题;增加布局管理器;完善插件系统; 2024-12-14 19:12:38 +08:00
寂静的羽夏 e47b96b563 feat: 完善插件系统;增加测试插件;完善 README; 2024-12-08 22:09:31 +08:00
寂静的羽夏 893f3112c7 docs: 文档相关变更; 2024-12-07 21:27:55 +08:00
寂静的羽夏 1452874ac5 feat: 语言相关调整;修复一些编辑器的细节问题;文档内容调整; 2024-12-07 20:52:09 +08:00
寂静的羽夏 862a6717ec feat: 增加脚本 json 支持;优化代码;调整函数;更新上游库; 2024-12-05 21:55:20 +08:00
寂静的羽夏 8e76d29707 fix: 调动多语言支持相关;重构代码提示;修复导致代码编辑器的崩溃; 2024-12-02 09:30:51 +08:00
寂静的羽夏 7e33b3b87a feat: 软件语言支持相关调动。 2024-11-30 21:04:36 +08:00
寂静的羽夏 2a897e0099 feat: 增加两个功能启用设置选项;增加脚本符号浏览器;修复脚本 IDE 运行总是吃掉一行的问题;调整编译; 2024-11-28 13:25:31 +08:00
寂静的羽夏 85cad2aa0e feat: 脚本增加字符类型;完善插件系统;完成缺失的设置功能; 2024-11-27 09:38:59 +08:00
寂静的羽夏 3e3ca37642 fix: 修复十六进制标记无法添加问题;完成全文加载;修复一些误操作的限制;修复代码编辑器无法应用设置; 2024-11-24 23:10:17 +08:00
寂静的羽夏 11e207f686 feat: 增加全文显示;增加加载窗体;完善插件脚本函数名称; 2024-11-23 17:32:56 +08:00
寂静的羽夏 db90ece792 feat: 增加有标注增删字节跟随调整;完成 Clang-Format 支持;修复控制台颜色渲染问题; 2024-11-21 13:54:45 +08:00
寂静的羽夏 d5a4095779 feat: 增加 clang-format 的支持;完善代码自动填充;完善代码编辑器组件功能; 2024-11-17 21:46:46 +08:00
寂静的羽夏 48cf02cfa9 feat: 调整控制台基类以实现代码高亮和提示(WIP);修复代码编辑器光标重绘残留; 2024-11-10 22:11:41 +08:00
寂静的羽夏 912dfaf227 feat: 设置方面相关更新;优化标记的颜色显示;修复软件关于显示开源协议时文字无换行的问题; 2024-11-09 21:34:46 +08:00
寂静的羽夏 c08c2a859e feat(api)!: 补充遗漏的插件函数实现和机制并移除一些接口;重构十六进制编辑组件增强标注能力;更好的代码提示; 2024-11-08 18:35:24 +08:00
寂静的羽夏 96fa55d930 feat: 更好的代码填充;移除冗余的组件;查找完毕强制弹出查找结果; 2024-11-04 09:47:41 +08:00
寂静的羽夏 5686edde5b feat: 支持内置函数的自动补充(WIP); 2024-11-02 21:17:40 +08:00
寂静的羽夏 4f4db8b5f8 feat: 将协议注释添加到代码中;初步支持内置函数的自动补充(WIP);调整 AngelScript 的字符串全局函数的命名空间为 string 而非空; 2024-11-01 21:33:53 +08:00
寂静的羽夏 63b4583ccd feat: 修复错误的日志保存路径;增加 python 脚本安装方式; 2024-10-27 23:04:50 +08:00
寂静的羽夏 a16a8033b5 feat: 完善在 Win 上二进制程序的详细信息;增加代码填充功能(WIP); 2024-10-26 10:01:11 +08:00
寂静的羽夏 b4881d7e3c feat: 增加更细致的提醒 2024-10-22 21:27:52 +08:00
寂静的羽夏 84d9596ada fix: 优化大文件读写逻辑;修复在 Win 下读取驱动器的极度卡顿问题; 2024-10-21 21:38:52 +08:00
寂静的羽夏 ed118376d5 fix: 修复在 Linux 下脚本引擎配置失效问题;修复在 Linux 下崩溃无法再次启动的问题;初步对词法分析尝试; 2024-10-20 21:42:48 +08:00
寂静的羽夏 31c896c9dc fix: 修复语言文件为空的崩溃;增加需重启的设置提醒;调整 Win 下驱动器读写类;调整 CodeModel;优化设置管理器; 2024-10-18 19:54:25 +08:00
寂静的羽夏 8c866d090f feat: 初步适配 AngelScript ,增加代码填充功能,但目前未正常工作 2024-10-15 21:13:52 +08:00
寂静的羽夏 b2d03972b8 fix: 修复 Toast 组件显示始终置顶且显示时移动窗体崩溃问题 2024-09-28 18:55:34 +08:00
寂静的羽夏 204b34447b build: 增加 WINGHEX_USE_FRAMELESS 开关以是否支持自定义窗体边框 2024-09-23 12:48:59 +08:00
423 changed files with 19820 additions and 16685 deletions

View File

@ -7,7 +7,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/clang-format-action@v4.13.0
uses: jidicula/clang-format-action@v4.14.0
with:
clang-format-version: '13'
clang-format-version: '12'
fallback-style: 'LLVM' # optional

View File

@ -9,6 +9,6 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: cmake-format lint
uses: neg-c/cmake-format-action@v0.1.1
uses: neg-c/cmake-format-action@v0.1.3
with:
inplace: true

View File

@ -0,0 +1,63 @@
name: CMake build release for linux
on:
push:
branches:
- release
env:
BUILD_TYPE: Release
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
token: ${{ secrets.CONTRIBUTORS_TOKEN }}
- name: Install Qt
# Installs the Qt SDK
uses: jurplel/install-qt-action@v3
with:
version: 6.8.1
host: 'linux'
target: 'desktop'
arch: 'linux_gcc_64'
cache: true
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/build/package
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target install
- name: Install Packing Tools
run: sudo apt install fakeroot patchelf -y
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
cache: 'pip'
- name: Install Python packages
run: pip install -r ${{github.workspace}}/mkinstaller/linuxdeploy/requirements.txt
- name: Deploy WingHexExplorer2
run: python ${{github.workspace}}/mkinstaller/linuxdeploy/deploy.py ${{github.workspace}}/build
- name: +x for ld-linux if it has
run: sudo ${{github.workspace}}/mkinstaller/linuxdeploy/add-ld-x.sh ${{github.workspace}}/build/package
- name: Create installer
run: bash ${{github.workspace}}/mkinstaller/linuxdeploy/build.sh ${{github.workspace}}/build/package
- uses: actions/upload-artifact@v4
with:
name: WingHexExplorer2-linux-release-build-cache
path: ${{github.workspace}}/mkinstaller/linuxdeploy/build

View File

@ -0,0 +1,66 @@
name: CMake build release for win
on:
push:
branches:
- release
env:
BUILD_TYPE: Release
jobs:
build-release:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
token: ${{ secrets.CONTRIBUTORS_TOKEN }}
- name: Install Qt
# Installs the Qt SDK
uses: jurplel/install-qt-action@v3
with:
version: 6.6.2
host: 'windows'
target: 'desktop'
arch: 'win64_msvc2019_64'
cache: true
- name: Add Chinese support file for InnoSetup
run: |
$sourcePath = "${{github.workspace}}/mkinstaller/innoSetup/ChineseSimplified.isl"
$destinationPath = "C:\Program Files (x86)\Inno Setup 6\Languages\ChineseSimplified.isl"
Start-Process powershell -ArgumentList "Copy-Item -Path '$sourcePath' -Destination '$destinationPath' -Force" -Verb runAs
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
cache: 'pip'
- name: Install Python packages
run: pip install -r ${{github.workspace}}/mkinstaller/innoSetup/requirements.txt
- name: Deploy WingHexExplorer2
run: python ${{github.workspace}}/mkinstaller/innoSetup/mkinnopak.py --no-build "${{github.workspace}}/build"
- name: Compile .ISS to .EXE Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: build/package/WingHexExplorer2/mkiss.iss
options: /O${{github.workspace}}/mkinstaller/innoSetup
- uses: actions/upload-artifact@v4
with:
name: WingHexExplorer2-win-release-build-cache
path: ${{github.workspace}}/mkinstaller/innoSetup/*.exe

View File

@ -1,6 +1,12 @@
name: CMake build check
on: [push, pull_request]
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
BUILD_TYPE: Release

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "3rdparty/SingleApplication"]
path = 3rdparty/SingleApplication
url = git@github.com:itay-grudev/SingleApplication.git
[submodule "3rdparty/json"]
path = 3rdparty/json
url = git@github.com:nlohmann/json.git

@ -1 +1 @@
Subproject commit f2034769ce887367e97a5fbaced5b14aa8039fd3
Subproject commit 57ef77e4793ca14f448f485f52392ab0eefe968b

View File

@ -1,3 +0,0 @@
*.pro.user*

View File

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(
QConsoleWidget
VERSION 2.14.1
LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
if(MSVC)
string(APPEND CMAKE_CXX_FLAGS " /utf-8")
string(APPEND CMAKE_C_FLAGS " /utf-8")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
add_library(
QConsoleWidget STATIC src/QConsoleIODevice.cpp src/QConsoleIODevice.h
src/QConsoleWidget.cpp src/QConsoleWidget.h)
target_link_libraries(QConsoleWidget PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

View File

@ -9,7 +9,7 @@
QConsoleIODevice::QConsoleIODevice(QConsoleWidget *w, QObject *parent)
: QIODevice(parent), widget_(w), readpos_(0), writtenSinceLastEmit_(0),
readSinceLastEmit_(0) {
setCurrentWriteChannel(QConsoleWidget::StandardOutput);
setCurrentWriteChannel(STDOUT_FILENO);
open(QIODevice::ReadWrite | QIODevice::Unbuffered);
}
@ -53,10 +53,10 @@ qint64 QConsoleIODevice::readData(char *data, qint64 len) {
qint64 QConsoleIODevice::writeData(const char *data, qint64 len) {
QByteArray ba(data, (int)len);
int ch = currentWriteChannel();
if (ch == QConsoleWidget::StandardError)
widget_->writeStdErr(ba);
else
if (ch == STDOUT_FILENO)
widget_->writeStdOut(ba);
else
widget_->writeStdErr(ba);
writtenSinceLastEmit_ += len;
if (!signalsBlocked()) {

View File

@ -6,8 +6,15 @@
class QConsoleWidget;
class QConsoleIODevice : public QIODevice {
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
class QConsoleIODevice : public QIODevice {
Q_OBJECT
public:

View File

@ -0,0 +1,451 @@
#include "QConsoleWidget.h"
#include "class/ascompletion.h"
#include "control/qcodecompletionwidget.h"
#include "qdocumentline.h"
#include "qformatscheme.h"
#include "utilities.h"
#include "QConsoleIODevice.h"
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QKeyEvent>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QScrollBar>
QConsoleWidget::QConsoleWidget(QWidget *parent)
: QEditor(false, parent), mode_(Output) {
iodevice_ = new QConsoleIODevice(this, this);
m_doc->setProperty("console", QVariant::fromValue(inpos_));
setFlag(QEditor::AutoCloseChars, true);
setAcceptDrops(false);
setUndoRedoEnabled(false);
setCursorMirrorEnabled(false);
createSimpleBasicContextMenu(false, false);
}
QConsoleWidget::~QConsoleWidget() {}
void QConsoleWidget::setMode(ConsoleMode m) {
if (m == mode_)
return;
if (m == Input) {
auto cursor = this->cursor();
cursor.movePosition(QDocumentCursor::End);
setCursor(cursor);
inpos_ = cursor;
m_doc->setProperty("console", QVariant::fromValue(inpos_));
mode_ = Input;
}
if (m == Output) {
mode_ = Output;
}
}
QString QConsoleWidget::getCommandLine() {
if (mode_ == Output)
return QString();
auto textCursor = this->cursor();
auto ltxt = textCursor.line().text();
QString code = ltxt.mid(inpos_.columnNumber());
return code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
}
void QConsoleWidget::paste() {
auto text = qApp->clipboard()->text();
if (canPaste()) {
m_cursor.insertText(text.replace('\n', ' '));
}
}
void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine();
// start new block
auto textCursor = this->cursor();
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
textCursor.insertLine();
setMode(Output);
setCursor(textCursor);
// Update the history
if (!code.isEmpty())
history_.add(code);
// send signal / update iodevice
if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code);
emit consoleCommand(code);
}
void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
if (mode() == Input) {
auto ascom = dynamic_cast<AsCompletion *>(completionEngine());
if (ascom) {
auto cw = ascom->codeCompletionWidget();
if (cw && cw->isVisible()) {
// The following keys are forwarded by the completer to the
// widget
switch (e->key()) {
case Qt::Key_Tab:
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Backtab:
e->ignore();
return; // let the completer do default behavior
default:
break;
}
}
}
}
auto textCursor = this->cursor();
bool selectionInEditZone = isSelectionInEditZone();
// check for user abort request
if (e->modifiers() & Qt::ControlModifier) {
if (e->key() == Qt::Key_Q) // Ctrl-Q aborts
{
emit abortEvaluation();
e->accept();
return;
}
}
// Allow copying anywhere in the console ...
if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) {
if (textCursor.hasSelection())
copy();
e->accept();
return;
}
// the rest of key events are ignored during output mode
if (mode() != Input) {
e->ignore();
return;
}
// Allow cut only if the selection is limited to the interactive area ...
if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) {
cut();
e->accept();
return;
}
// Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard =
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text);
}
}
e->accept();
return;
}
int key = e->key();
// int shiftMod = e->modifiers() == Qt::ShiftModifier;
if (history_.isActive() && key != Qt::Key_Up && key != Qt::Key_Down)
history_.deactivate();
// Force the cursor back to the interactive area
// for all keys except modifiers
if (!isCursorInEditZone() && key != Qt::Key_Control &&
key != Qt::Key_Shift && key != Qt::Key_Alt) {
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
setCursor(textCursor);
}
switch (key) {
case Qt::Key_Up:
// Activate the history and move to the 1st matching history item
if (!history_.isActive())
history_.activate(getCommandLine());
if (history_.move(true))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
break;
case Qt::Key_Down:
if (history_.move(false))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
case Qt::Key_Left:
if (textCursor > inpos_)
QEditor::keyPressEvent(e);
else {
QApplication::beep();
e->accept();
}
break;
case Qt::Key_Delete:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor < inpos_)
QApplication::beep();
else
QEditor::keyPressEvent(e);
}
break;
case Qt::Key_Backspace:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor <= inpos_)
QApplication::beep();
else
QEditor::keyPressEvent(e);
}
break;
case Qt::Key_Home:
e->accept();
setCursor(inpos_);
break;
case Qt::Key_Enter:
case Qt::Key_Return:
e->accept();
handleReturnKey();
break;
case Qt::Key_Escape:
e->accept();
replaceCommandLine(QString());
break;
default:
// setCurrentCharFormat(chanFormat_[StandardInput]);
if (isCursorInEditZone()) {
QEditor::keyPressEvent(e);
} else {
e->ignore();
}
break;
}
}
bool QConsoleWidget::isSelectionInEditZone() const {
auto textCursor = this->cursor();
if (!textCursor.hasSelection())
return false;
auto selectionStart = textCursor.selectionStart();
auto selectionEnd = textCursor.selectionEnd();
return selectionStart > inpos_ && selectionEnd >= inpos_;
}
bool QConsoleWidget::isCursorInEditZone() const { return cursor() >= inpos_; }
bool QConsoleWidget::canPaste() const {
auto textCursor = this->cursor();
if (textCursor < inpos_)
return false;
return true;
}
void QConsoleWidget::replaceCommandLine(const QString &str) {
// Select the text after the last command prompt ...
auto textCursor = this->cursor();
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
auto bcursor = inpos_;
bcursor.setSelectionBoundary(textCursor);
bcursor.replaceSelectedText(str);
bcursor.movePosition(str.length());
setCursor(bcursor);
}
QString QConsoleWidget::getHistoryPath() {
QDir dir(Utilities::getAppDataPath());
return dir.absoluteFilePath(QStringLiteral(".command_history.lst"));
}
void QConsoleWidget::write(const QString &message, const QString &sfmtID) {
auto tc = cursor();
auto ascom = dynamic_cast<AsCompletion *>(completionEngine());
QCodeCompletionWidget *cw = nullptr;
if (ascom) {
cw = ascom->codeCompletionWidget();
}
if (ascom == nullptr || mode() == Output || (cw && cw->isCompleting())) {
// in output mode or completion messages are appended
auto tc1 = tc;
auto line = tc1.line();
tc1.moveTo(line, line.length());
// check is cursor was not at the end
// (e.g. had been moved per mouse action)
bool needsRestore = tc1.position() != tc.position();
// insert text
setCursor(tc1);
tc.insertText(message, false, sfmtID);
ensureCursorVisible();
// restore cursor if needed
if (needsRestore)
setCursor(tc);
} else {
// in Input mode output messages are inserted
// before the edit block
// get offset of current pos from the end
auto editpos = tc;
auto line = editpos.line();
tc.moveTo(line, 0);
tc.insertLine();
tc.insertText(message, false, sfmtID);
setCursor(editpos);
}
}
void QConsoleWidget::writeStdOut(const QString &s) {
write(s, QStringLiteral("stdout"));
}
void QConsoleWidget::writeStdErr(const QString &s) {
write(s, QStringLiteral("stderr"));
}
/////////////////// QConsoleWidget::History /////////////////////
QConsoleWidget::History QConsoleWidget::history_;
QConsoleWidget::History::History(void)
: pos_(0), active_(false), maxsize_(10000) {
QFile f(QConsoleWidget::getHistoryPath());
if (f.open(QFile::ReadOnly)) {
QTextStream is(&f);
while (!is.atEnd())
add(is.readLine());
}
}
QConsoleWidget::History::~History(void) {
QFile f(QConsoleWidget::getHistoryPath());
if (f.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream os(&f);
int n = strings_.size();
while (n > 0)
os << strings_.at(--n) << Qt::endl;
}
}
void QConsoleWidget::History::add(const QString &str) {
active_ = false;
// if (strings_.contains(str)) return;
if (strings_.size() == maxsize_)
strings_.pop_back();
strings_.push_front(str);
}
void QConsoleWidget::History::activate(const QString &tk) {
active_ = true;
token_ = tk;
pos_ = -1;
}
bool QConsoleWidget::History::move(bool dir) {
if (active_) {
int next = indexOf(dir, pos_);
if (pos_ != next) {
pos_ = next;
return true;
} else
return false;
} else
return false;
}
int QConsoleWidget::History::indexOf(bool dir, int from) const {
int i = from, to = from;
if (dir) {
while (i < strings_.size() - 1) {
const QString &si = strings_.at(++i);
if (si.startsWith(token_)) {
return i;
}
}
} else {
while (i > 0) {
const QString &si = strings_.at(--i);
if (si.startsWith(token_)) {
return i;
}
}
return -1;
}
return to;
}
void QConsoleWidget::cut() {
if (isSelectionInEditZone()) {
QEditor::cut();
}
}
/////////////////// Stream manipulators /////////////////////
QTextStream &waitForInput(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->waitForReadyRead(-1);
return s;
}
QTextStream &inputMode(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d && d->widget())
d->widget()->setMode(QConsoleWidget::Input);
return s;
}
QTextStream &outChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(STDOUT_FILENO);
return s;
}
QTextStream &errChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(STDERR_FILENO);
return s;
}

View File

@ -1,55 +1,40 @@
#ifndef _QCONSOLEWIDGET_H_
#define _QCONSOLEWIDGET_H_
#include <QCompleter>
#include <QPlainTextEdit>
#include <QIODevice>
#include <QTextCharFormat>
#include <QTextStream>
class QConsoleIODevice;
class QConsoleWidgetCompleter;
#include "qeditor.h"
class QConsoleWidget : public QPlainTextEdit {
class QConsoleIODevice;
class QConsoleWidget : public QEditor {
Q_OBJECT
public:
enum ConsoleMode { Input, Output };
Q_ENUM(ConsoleMode)
enum ConsoleChannel {
StandardInput,
StandardOutput,
StandardError,
nConsoleChannels
};
Q_ENUM(ConsoleChannel)
QConsoleWidget(QWidget *parent = 0);
~QConsoleWidget();
explicit QConsoleWidget(QWidget *parent = nullptr);
virtual ~QConsoleWidget();
ConsoleMode mode() const { return mode_; }
void setMode(ConsoleMode m);
QIODevice *device() const { return (QIODevice *)iodevice_; }
QTextCharFormat channelCharFormat(ConsoleChannel ch) const {
return chanFormat_[ch];
}
void setChannelCharFormat(ConsoleChannel ch, const QTextCharFormat &fmt) {
chanFormat_[ch] = fmt;
}
const QStringList &completionTriggers() const {
return completion_triggers_;
}
void setCompletionTriggers(const QStringList &l) {
completion_triggers_ = l;
}
virtual QSize sizeHint() const override { return QSize(600, 400); }
// write a formatted message to the console
void write(const QString &message, const QTextCharFormat &fmt);
void write(const QString &message, const QString &sfmtID = {}) override;
static const QStringList &history() { return history_.strings_; }
void setCompleter(QConsoleWidgetCompleter *c);
// get the current command line
QString getCommandLine();
public slots:
virtual void paste() override;
// write to StandardOutput
void writeStdOut(const QString &s);
@ -67,12 +52,9 @@ protected:
bool canPaste() const;
bool canCut() const { return isSelectionInEditZone(); }
void handleReturnKey();
void handleTabKey();
void updateCompleter();
void checkCompletionTriggers(const QString &txt);
// reimp QPlainTextEdit functions
void keyPressEvent(QKeyEvent *e) override;
void contextMenuEvent(QContextMenuEvent *event) override;
// Returns true if there is a selection in edit zone
bool isSelectionInEditZone() const;
// Returns true if cursor is in edit zone
@ -82,10 +64,9 @@ protected:
static QString getHistoryPath();
protected slots:
// insert the completion from completer
void insertCompletion(const QString &completion);
// QEditor interface
public slots:
virtual void cut() override;
private:
struct History {
@ -109,12 +90,9 @@ private:
static History history_;
ConsoleMode mode_;
int inpos_, completion_pos_;
QStringList completion_triggers_;
QDocumentCursor inpos_;
QString currentMultiLineCode_;
QConsoleIODevice *iodevice_;
QTextCharFormat chanFormat_[nConsoleChannels];
QConsoleWidgetCompleter *completer_;
};
QTextStream &waitForInput(QTextStream &s);
@ -122,22 +100,4 @@ QTextStream &inputMode(QTextStream &s);
QTextStream &outChannel(QTextStream &s);
QTextStream &errChannel(QTextStream &s);
class QConsoleWidgetCompleter : public QCompleter {
public:
/*
* Update the completion model given a string. The given string
* is the current console text between the cursor and the start of
* the line.
*
* Return the completion count
*/
virtual int updateCompletionModel(const QString &str) = 0;
/*
* Return the position in the command line where the completion
* should be inserted
*/
virtual int insertPos() = 0;
};
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

View File

@ -1,577 +0,0 @@
#include "QConsoleWidget.h"
#include "QConsoleIODevice.h"
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QKeyEvent>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QScrollBar>
#include <QStandardPaths>
#include <QStringListModel>
#include <QTextBlock>
#include <QTextCursor>
#include <QTextDocumentFragment>
QConsoleWidget::QConsoleWidget(QWidget *parent)
: QPlainTextEdit(parent), mode_(Output), completer_(0) {
iodevice_ = new QConsoleIODevice(this, this);
QTextCharFormat fmt = currentCharFormat();
for (int i = 0; i < nConsoleChannels; i++)
chanFormat_[i] = fmt;
chanFormat_[StandardOutput].setForeground(Qt::darkBlue);
chanFormat_[StandardError].setForeground(Qt::red);
setTextInteractionFlags(Qt::TextEditorInteraction);
setUndoRedoEnabled(false);
}
QConsoleWidget::~QConsoleWidget() {}
void QConsoleWidget::setMode(ConsoleMode m) {
if (m == mode_)
return;
if (m == Input) {
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::End);
setTextCursor(cursor);
setCurrentCharFormat(chanFormat_[StandardInput]);
inpos_ = cursor.position();
mode_ = Input;
}
if (m == Output) {
mode_ = Output;
}
}
QString QConsoleWidget::getCommandLine() {
if (mode_ == Output)
return QString();
// select text in edit zone (from the input pos to the end)
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
QString code = textCursor.selectedText();
code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
return code;
}
void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine();
// start new block
appendPlainText(QString());
setMode(Output);
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
// Update the history
if (!code.isEmpty())
history_.add(code);
// send signal / update iodevice
if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code);
emit consoleCommand(code);
}
void QConsoleWidget::handleTabKey() {
QTextCursor tc = this->textCursor();
int anchor = tc.anchor();
int position = tc.position();
tc.setPosition(inpos_);
tc.setPosition(position, QTextCursor::KeepAnchor);
QString text = tc.selectedText().trimmed();
tc.setPosition(anchor, QTextCursor::MoveAnchor);
tc.setPosition(position, QTextCursor::KeepAnchor);
if (text.isEmpty()) {
tc.insertText(" ");
} else {
updateCompleter();
if (completer_ && completer_->completionCount() == 1) {
insertCompletion(completer_->currentCompletion());
completer_->popup()->hide();
}
}
}
void QConsoleWidget::updateCompleter() {
if (!completer_)
return;
// if the completer is first shown, mark
// the text position
QTextCursor textCursor = this->textCursor();
if (!completer_->popup()->isVisible()) {
completion_pos_ = textCursor.position();
// qDebug() << "show completer, pos " << completion_pos_;
}
// Get the text between the current cursor position
// and the start of the input
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
QString commandText = textCursor.selectedText();
// qDebug() << "code to complete: " << commandText;
// Call the completer to update the completion model
// Place and show the completer if there are available completions
int count;
if ((count = completer_->updateCompletionModel(commandText))) {
// qDebug() << "found " << count << " completions";
// Get a QRect for the cursor at the start of the
// current word and then translate it down 8 pixels.
textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::StartOfWord);
QRect cr = this->cursorRect(textCursor);
cr.translate(0, 8);
cr.setWidth(
completer_->popup()->sizeHintForColumn(0) +
completer_->popup()->verticalScrollBar()->sizeHint().width());
completer_->complete(cr);
} else {
// qDebug() << "no completions - hiding";
completer_->popup()->hide();
}
}
void QConsoleWidget::checkCompletionTriggers(const QString &txt) {
if (!completer_ || completion_triggers_.isEmpty() || txt.isEmpty())
return;
foreach (const QString &tr, completion_triggers_) {
if (tr.endsWith(txt)) {
QTextCursor tc = this->textCursor();
tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor,
tr.length());
if (tc.selectedText() == tr) {
updateCompleter();
return;
}
}
}
}
void QConsoleWidget::insertCompletion(const QString &completion) {
QTextCursor tc = textCursor();
tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor,
tc.position() - inpos_ - completer_->insertPos());
tc.insertText(completion, chanFormat_[StandardInput]);
setTextCursor(tc);
}
void QConsoleWidget::setCompleter(QConsoleWidgetCompleter *c) {
if (completer_) {
completer_->setWidget(0);
QObject::disconnect(completer_, SIGNAL(activated(const QString &)),
this, SLOT(insertCompletion(const QString &)));
}
completer_ = c;
if (completer_) {
completer_->setWidget(this);
QObject::connect(completer_, SIGNAL(activated(const QString &)), this,
SLOT(insertCompletion(const QString &)));
}
}
void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
if (completer_ && completer_->popup()->isVisible()) {
// The following keys are forwarded by the completer to the widget
switch (e->key()) {
case Qt::Key_Tab:
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Backtab:
e->ignore();
return; // let the completer do default behavior
default:
break;
}
}
QTextCursor textCursor = this->textCursor();
bool selectionInEditZone = isSelectionInEditZone();
// check for user abort request
if (e->modifiers() & Qt::ControlModifier) {
if (e->key() == Qt::Key_Q) // Ctrl-Q aborts
{
emit abortEvaluation();
e->accept();
return;
}
}
// Allow copying anywhere in the console ...
if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) {
if (textCursor.hasSelection())
copy();
e->accept();
return;
}
// the rest of key events are ignored during output mode
if (mode() != Input) {
e->ignore();
return;
}
// Allow cut only if the selection is limited to the interactive area ...
if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone)
cut();
e->accept();
return;
}
// Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard =
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text, channelCharFormat(StandardInput));
}
}
e->accept();
return;
}
int key = e->key();
int shiftMod = e->modifiers() == Qt::ShiftModifier;
if (history_.isActive() && key != Qt::Key_Up && key != Qt::Key_Down)
history_.deactivate();
// Force the cursor back to the interactive area
// for all keys except modifiers
if (!isCursorInEditZone() && key != Qt::Key_Control &&
key != Qt::Key_Shift && key != Qt::Key_Alt) {
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
}
switch (key) {
case Qt::Key_Up:
// Activate the history and move to the 1st matching history item
if (!history_.isActive())
history_.activate(getCommandLine());
if (history_.move(true))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
break;
case Qt::Key_Down:
if (history_.move(false))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
case Qt::Key_Left:
if (textCursor.position() > inpos_)
QPlainTextEdit::keyPressEvent(e);
else {
QApplication::beep();
e->accept();
}
break;
case Qt::Key_Delete:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor.position() < inpos_)
QApplication::beep();
else
QPlainTextEdit::keyPressEvent(e);
}
break;
case Qt::Key_Backspace:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor.position() <= inpos_)
QApplication::beep();
else
QPlainTextEdit::keyPressEvent(e);
}
break;
case Qt::Key_Tab:
e->accept();
handleTabKey();
return;
case Qt::Key_Home:
e->accept();
textCursor.setPosition(inpos_, shiftMod ? QTextCursor::KeepAnchor
: QTextCursor::MoveAnchor);
setTextCursor(textCursor);
break;
case Qt::Key_Enter:
case Qt::Key_Return:
e->accept();
handleReturnKey();
break;
case Qt::Key_Escape:
e->accept();
replaceCommandLine(QString());
break;
default:
e->accept();
setCurrentCharFormat(chanFormat_[StandardInput]);
QPlainTextEdit::keyPressEvent(e);
// check if the last key triggers a completion
checkCompletionTriggers(e->text());
break;
}
if (completer_ && completer_->popup()->isVisible()) {
// if the completer is visible check if it should be updated
if (this->textCursor().position() < completion_pos_)
completer_->popup()->hide();
else
updateCompleter();
}
}
void QConsoleWidget::contextMenuEvent(QContextMenuEvent *event) {
QMenu *menu = createStandardContextMenu();
QAction *a;
if ((a = menu->findChild<QAction *>("edit-cut")))
a->setEnabled(canCut());
if ((a = menu->findChild<QAction *>("edit-delete")))
a->setEnabled(canCut());
if ((a = menu->findChild<QAction *>("edit-paste")))
a->setEnabled(canPaste());
menu->exec(event->globalPos());
delete menu;
}
bool QConsoleWidget::isSelectionInEditZone() const {
QTextCursor textCursor = this->textCursor();
if (!textCursor.hasSelection())
return false;
int selectionStart = textCursor.selectionStart();
int selectionEnd = textCursor.selectionEnd();
return selectionStart >= inpos_ && selectionEnd >= inpos_;
}
bool QConsoleWidget::isCursorInEditZone() const {
return textCursor().position() >= inpos_;
}
bool QConsoleWidget::canPaste() const {
QTextCursor textCursor = this->textCursor();
if (textCursor.position() < inpos_)
return false;
if (textCursor.anchor() < inpos_)
return false;
return true;
}
void QConsoleWidget::replaceCommandLine(const QString &str) {
// Select the text after the last command prompt ...
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
// ... and replace it with new string.
textCursor.insertText(str, chanFormat_[StandardInput]);
// move to the end of the document
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
}
QString QConsoleWidget::getHistoryPath() {
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
QDir::separator() + APP_NAME);
return dir.absoluteFilePath(QStringLiteral(".command_history.lst"));
}
void QConsoleWidget::write(const QString &message, const QTextCharFormat &fmt) {
QTextCharFormat currfmt = currentCharFormat();
QTextCursor tc = textCursor();
if (mode() == Input) {
// in Input mode output messages are inserted
// before the edit block
// get offset of current pos from the end
int editpos = tc.position();
tc.movePosition(QTextCursor::End);
editpos = tc.position() - editpos;
// convert the input pos as relative from the end
inpos_ = tc.position() - inpos_;
// insert block
tc.movePosition(QTextCursor::StartOfBlock);
tc.insertBlock();
tc.movePosition(QTextCursor::PreviousBlock);
tc.insertText(message, fmt);
tc.movePosition(QTextCursor::End);
// restore input pos
inpos_ = tc.position() - inpos_;
// restore the edit pos
tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, editpos);
setTextCursor(tc);
setCurrentCharFormat(currfmt);
} else {
// in output mode messages are appended
QTextCursor tc1 = tc;
tc1.movePosition(QTextCursor::End);
// check is cursor was not at the end
// (e.g. had been moved per mouse action)
bool needsRestore = tc1.position() != tc.position();
// insert text
setTextCursor(tc1);
textCursor().insertText(message, fmt);
ensureCursorVisible();
// restore cursor if needed
if (needsRestore)
setTextCursor(tc);
}
}
void QConsoleWidget::writeStdOut(const QString &s) {
write(s, chanFormat_[StandardOutput]);
}
void QConsoleWidget::writeStdErr(const QString &s) {
write(s, chanFormat_[StandardError]);
}
/////////////////// QConsoleWidget::History /////////////////////
QConsoleWidget::History QConsoleWidget::history_;
QConsoleWidget::History::History(void)
: pos_(0), active_(false), maxsize_(10000) {
QFile f(QConsoleWidget::getHistoryPath());
if (f.open(QFile::ReadOnly)) {
QTextStream is(&f);
while (!is.atEnd())
add(is.readLine());
}
}
QConsoleWidget::History::~History(void) {
QFile f(QConsoleWidget::getHistoryPath());
if (f.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream os(&f);
int n = strings_.size();
while (n > 0)
os << strings_.at(--n) << Qt::endl;
}
}
void QConsoleWidget::History::add(const QString &str) {
active_ = false;
// if (strings_.contains(str)) return;
if (strings_.size() == maxsize_)
strings_.pop_back();
strings_.push_front(str);
}
void QConsoleWidget::History::activate(const QString &tk) {
active_ = true;
token_ = tk;
pos_ = -1;
}
bool QConsoleWidget::History::move(bool dir) {
if (active_) {
int next = indexOf(dir, pos_);
if (pos_ != next) {
pos_ = next;
return true;
} else
return false;
} else
return false;
}
int QConsoleWidget::History::indexOf(bool dir, int from) const {
int i = from, to = from;
if (dir) {
while (i < strings_.size() - 1) {
const QString &si = strings_.at(++i);
if (si.startsWith(token_)) {
return i;
}
}
} else {
while (i > 0) {
const QString &si = strings_.at(--i);
if (si.startsWith(token_)) {
return i;
}
}
return -1;
}
return to;
}
/////////////////// Stream manipulators /////////////////////
QTextStream &waitForInput(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->waitForReadyRead(-1);
return s;
}
QTextStream &inputMode(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d && d->widget())
d->widget()->setMode(QConsoleWidget::Input);
return s;
}
QTextStream &outChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(QConsoleWidget::StandardOutput);
return s;
}
QTextStream &errChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(QConsoleWidget::StandardError);
return s;
}

View File

@ -1,9 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
SOURCES += $$PWD/QConsoleWidget.cpp \
$$PWD/QConsoleIODevice.cpp
HEADERS += $$PWD/QConsoleWidget.h \
$$PWD/QConsoleIODevice.h

View File

@ -4,7 +4,7 @@ project(QHexView LANGUAGES CXX)
find_package(
Qt${QT_VERSION_MAJOR}
COMPONENTS Widgets Gui
COMPONENTS Widgets Gui Concurrent
REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
@ -57,8 +57,6 @@ add_library(
document/commands/baseaddrcommand.h
document/commands/encodingchangecommand.cpp
document/commands/encodingchangecommand.h
document/buffer/qwindriverbuffer.h
document/buffer/qwindriverbuffer.cpp
document/qstoragedevice.h
document/qstoragedevice.cpp
document/qhexcursor.cpp
@ -71,16 +69,15 @@ add_library(
document/qhexrenderer.h
QHexEdit2/chunks.cpp
QHexEdit2/chunks.h
QHexEdit2/chunks_win.cpp
QHexEdit2/chunks_win.h
qhexview.h
qhexview.cpp)
set_target_properties(
QHexView
PROPERTIES AUTOMOC ON
CXX_STANDARD 11
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)
target_link_libraries(QHexView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Gui)
target_link_libraries(
QHexView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Concurrent)

View File

@ -12,25 +12,17 @@ Chunks::Chunks(QObject *parent) : QObject(parent) {}
Chunks::Chunks(QIODevice *ioDevice, QObject *parent) : QObject(parent) {
setIODevice(ioDevice);
if (ioDevice)
ioDevice->setParent(this);
}
Chunks::~Chunks() {}
bool Chunks::setIODevice(QIODevice *ioDevice) {
_ioDevice = ioDevice;
if (_ioDevice &&
(_ioDevice->isOpen() ||
_ioDevice->open(QIODevice::ReadOnly))) // Try to open IODevice
{
_size = _ioDevice->size();
_ioDevice->close();
} else // Fallback is an empty buffer
{
QBuffer *buf = new QBuffer(this);
_ioDevice = buf;
_size = 0;
if (ioDevice && ioDevice->isOpen()) {
ioDevice->setParent(this);
_size = ioDevice->size();
_ioDevice = ioDevice;
} else {
return false;
}
_chunks.clear();
_pos = 0;
@ -56,8 +48,6 @@ QByteArray Chunks::data(qsizetype pos, qsizetype maxSize) {
else if ((pos + maxSize) > _size)
maxSize = _size - pos;
_ioDevice->open(QIODevice::ReadOnly);
while (maxSize > 0) {
chunk.absPos = std::numeric_limits<qsizetype>::max();
bool chunksLoopOngoing = true;
@ -105,7 +95,7 @@ QByteArray Chunks::data(qsizetype pos, qsizetype maxSize) {
pos += quint64(readBuffer.size());
}
}
_ioDevice->close();
return buffer;
}
@ -113,15 +103,12 @@ bool Chunks::write(QIODevice *iODevice, qsizetype pos, qsizetype count) {
if (count == -1)
count = _size;
// fix the bug
bool ok = (iODevice->isOpen() && iODevice->isWritable()) ||
iODevice->open(QIODevice::WriteOnly);
bool ok = iODevice->isOpen() && iODevice->isWritable();
if (ok) {
for (auto idx = pos; idx < qsizetype(count); idx += BUFFER_SIZE) {
QByteArray ba = data(idx, BUFFER_SIZE);
iODevice->write(ba);
}
iODevice->close();
}
return ok;
}
@ -253,10 +240,8 @@ qsizetype Chunks::getChunkIndex(qsizetype absPos) {
Chunk newChunk;
qsizetype readAbsPos = absPos - ioDelta;
qsizetype readPos = (readAbsPos & READ_CHUNK_MASK);
_ioDevice->open(QIODevice::ReadOnly);
_ioDevice->seek(qint64(readPos));
newChunk.data = _ioDevice->read(CHUNK_SIZE);
_ioDevice->close();
newChunk.absPos = absPos - (readAbsPos - readPos);
newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0));
_chunks.insert(insertIdx, newChunk);

View File

@ -1,310 +0,0 @@
#include "chunks_win.h"
#ifdef Q_OS_WIN
#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffffd00)
/*this file is modified by wingsummer in order to fit the QHexView*/
// ***************************************** Constructors and file settings
Chunks_win::Chunks_win(QObject *parent) : QObject(parent) {}
Chunks_win::Chunks_win(const QStorageInfo &ioDevice, QObject *parent)
: QObject(parent) {
setIODevice(ioDevice);
}
Chunks_win::~Chunks_win() {
if (_handle != INVALID_HANDLE_VALUE) {
CloseHandle(_handle);
}
}
bool Chunks_win::setIODevice(const QStorageInfo &ioDevice) {
if (ioDevice.isValid()) {
auto device = ioDevice.device();
auto devicePrefix = QStringLiteral("\\\\.\\");
QString dd = devicePrefix +
device.mid(devicePrefix.length(),
device.length() - devicePrefix.length() - 1);
_handle = CreateFileA(dd.toLatin1(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (_handle == INVALID_HANDLE_VALUE) {
return false;
}
DISK_GEOMETRY diskGeometry;
DWORD bytesReturned;
if (!DeviceIoControl(_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
&diskGeometry, sizeof(diskGeometry),
&bytesReturned, NULL)) {
CloseHandle(_handle);
return false;
}
// dont use ioDevice.bytesTotal(),
// because it's use GetDiskFreeSpaceEx API to get
this->CHUNK_SIZE = diskGeometry.BytesPerSector;
_size = diskGeometry.Cylinders.QuadPart *
diskGeometry.TracksPerCylinder * diskGeometry.SectorsPerTrack *
diskGeometry.BytesPerSector;
} else {
return false;
}
_chunks.clear();
_pos = 0;
return true;
}
// ***************************************** Getting data out of Chunks_win
QByteArray Chunks_win::data(qsizetype pos, qsizetype maxSize) {
qsizetype ioDelta = 0;
qsizetype chunkIdx = 0;
Chunk_win chunk;
QByteArray buffer;
// Do some checks and some arrangements
if (pos >= _size)
return buffer;
if (maxSize < 0)
maxSize = _size;
else if ((pos + maxSize) > _size)
maxSize = _size - pos;
while (maxSize > 0) {
chunk.absPos = std::numeric_limits<qsizetype>::max();
bool chunksLoopOngoing = true;
while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) {
// In this section, we track changes before our required data and
// we take the editdet data, if availible. ioDelta is a difference
// counter to justify the read pointer to the original data, if
// data in between was deleted or inserted.
chunk = _chunks[chunkIdx];
if (chunk.absPos > pos)
chunksLoopOngoing = false;
else {
chunkIdx += 1;
qsizetype count;
qsizetype chunkOfs = pos - chunk.absPos;
if (qsizetype(maxSize) > chunk.data.size() - chunkOfs) {
count = chunk.data.size() - chunkOfs;
ioDelta += CHUNK_SIZE - chunk.data.size();
} else
count = maxSize;
if (count > 0) {
buffer += chunk.data.mid(chunkOfs, count);
maxSize -= count;
pos += count;
}
}
}
if ((maxSize > 0) && (pos < chunk.absPos)) {
// In this section, we read data from the original source. This only
// will happen, whe no copied data is available
qint64 byteCount;
QByteArray readBuffer;
if (chunk.absPos - pos > qsizetype(maxSize))
byteCount = maxSize;
else
byteCount = chunk.absPos - pos;
maxSize -= byteCount;
// Set the pointer to the start of the sector you want to read
LARGE_INTEGER sectorOffset;
auto sorquot = (pos + ioDelta) / CHUNK_SIZE;
auto sorrem = (pos + ioDelta) % CHUNK_SIZE;
sectorOffset.QuadPart = sorquot * CHUNK_SIZE;
Q_ASSERT(SetFilePointerEx(_handle, sectorOffset, NULL, FILE_BEGIN));
readBuffer.fill(0, CHUNK_SIZE);
DWORD bytesRead;
Q_ASSERT(ReadFile(_handle, readBuffer.data(), CHUNK_SIZE,
&bytesRead, NULL));
readBuffer = readBuffer.mid(sorrem, byteCount);
buffer += readBuffer;
pos += readBuffer.size();
}
}
return buffer;
}
bool Chunks_win::write(QIODevice *iODevice, qsizetype pos, qsizetype count) {
if (count == -1)
count = _size;
// fix the bug
bool ok = (iODevice->isOpen() && iODevice->isWritable()) ||
iODevice->open(QIODevice::WriteOnly);
if (ok) {
for (auto idx = pos; idx < qsizetype(count); idx += CHUNK_SIZE) {
QByteArray ba = data(idx, CHUNK_SIZE);
iODevice->write(ba);
}
iODevice->close();
}
return ok;
}
// ***************************************** Search API
qsizetype Chunks_win::indexOf(const QByteArray &ba, qsizetype from) {
qsizetype result = -1;
QByteArray buffer;
for (auto pos = from; (pos < _size) && (result < 0); pos += CHUNK_SIZE) {
buffer = data(pos, CHUNK_SIZE + ba.size() - 1);
int findPos = buffer.indexOf(ba);
if (findPos >= 0)
result = pos + findPos;
}
return result;
}
qsizetype Chunks_win::lastIndexOf(const QByteArray &ba, qsizetype from) {
qint64 result = -1;
QByteArray buffer;
for (auto pos = from; (pos > 0) && (result < 0); pos -= CHUNK_SIZE) {
auto sPos = pos - CHUNK_SIZE - ba.size() + 1;
/*if (sPos < 0)
sPos = 0;*/
buffer = data(sPos, pos - sPos);
int findPos = buffer.lastIndexOf(ba);
if (findPos >= 0)
result = sPos + findPos;
}
return result;
}
// ***************************************** Char manipulations
bool Chunks_win::insert(qsizetype pos, char b) {
if (pos > _size)
return false;
qsizetype chunkIdx;
if (pos == _size) {
chunkIdx = getChunkIndex(pos - 1);
} else
chunkIdx = getChunkIndex(pos);
auto posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data.insert(int(posInBa), b);
_chunks[chunkIdx].dataChanged.insert(int(posInBa), char(1));
for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++)
_chunks[idx].absPos += 1;
_size += 1;
_pos = pos;
return true;
}
bool Chunks_win::overwrite(qsizetype pos, char b) {
if (pos >= _size)
return false;
auto chunkIdx = getChunkIndex(pos);
auto posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data[int(posInBa)] = b;
_chunks[chunkIdx].dataChanged[int(posInBa)] = char(1);
_pos = pos;
return true;
}
bool Chunks_win::removeAt(qsizetype pos) {
if (pos >= _size)
return false;
auto chunkIdx = getChunkIndex(pos);
auto posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data.remove(int(posInBa), 1);
_chunks[chunkIdx].dataChanged.remove(int(posInBa), 1);
for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++)
_chunks[idx].absPos -= 1;
_size -= 1;
_pos = pos;
return true;
}
// ***************************************** Utility functions
char Chunks_win::operator[](qsizetype pos) {
auto d = data(pos, 1);
if (d.isEmpty())
return '0';
return d.at(0);
}
qsizetype Chunks_win::pos() { return _pos; }
qsizetype Chunks_win::size() { return _size; }
qsizetype Chunks_win::getChunkIndex(qsizetype absPos) {
// This routine checks, if there is already a copied chunk available. If so,
// it returns a reference to it. If there is no copied chunk available,
// original data will be copied into a new chunk.
qsizetype foundIdx = -1;
qsizetype insertIdx = 0;
qsizetype ioDelta = 0;
// fix the bug by wingsummer
if (absPos < 0) {
Chunk_win newChunk;
newChunk.data = QByteArray(CHUNK_SIZE, 0);
newChunk.absPos = 0;
newChunk.dataChanged = nullptr;
_chunks.insert(insertIdx, newChunk);
return insertIdx;
}
for (int idx = 0; idx < _chunks.size(); idx++) {
Chunk_win chunk = _chunks[idx];
if ((absPos >= chunk.absPos) &&
(absPos < (chunk.absPos + chunk.data.size()))) {
foundIdx = idx;
break;
}
if (absPos < chunk.absPos) {
insertIdx = idx;
break;
}
ioDelta += chunk.data.size() - CHUNK_SIZE;
insertIdx = idx + 1;
}
if (foundIdx == -1) {
Chunk_win newChunk;
auto readAbsPos = absPos - ioDelta;
auto readPos = (readAbsPos & READ_CHUNK_MASK);
// Set the pointer to the start of the sector you want to read
LARGE_INTEGER sectorOffset;
sectorOffset.QuadPart = readPos;
Q_ASSERT(SetFilePointerEx(_handle, sectorOffset, NULL, FILE_BEGIN));
newChunk.data.fill(0, CHUNK_SIZE);
DWORD bytesRead = 0;
Q_ASSERT(ReadFile(_handle, newChunk.data.data(), CHUNK_SIZE, &bytesRead,
NULL));
newChunk.data.resize(bytesRead);
newChunk.absPos = absPos - (readAbsPos - readPos);
newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0));
_chunks.insert(insertIdx, newChunk);
foundIdx = insertIdx;
}
return foundIdx;
}
#endif

View File

@ -1,78 +0,0 @@
#ifndef Chunks_winWIN_H
#define Chunks_winWIN_H
/** \cond docNever */
/*! The Chunks_win class is the storage backend for QHexEdit.
*
* When QHexEdit loads data, Chunks_win access them using a QIODevice interface.
* When the app uses a QByteArray interface, QBuffer is used to provide again a
* QIODevice like interface. No data will be changed, therefore Chunks_win opens
* the QIODevice in QIODevice::ReadOnly mode. After every access Chunks_win
* closes the QIODevice, that's why external applications can overwrite files
* while QHexEdit shows them.
*
* When the the user starts to edit the data, Chunks_win creates a local copy of
* a chunk of data (4 kilobytes) and notes all changes there. Parallel to that
* chunk, there is a second chunk, which keep track of which bytes are changed
* and which not.
*
*/
#include <QtCore>
// note: this class is only for storage device reading
#ifdef Q_OS_WIN
#include <QStorageInfo>
#include <Windows.h>
struct Chunk_win {
QByteArray data;
QByteArray dataChanged;
qsizetype absPos;
};
class Chunks_win : public QObject {
Q_OBJECT
public:
// Constructors and file settings
Chunks_win(QObject *parent = nullptr);
Chunks_win(const QStorageInfo &ioDevice, QObject *parent);
~Chunks_win();
bool setIODevice(const QStorageInfo &ioDevice);
// Getting data out of Chunks_win
QByteArray data(qsizetype pos = 0, qsizetype maxSize = -1);
bool write(QIODevice *iODevice, qsizetype pos = 0, qsizetype count = -1);
// Search API
qsizetype indexOf(const QByteArray &ba, qsizetype from);
qsizetype lastIndexOf(const QByteArray &ba, qsizetype from);
// Char manipulations
bool insert(qsizetype pos, char b);
bool overwrite(qsizetype pos, char b);
bool removeAt(qsizetype pos);
// Utility functions
char operator[](qsizetype pos);
qsizetype pos();
qsizetype size();
private:
qsizetype getChunkIndex(qsizetype absPos);
QIODevice *_ioDevice;
qsizetype _pos;
qsizetype _size;
qsizetype CHUNK_SIZE;
HANDLE _handle = INVALID_HANDLE_VALUE;
QList<Chunk_win> _chunks;
};
#endif
#endif // Chunks_win_H

View File

@ -13,7 +13,10 @@ QFileBuffer::QFileBuffer(QObject *parent) : QHexBuffer(parent) {
QFileBuffer::~QFileBuffer() {}
uchar QFileBuffer::at(qsizetype idx) { return uchar(_chunks->data(idx, 1)[0]); }
uchar QFileBuffer::at(qsizetype idx) {
auto data = _chunks->data(idx, 1);
return uchar(data[0]);
}
qsizetype QFileBuffer::length() const { return _chunks->size(); }
@ -34,8 +37,7 @@ QByteArray QFileBuffer::read(qsizetype offset, qsizetype length) {
}
bool QFileBuffer::read(QIODevice *device) {
_chunks->setIODevice(device);
return true;
return _chunks->setIODevice(device);
}
void QFileBuffer::write(QIODevice *device) { _chunks->write(device); }

View File

@ -24,8 +24,8 @@ public:
qsizetype lastIndexOf(const QByteArray &ba, qsizetype from) override;
private:
Chunks *_chunks;
uchar *m_memory;
Chunks *_chunks = nullptr;
uchar *m_memory = nullptr;
};
#endif // QFILEBUFFER_H

View File

@ -1,69 +0,0 @@
#include "qwindriverbuffer.h"
#ifdef Q_OS_WIN
#include "document/qstoragedevice.h"
/*
* this file is implemented by wingsummer,
* 使 QHexEdit2 访 GB
*
*/
QWinDriverBuffer::QWinDriverBuffer(QObject *parent) : QHexBuffer(parent) {
_chunks = new Chunks_win(parent);
}
QWinDriverBuffer::~QWinDriverBuffer() {}
uchar QWinDriverBuffer::at(qsizetype idx) {
return uchar(_chunks->data(idx, 1)[0]);
}
qsizetype QWinDriverBuffer::length() const { return _chunks->size(); }
void QWinDriverBuffer::insert(qsizetype offset, const QByteArray &data) {
for (int i = 0; i < data.length(); i++) {
_chunks->insert(offset + i, data.at(i));
}
}
void QWinDriverBuffer::remove(qsizetype offset, qsizetype length) {
for (uint i = 0; i < uint(length); i++) {
_chunks->removeAt(offset + i);
}
}
QByteArray QWinDriverBuffer::read(qsizetype offset, qsizetype length) {
return _chunks->data(offset, length);
}
bool QWinDriverBuffer::read(QIODevice *device) {
if (device == nullptr) {
return false;
}
auto driver = qobject_cast<QStorageDevice *>(device);
if (driver == nullptr) {
delete device;
return false;
}
auto storage = driver->storage(); // only use name
delete device;
_chunks->setIODevice(storage);
return true;
}
void QWinDriverBuffer::write(QIODevice *device) { _chunks->write(device); }
qsizetype QWinDriverBuffer::indexOf(const QByteArray &ba, qsizetype from) {
return _chunks->indexOf(ba, from);
}
qsizetype QWinDriverBuffer::lastIndexOf(const QByteArray &ba, qsizetype from) {
return _chunks->lastIndexOf(ba, from);
}
#endif

View File

@ -1,35 +0,0 @@
#ifndef QWINDRIVERBUFFER_H
#define QWINDRIVERBUFFER_H
#include <qnamespace.h>
#ifdef Q_OS_WIN
#include "QHexEdit2/chunks_win.h"
#include "qhexbuffer.h"
#include <QFile>
class QWinDriverBuffer : public QHexBuffer {
public:
explicit QWinDriverBuffer(QObject *parent = nullptr);
~QWinDriverBuffer() override;
uchar at(qsizetype idx) override;
qsizetype length() const override;
void insert(qsizetype offset, const QByteArray &data) override;
void remove(qsizetype offset, qsizetype length) override;
QByteArray read(qsizetype offset, qsizetype length) override;
bool read(QIODevice *device) override;
void write(QIODevice *device) override;
qsizetype indexOf(const QByteArray &ba, qsizetype from) override;
qsizetype lastIndexOf(const QByteArray &ba, qsizetype from) override;
private:
Chunks_win *_chunks;
uchar *m_memory;
};
#endif
#endif // QWINDRIVERBUFFER_H

View File

@ -1,8 +1,8 @@
#include "bookmarkclearcommand.h"
BookMarkClearCommand::BookMarkClearCommand(QHexDocument *doc,
QList<BookMarkStruct> bookmarks,
QUndoCommand *parent)
BookMarkClearCommand::BookMarkClearCommand(
QHexDocument *doc, const QMap<qsizetype, QString> &bookmarks,
QUndoCommand *parent)
: QUndoCommand(parent), m_doc(doc), m_bookmarks(bookmarks) {}
void BookMarkClearCommand::redo() { m_doc->clearBookMark(); }

View File

@ -2,12 +2,14 @@
#define BOOKMARKCLEARCOMMAND_H
#include "document/qhexdocument.h"
#include <QMap>
#include <QObject>
#include <QUndoCommand>
class BookMarkClearCommand : public QUndoCommand {
public:
BookMarkClearCommand(QHexDocument *doc, QList<BookMarkStruct> bookmarks,
BookMarkClearCommand(QHexDocument *doc,
const QMap<qsizetype, QString> &bookmarks,
QUndoCommand *parent = nullptr);
void undo() override;
@ -15,7 +17,7 @@ public:
protected:
QHexDocument *m_doc;
QList<BookMarkStruct> m_bookmarks;
QMap<qsizetype, QString> m_bookmarks;
};
#endif // BOOKMARKCLEARCOMMAND_H

View File

@ -1,6 +1,6 @@
#include "hexcommand.h"
HexCommand::HexCommand(QHexBuffer *buffer, QHexCursor *cursor, int nibbleindex,
HexCommand::HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent)
: QUndoCommand(parent), m_buffer(buffer), m_offset(0), m_length(0),
m_cursor(cursor), m_nibbleindex(nibbleindex) {}
: QUndoCommand(parent), m_doc(doc), m_cursor(cursor), m_offset(0),
m_length(0), m_nibbleindex(nibbleindex) {}

View File

@ -1,22 +1,24 @@
#ifndef HEXCOMMAND_H
#define HEXCOMMAND_H
#include "document/buffer/qhexbuffer.h"
#include "document/qhexcursor.h"
#include "document/qhexdocument.h"
#include <QUndoCommand>
class HexCommand : public QUndoCommand {
public:
HexCommand(QHexBuffer *buffer, QHexCursor *cursor, int nibbleindex,
HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent = nullptr);
protected:
QHexBuffer *m_buffer;
QHexDocument *m_doc;
QHexCursor *m_cursor;
qsizetype m_offset;
qsizetype m_length;
QByteArray m_data;
QHexCursor *m_cursor;
int m_nibbleindex;
};

View File

@ -1,20 +1,20 @@
#include "insertcommand.h"
InsertCommand::InsertCommand(QHexBuffer *buffer, qsizetype offset,
const QByteArray &data, QHexCursor *cursor,
InsertCommand::InsertCommand(QHexDocument *doc, QHexCursor *cursor,
qsizetype offset, const QByteArray &data,
int nibbleindex, QUndoCommand *parent)
: HexCommand(buffer, cursor, nibbleindex, parent) {
: HexCommand(doc, cursor, nibbleindex, parent) {
m_offset = offset;
m_data = data;
m_length = data.length();
}
void InsertCommand::undo() {
m_buffer->remove(m_offset, m_data.length());
m_doc->_remove(m_offset, m_data.length());
m_cursor->setPos(m_offset, m_nibbleindex);
}
void InsertCommand::redo() {
m_buffer->insert(m_offset, m_data);
m_doc->_insert(m_offset, m_data);
if (m_data.length() == 1 && m_nibbleindex) {
m_cursor->setPos(m_offset, 0);
} else {

View File

@ -5,8 +5,8 @@
class InsertCommand : public HexCommand {
public:
InsertCommand(QHexBuffer *buffer, qsizetype offset, const QByteArray &data,
QHexCursor *cursor, int nibbleindex,
InsertCommand(QHexDocument *doc, QHexCursor *cursor, qsizetype offset,
const QByteArray &data, int nibbleindex,
QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;

View File

@ -1,16 +1,16 @@
#include "removecommand.h"
RemoveCommand::RemoveCommand(QHexBuffer *buffer, qsizetype offset,
RemoveCommand::RemoveCommand(QHexDocument *doc, qsizetype offset,
qsizetype length, QHexCursor *cursor,
int nibbleindex, QUndoCommand *parent)
: HexCommand(buffer, cursor, nibbleindex, parent) {
: HexCommand(doc, cursor, nibbleindex, parent) {
m_offset = offset;
m_length = length;
m_data = m_buffer->read(m_offset, m_length);
m_data = doc->read(m_offset, m_length);
}
void RemoveCommand::undo() {
m_buffer->insert(m_offset, m_data);
m_doc->_insert(m_offset, m_data);
if (m_length > 1) {
m_cursor->setPos(m_offset + m_length - 1, 1);
} else {
@ -24,5 +24,5 @@ void RemoveCommand::undo() {
void RemoveCommand::redo() {
m_cursor->setPos(m_offset, m_nibbleindex);
m_buffer->remove(m_offset, m_length);
m_doc->_remove(m_offset, m_length);
}

View File

@ -5,7 +5,7 @@
class RemoveCommand : public HexCommand {
public:
RemoveCommand(QHexBuffer *buffer, qsizetype offset, qsizetype length,
RemoveCommand(QHexDocument *doc, qsizetype offset, qsizetype length,
QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent = nullptr);
void undo() override;

View File

@ -1,22 +1,24 @@
#include "replacecommand.h"
#include "document/qhexdocument.h"
ReplaceCommand::ReplaceCommand(QHexBuffer *buffer, qsizetype offset,
ReplaceCommand::ReplaceCommand(QHexDocument *doc, qsizetype offset,
const QByteArray &data, QHexCursor *cursor,
int nibbleindex, QUndoCommand *parent)
: HexCommand(buffer, cursor, nibbleindex, parent) {
: HexCommand(doc, cursor, nibbleindex, parent) {
m_offset = offset;
m_data = data;
m_length = data.length();
m_olddata = m_buffer->read(m_offset, m_length);
m_olddata = doc->read(m_offset, m_length);
}
void ReplaceCommand::undo() {
m_buffer->replace(m_offset, m_olddata);
m_doc->_replace(m_offset, m_olddata);
m_cursor->setPos(m_offset, m_nibbleindex);
}
void ReplaceCommand::redo() {
m_buffer->replace(m_offset, m_data);
m_doc->_replace(m_offset, m_data);
if (m_data.length() == 1 && m_nibbleindex) {
m_cursor->setPos(m_offset, 0);
} else {

View File

@ -5,7 +5,7 @@
class ReplaceCommand : public HexCommand {
public:
ReplaceCommand(QHexBuffer *buffer, qsizetype offset, const QByteArray &data,
ReplaceCommand(QHexDocument *doc, qsizetype offset, const QByteArray &data,
QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent = nullptr);
void undo() override;

View File

@ -1,7 +1,7 @@
#include "metaaddcommand.h"
MetaAddCommand::MetaAddCommand(QHexMetadata *hexmeta,
QHexMetadataAbsoluteItem &meta,
const QHexMetadataItem &meta,
QUndoCommand *parent)
: MetaCommand(hexmeta, meta, parent) {}

View File

@ -6,7 +6,7 @@
class MetaAddCommand : public MetaCommand {
public:
MetaAddCommand(QHexMetadata *hexmeta, QHexMetadataAbsoluteItem &meta,
MetaAddCommand(QHexMetadata *hexmeta, const QHexMetadataItem &meta,
QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;

View File

@ -1,7 +1,7 @@
#include "metaclearcommand.h"
MetaClearCommand::MetaClearCommand(QHexMetadata *hexmeta,
QList<QHexMetadataAbsoluteItem> metas,
const QVector<QHexMetadataItem> &metas,
QUndoCommand *parent)
: QUndoCommand(parent), m_hexmeta(hexmeta), m_metas(metas) {}

View File

@ -12,7 +12,7 @@
class MetaClearCommand : public QUndoCommand {
public:
MetaClearCommand(QHexMetadata *hexmeta,
QList<QHexMetadataAbsoluteItem> metas,
const QVector<QHexMetadataItem> &metas,
QUndoCommand *parent = nullptr);
void undo() override;
@ -20,7 +20,7 @@ public:
protected:
QHexMetadata *m_hexmeta;
QList<QHexMetadataAbsoluteItem> m_metas;
QVector<QHexMetadataItem> m_metas;
};
#endif // METACLEARCOMMAND_H

View File

@ -1,5 +1,5 @@
#include "metacommand.h"
MetaCommand::MetaCommand(QHexMetadata *hexmeta, QHexMetadataAbsoluteItem &meta,
MetaCommand::MetaCommand(QHexMetadata *hexmeta, const QHexMetadataItem &meta,
QUndoCommand *parent)
: QUndoCommand(parent), m_hexmeta(hexmeta), m_meta(meta) {}

View File

@ -10,12 +10,12 @@
class MetaCommand : public QUndoCommand {
public:
MetaCommand(QHexMetadata *hexmeta, QHexMetadataAbsoluteItem &meta,
MetaCommand(QHexMetadata *hexmeta, const QHexMetadataItem &meta,
QUndoCommand *parent = nullptr);
protected:
QHexMetadata *m_hexmeta;
QHexMetadataAbsoluteItem m_meta;
QHexMetadataItem m_meta;
};
#endif // METACOMMAND_H

View File

@ -1,7 +1,7 @@
#include "metaremovecommand.h"
MetaRemoveCommand::MetaRemoveCommand(QHexMetadata *hexmeta,
QHexMetadataAbsoluteItem &meta,
const QHexMetadataItem &meta,
QUndoCommand *parent)
: MetaCommand(hexmeta, meta, parent) {}

View File

@ -9,7 +9,7 @@
class MetaRemoveCommand : public MetaCommand {
public:
MetaRemoveCommand(QHexMetadata *hexmeta, QHexMetadataAbsoluteItem &meta,
MetaRemoveCommand(QHexMetadata *hexmeta, const QHexMetadataItem &meta,
QUndoCommand *parent = nullptr);
void undo() override;

View File

@ -9,7 +9,7 @@ MetaRemovePosCommand::MetaRemovePosCommand(QHexMetadata *hexmeta, qsizetype pos,
void MetaRemovePosCommand::redo() { m_hexmeta->removeMetadata(m_pos); }
void MetaRemovePosCommand::undo() {
for (auto item : olditems)
for (auto &item : olditems)
m_hexmeta->metadata(item.begin, item.end, item.foreground,
item.background, item.comment);
}

View File

@ -18,7 +18,7 @@ public:
protected:
QHexMetadata *m_hexmeta;
qsizetype m_pos;
QList<QHexMetadataAbsoluteItem> olditems;
QVector<QHexMetadataItem> olditems;
};
#endif // METAREMOVEPOSCOMMAND_H

View File

@ -1,8 +1,8 @@
#include "metareplacecommand.h"
MetaReplaceCommand::MetaReplaceCommand(QHexMetadata *hexmeta,
QHexMetadataAbsoluteItem &meta,
QHexMetadataAbsoluteItem &oldmeta,
const QHexMetadataItem &meta,
const QHexMetadataItem &oldmeta,
QUndoCommand *parent)
: MetaCommand(hexmeta, meta, parent), m_old(oldmeta) {}

View File

@ -6,14 +6,14 @@
class MetaReplaceCommand : public MetaCommand {
public:
MetaReplaceCommand(QHexMetadata *hexmeta, QHexMetadataAbsoluteItem &meta,
QHexMetadataAbsoluteItem &oldmeta,
MetaReplaceCommand(QHexMetadata *hexmeta, const QHexMetadataItem &meta,
const QHexMetadataItem &oldmeta,
QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
private:
QHexMetadataAbsoluteItem m_old;
QHexMetadataItem m_old;
};
#endif // METAREPLACECOMMAND_H

View File

@ -1,15 +1,7 @@
#include "qhexcursor.h"
#include <QWidget>
void QHexCursor::setSelection(qsizetype offset, qsizetype length) {
auto lld = lldiv(offset, m_position.lineWidth);
m_position.line = lld.quot;
m_position.column = int(lld.rem);
moveTo(m_position);
lld = lldiv(offset + length - 1, m_position.lineWidth);
m_selection.line = lld.quot;
m_selection.column = int(lld.rem);
}
#include <QtConcurrent/QtConcurrentMap>
QHexCursor::QHexCursor(QObject *parent)
: QObject(parent), m_insertionmode(QHexCursor::OverwriteMode) {
@ -20,104 +12,168 @@ QHexCursor::QHexCursor(QObject *parent)
m_selection.line = m_selection.column = 0;
m_position.nibbleindex = m_selection.nibbleindex = 1;
setLineWidth(DEFAULT_HEX_LINE_LENGTH);
}
const QHexPosition &QHexCursor::selectionStart() const {
if (m_position.line < m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column < m_selection.column)
return m_position;
}
return m_selection;
const QHexPosition &QHexCursor::selectionStart(qsizetype index) const {
return m_sels.at(index).start;
}
const QHexPosition &QHexCursor::selectionEnd() const {
if (m_position.line > m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column > m_selection.column)
return m_position;
}
return m_selection;
const QHexPosition &QHexCursor::selectionEnd(qsizetype index) const {
return m_sels.at(index).end;
}
const QHexPosition &QHexCursor::position() const { return m_position; }
qsizetype QHexCursor::selectionCount() const { return m_sels.size(); }
const QHexSelection &QHexCursor::selection(qsizetype index) const {
return m_sels.at(index);
}
QHexCursor::InsertionMode QHexCursor::insertionMode() const {
return m_insertionmode;
}
qsizetype QHexCursor::selectionLength() const {
return this->selectionEnd() - this->selectionStart() + 1;
qsizetype QHexCursor::selectionLength(qsizetype index) const {
return m_sels.at(index).length();
}
qsizetype QHexCursor::currentLine() const { return m_position.line; }
int QHexCursor::currentColumn() const { return m_position.column; }
int QHexCursor::currentNibble() const { return m_position.nibbleindex; }
qsizetype QHexCursor::selectionLine() const { return m_selection.line; }
qsizetype QHexCursor::selectionColumn() const { return m_selection.column; }
int QHexCursor::selectionNibble() const { return m_selection.nibbleindex; }
qsizetype QHexCursor::currentSelectionLength() const {
if (hasPreviewSelection() && m_preMode != SelectionRemove) {
return qAbs(m_position - m_selection);
}
qsizetype len = 0;
auto res = QtConcurrent::blockingMappedReduced(
m_sels, &QHexSelection::length,
QOverload<
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
const qsizetype &
#else
QVector<qsizetype>::parameter_type
#endif
>::of(&QVector<qsizetype>::append));
for (auto &item : res) {
len += item;
}
return len;
}
qsizetype QHexCursor::currentLine() const { return m_selection.line; }
int QHexCursor::currentColumn() const { return m_selection.column; }
int QHexCursor::currentNibble() const { return m_selection.nibbleindex; }
bool QHexCursor::isLineSelected(qsizetype line) const {
if (!this->hasSelection())
return false;
auto first = std::min(m_position.line, m_selection.line);
auto last = std::max(m_position.line, m_selection.line);
if (isLineSelected(previewSelection(), line)) {
return true;
}
if ((line < first) || (line > last))
return false;
for (auto &sel : m_sels) {
if (isLineSelected(sel, line)) {
return true;
}
}
return true;
return false;
}
bool QHexCursor::hasSelection() const { return m_position != m_selection; }
bool QHexCursor::hasSelection() const {
return hasPreviewSelection() || hasInternalSelection();
}
void QHexCursor::clearSelection() {
bool QHexCursor::hasInternalSelection() const { return !m_sels.isEmpty(); }
void QHexCursor::clearPreviewSelection() {
m_selection = m_position;
emit positionChanged();
m_preMode = SelectionNormal;
}
void QHexCursor::moveTo(const QHexPosition &pos) {
this->moveTo(pos.line, pos.column, pos.nibbleindex);
void QHexCursor::clearSelection() { m_sels.clear(); }
void QHexCursor::moveTo(const QHexPosition &pos, bool clearSelection) {
this->moveTo(pos.line, pos.column, pos.nibbleindex, clearSelection);
}
void QHexCursor::select(const QHexPosition &pos) {
this->select(pos.line, pos.column, pos.nibbleindex);
void QHexCursor::select(const QHexPosition &pos,
QHexCursor::SelectionModes mode) {
this->select(pos.line, pos.column, pos.nibbleindex, mode);
}
void QHexCursor::moveTo(qsizetype line, int column, int nibbleindex) {
m_selection.line = line;
m_selection.column = column;
m_selection.nibbleindex = nibbleindex;
this->select(line, column, nibbleindex);
}
void QHexCursor::select(qsizetype line, int column, int nibbleindex) {
void QHexCursor::moveTo(qsizetype line, int column, int nibbleindex,
bool clearSelection) {
m_position.line = line;
m_position.column = qMax(0, column); // fix the bug by wingsummer
m_position.nibbleindex = nibbleindex;
m_selection = m_position;
if (clearSelection) {
m_sels.clear();
}
emit positionChanged();
}
void QHexCursor::moveTo(qsizetype offset) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)));
void QHexCursor::select(qsizetype line, int column, int nibbleindex,
SelectionModes modes) {
if (modes.testFlag(SelectionPreview)) {
m_selection.line = line;
m_selection.column = qMax(0, column); // fix the bug by wingsummer
m_selection.nibbleindex = nibbleindex;
modes.setFlag(SelectionPreview, false);
m_preMode = SelectionMode(int(modes));
} else {
QHexSelection sel;
sel.start = m_position;
sel.end.line = line;
sel.end.column = column;
sel.end.nibbleindex = nibbleindex;
sel.normalize();
switch (modes) {
case SelectionAdd:
mergeAdd(sel);
break;
case SelectionNormal:
m_sels.clear();
m_sels.append(sel);
break;
case SelectionRemove:
mergeRemove(sel);
break;
}
}
emit positionChanged();
emit selectionChanged();
}
void QHexCursor::setPos(qsizetype offset, int nibbleindex) {
void QHexCursor::moveTo(qsizetype offset, bool clearSelection) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)), nibbleindex);
this->moveTo(line, int(offset - (line * m_lineWidth)), clearSelection);
}
void QHexCursor::select(qsizetype length) {
this->select(
m_position.line,
std::min(m_lineWidth - 1, int(m_position.column + length - 1)));
void QHexCursor::setPos(qsizetype offset, int nibbleindex,
bool clearSelection) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)), nibbleindex,
clearSelection);
}
void QHexCursor::select(qsizetype length, QHexCursor::SelectionModes mode) {
this->select(m_position.line,
std::min(m_lineWidth - 1, int(m_position.column + length - 1)),
1, mode);
}
void QHexCursor::selectOffset(qsizetype offset, qsizetype length) {
@ -137,6 +193,11 @@ void QHexCursor::setLineWidth(quint8 width) {
m_lineWidth = width;
m_position.lineWidth = width;
m_selection.lineWidth = width;
for (auto &sel : m_sels) {
sel.start.lineWidth = width;
sel.end.lineWidth = width;
}
}
void QHexCursor::switchInsertionMode() {
@ -147,3 +208,100 @@ void QHexCursor::switchInsertionMode() {
emit insertionModeChanged();
}
bool QHexCursor::hasPreviewSelection() const {
return m_selection != m_position;
}
void QHexCursor::mergeRemove(const QHexSelection &sel) {
Q_ASSERT(sel.isNormalized());
QList<QHexSelection> buffer;
QMutex locker;
QtConcurrent::blockingMap(m_sels,
[&buffer, &locker, &sel](QHexSelection &s) {
auto r = s.removeSelection(sel);
if (r.has_value()) {
QMutexLocker l(&locker);
buffer.append(r.value());
}
});
// clean up invalid selections
auto cleanup = [](const QHexSelection &s) { return s.start == s.end; };
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_sels.removeIf(cleanup);
#else
m_sels.erase(std::remove_if(m_sels.begin(), m_sels.end(), cleanup));
#endif
QtConcurrent::blockingMap(
buffer, [&locker, this](QHexSelection &s) { mergeAdd(s, &locker); });
}
void QHexCursor::mergeAdd(const QHexSelection &sel, QMutex *locker) {
bool merged = false;
Q_ASSERT(sel.isNormalized());
for (auto p = m_sels.begin(); p != m_sels.end(); ++p) {
merged = p->mergeSelection(sel, locker);
if (merged) {
break;
}
}
if (!merged) {
m_sels.append(sel);
}
}
bool QHexCursor::isLineSelected(const QHexSelection &sel,
qsizetype line) const {
auto first = std::min(sel.start.line, sel.end.line);
auto last = std::max(sel.start.line, sel.end.line);
if ((line >= first) && (line <= last))
return true;
return false;
}
QHexSelection QHexCursor::previewSelection() const {
QHexSelection sel;
sel.start = m_position;
sel.end = m_selection;
return sel;
}
void QHexCursor::setPreviewSelectionMode(SelectionMode mode) {
m_preMode = mode;
}
QHexCursor::SelectionMode QHexCursor::previewSelectionMode() const {
return m_preMode;
}
void QHexCursor::mergePreviewSelection() {
auto ss = QHexSelection{m_position, m_selection}.normalized();
switch (m_preMode) {
case SelectionNormal:
if (m_sels.isEmpty()) {
m_sels.append(ss);
}
break;
case SelectionAdd:
mergeAdd(ss);
break;
case SelectionRemove:
mergeRemove(ss);
break;
case SelectionSingle:
m_sels.clear();
m_sels.append(ss);
break;
case SelectionPreview:
// should not go here
break;
}
clearPreviewSelection();
}

View File

@ -1,23 +1,40 @@
#ifndef QHEXCURSOR_H
#define QHEXCURSOR_H
#include <QMutex>
#include <QObject>
#include <optional>
#define DEFAULT_HEX_LINE_LENGTH 0x10
#define DEFAULT_AREA_IDENTATION 0x01
struct QHexPosition {
qsizetype line;
int column;
quint8 lineWidth;
int nibbleindex;
qsizetype line = -1;
int column = -1;
quint8 lineWidth = 0;
int nibbleindex = -1;
QHexPosition() = default;
inline qsizetype offset() const {
return static_cast<qsizetype>(line * lineWidth) + column;
}
inline int operator-(const QHexPosition &rhs) const {
return int(this->offset() - rhs.offset());
inline qsizetype operator-(const QHexPosition &rhs) const {
return this->offset() - rhs.offset();
}
inline void operator++() {
this->column++;
if (this->column >= lineWidth) {
this->line++;
this->column = 0;
}
}
inline void operator--() {
this->column--;
if (this->column < 0) {
this->line--;
this->column = lineWidth - 1;
}
}
inline bool operator==(const QHexPosition &rhs) const {
return (line == rhs.line) && (column == rhs.column) &&
@ -27,6 +44,135 @@ struct QHexPosition {
return (line != rhs.line) || (column != rhs.column) ||
(nibbleindex != rhs.nibbleindex);
}
inline bool operator<(const QHexPosition &rhs) const {
return this->offset() < rhs.offset();
}
inline bool operator>(const QHexPosition &rhs) const {
return this->offset() > rhs.offset();
}
inline bool operator<=(const QHexPosition &rhs) const {
return this->offset() <= rhs.offset();
}
inline bool operator>=(const QHexPosition &rhs) const {
return this->offset() >= rhs.offset();
}
};
struct QHexSelection {
QHexPosition start;
QHexPosition end;
void normalize(QMutex *locker = nullptr) {
if (locker) {
locker->lock();
}
if (end < start) {
std::swap(start, end);
}
if (locker) {
locker->unlock();
}
}
qsizetype length() const { return qAbs(end - start) + 1; }
bool contains(const QHexSelection &sel) const {
Q_ASSERT(isNormalized());
return this->start <= sel.start && this->end >= sel.end;
}
bool isLineSelected(qsizetype line) const {
Q_ASSERT(isNormalized());
if (this->start.line == line || this->end.line == line) {
return true;
}
return this->start.line < line && line < this->end.line;
}
bool isNormalized() const { return end >= start; }
QHexSelection normalized() const {
QHexSelection sel = *this;
if (end < start) {
std::swap(sel.start, sel.end);
}
return sel;
}
bool isIntersected(const QHexSelection &sel) const {
Q_ASSERT(isNormalized());
return !(sel.end < this->start || sel.start > this->end);
}
void intersect(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
auto s = sel.normalized();
if (locker) {
locker->lock();
}
this->start = qMax(this->start, s.start);
this->end = qMin(this->end, s.end);
if (locker) {
locker->unlock();
}
}
Q_REQUIRED_RESULT std::optional<QHexSelection>
removeSelection(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
Q_ASSERT(sel.isNormalized());
if (locker) {
locker->lock();
}
if (sel.start <= this->start) {
if (sel.end >= this->start) {
if (sel.end < this->end) {
this->start = sel.end;
++this->start;
} else {
// makes it invalid, delete later
this->end = this->start;
}
}
} else if (sel.start > this->start && sel.start < this->end) {
this->end = sel.start;
--this->end;
if (sel.end < this->end) {
// break into two ranges
QHexSelection sel;
sel.start = sel.end;
sel.end = this->end;
if (locker) {
locker->unlock();
}
return sel;
}
}
if (locker) {
locker->unlock();
}
return {};
}
bool mergeSelection(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
if (isIntersected(sel)) {
if (locker) {
locker->lock();
}
this->start = qMin(this->start, sel.start);
this->end = qMax(this->end, sel.end);
if (locker) {
locker->unlock();
}
return true;
}
return false;
}
};
class QHexCursor : public QObject {
@ -35,50 +181,89 @@ class QHexCursor : public QObject {
public:
enum InsertionMode { OverwriteMode, InsertMode };
enum SelectionMode {
SelectionNormal = 0,
SelectionAdd = 1,
SelectionRemove = 2,
SelectionSingle = 4,
SelectionPreview = 16 // a flag
};
Q_DECLARE_FLAGS(SelectionModes, SelectionMode)
public:
explicit QHexCursor(QObject *parent = nullptr);
public:
const QHexPosition &selectionStart() const;
const QHexPosition &selectionEnd() const;
const QHexPosition &position() const;
void setSelection(qsizetype offset,
qsizetype length); // added by wingsummer
qsizetype selectionCount() const;
const QHexSelection &selection(qsizetype index) const;
const QHexPosition &selectionStart(qsizetype index) const;
const QHexPosition &selectionEnd(qsizetype index) const;
InsertionMode insertionMode() const;
qsizetype selectionLength() const;
qsizetype currentLine() const;
int currentColumn() const;
int currentNibble() const;
qsizetype selectionLine() const;
qsizetype selectionColumn() const;
int selectionNibble() const;
qsizetype selectionLength(qsizetype index) const;
qsizetype currentSelectionLength() const;
bool atEnd() const;
bool isLineSelected(qsizetype line) const;
bool hasSelection() const;
bool hasInternalSelection() const;
void clearPreviewSelection();
void clearSelection();
public:
void moveTo(const QHexPosition &pos);
void moveTo(qsizetype line, int column, int nibbleindex = 1);
void moveTo(qsizetype offset);
void setPos(qsizetype offset, int nibbleindex);
// 和 moveTo 其实一样,只是为了不冲突
void select(const QHexPosition &pos);
void select(qsizetype line, int column, int nibbleindex = 1);
void select(qsizetype length);
void moveTo(const QHexPosition &pos, bool clearSelection = false);
void moveTo(qsizetype line, int column, int nibbleindex = 1,
bool clearSelection = false);
void moveTo(qsizetype offset, bool clearSelection = false);
void setPos(qsizetype offset, int nibbleindex, bool clearSelection = false);
void select(const QHexPosition &pos,
QHexCursor::SelectionModes mode = SelectionNormal);
void select(qsizetype line, int column, int nibbleindex = 1,
QHexCursor::SelectionModes mode = SelectionNormal);
void select(qsizetype length,
QHexCursor::SelectionModes mode = SelectionNormal);
void selectOffset(qsizetype offset, qsizetype length);
void setInsertionMode(InsertionMode mode);
void setLineWidth(quint8 width);
void switchInsertionMode();
bool hasPreviewSelection() const;
QHexSelection previewSelection() const;
void setPreviewSelectionMode(SelectionMode mode);
SelectionMode previewSelectionMode() const;
void mergePreviewSelection();
private:
void mergeRemove(const QHexSelection &sel);
void mergeAdd(const QHexSelection &sel, QMutex *locker = nullptr);
bool isLineSelected(const QHexSelection &sel, qsizetype line) const;
signals:
void positionChanged();
void insertionModeChanged();
void selectionChanged();
private:
InsertionMode m_insertionmode;
quint8 m_lineWidth;
QHexPosition m_position, m_selection;
SelectionMode m_preMode;
QList<QHexSelection> m_sels;
};
#endif // QHEXCURSOR_H

View File

@ -17,32 +17,35 @@
#include <QFile>
#ifdef Q_OS_WIN
#include "buffer/qwindriverbuffer.h"
#include "qstoragedevice.h"
#endif
/*======================*/
// added by wingsummer
QList<qsizetype> QHexDocument::getsBookmarkPos(qsizetype line) {
QList<qsizetype> QHexDocument::getLineBookmarksPos(qsizetype line) {
QList<qsizetype> pos;
auto begin = m_hexlinewidth * line;
auto end = m_hexlinewidth + begin;
for (auto item : bookmarks) {
if (item.pos >= begin && item.pos <= end)
pos.push_back(item.pos);
auto lbound = _bookmarks.lowerBound(begin);
auto ubound = _bookmarks.upperBound(end);
for (auto p = lbound; p != ubound; ++p) {
pos.append(p.key());
}
return pos;
}
bool QHexDocument::lineHasBookMark(qsizetype line) {
auto begin = m_hexlinewidth * line;
auto end = m_hexlinewidth + begin;
for (auto item : bookmarks) {
if (item.pos >= begin && item.pos <= end)
return true;
}
return false;
auto lbound = _bookmarks.lowerBound(begin);
auto ubound = _bookmarks.upperBound(end);
return lbound != ubound;
}
void QHexDocument::addUndoCommand(QUndoCommand *command) {
@ -90,11 +93,61 @@ bool QHexDocument::metafgVisible() { return m_metafg; }
bool QHexDocument::metaCommentVisible() { return m_metacomment; }
bool QHexDocument::isDocSaved() { return m_undostack->isClean(); }
void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
QMap<qsizetype, QString> bms;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto rmbegin = _bookmarks.lowerBound(offset);
#else
auto rmbegin = std::as_const(_bookmarks).lowerBound(offset);
#endif
auto addbegin = _bookmarks.upperBound(offset);
for (auto p = addbegin; p != _bookmarks.end(); ++p) {
bms.insert(p.key() + length, p.value());
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
for (auto it = rmbegin; it != _bookmarks.end();) {
it = _bookmarks.erase(it);
}
#else
_bookmarks.erase(rmbegin, _bookmarks.cend());
#endif
_bookmarks.insert(bms);
}
void QHexDocument::removeBookMarkAdjust(qsizetype offset, qsizetype length) {
QMap<qsizetype, QString> bms;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto rmbegin = _bookmarks.lowerBound(offset);
#else
auto rmbegin = std::as_const(_bookmarks).lowerBound(offset);
#endif
auto addbegin = _bookmarks.upperBound(offset);
for (auto p = addbegin; p != _bookmarks.end(); ++p) {
bms.insert(p.key() - length, p.value());
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
for (auto it = rmbegin; it != _bookmarks.end();) {
it = _bookmarks.erase(it);
}
#else
_bookmarks.erase(rmbegin, _bookmarks.cend());
#endif
_bookmarks.insert(bms);
}
bool QHexDocument::isDocSaved() { return m_isSaved; }
void QHexDocument::setDocSaved(bool b) {
if (b) {
m_undostack->setClean();
}
m_isSaved = b;
emit documentSaved(b);
}
@ -118,10 +171,8 @@ bool QHexDocument::setKeepSize(bool b) {
return true;
}
QList<BookMarkStruct> *QHexDocument::bookMarksPtr() { return &bookmarks; }
const QList<BookMarkStruct> &QHexDocument::bookMarks() const {
return bookmarks;
const QMap<qsizetype, QString> &QHexDocument::bookMarks() const {
return _bookmarks;
}
bool QHexDocument::AddBookMark(qsizetype pos, QString comment) {
@ -131,25 +182,29 @@ bool QHexDocument::AddBookMark(qsizetype pos, QString comment) {
return true;
}
bool QHexDocument::RemoveBookMark(qsizetype pos) {
m_undostack->push(new BookMarkRemoveCommand(this, pos, bookMark(pos)));
return true;
}
bool QHexDocument::ModBookMark(qsizetype pos, QString comment) {
if (!m_keepsize)
return false;
m_undostack->push(
new BookMarkReplaceCommand(this, pos, comment, bookMarkComment(pos)));
new BookMarkReplaceCommand(this, pos, comment, bookMark(pos)));
return true;
}
bool QHexDocument::ClearBookMark() {
if (!m_keepsize)
return false;
m_undostack->push(new BookMarkClearCommand(this, getAllBookMarks()));
m_undostack->push(new BookMarkClearCommand(this, _bookmarks));
return true;
}
bool QHexDocument::addBookMark(qsizetype pos, QString comment) {
if (m_keepsize && !existBookMark(pos)) {
BookMarkStruct b{pos, comment};
bookmarks.append(b);
_bookmarks.insert(pos, comment);
setDocSaved(false);
emit documentChanged();
emit bookMarkChanged();
@ -158,97 +213,46 @@ bool QHexDocument::addBookMark(qsizetype pos, QString comment) {
return false;
}
QString QHexDocument::bookMarkComment(qsizetype pos) {
if (pos > 0 && pos < m_buffer->length()) {
for (auto item : bookmarks) {
if (item.pos == pos) {
return item.comment;
}
}
}
return QString();
QString QHexDocument::bookMark(qsizetype pos) { return _bookmarks.value(pos); }
bool QHexDocument::bookMarkExists(qsizetype pos) {
return _bookmarks.contains(pos);
}
BookMarkStruct QHexDocument::bookMark(qsizetype pos) {
if (pos > 0 && pos < m_buffer->length()) {
for (auto item : bookmarks) {
if (item.pos == pos) {
return item;
}
}
}
return BookMarkStruct{-1, ""};
qsizetype QHexDocument::bookMarkPos(qsizetype index) {
Q_ASSERT(index >= 0 && index < _bookmarks.size());
return *(std::next(_bookmarks.keyBegin(), index));
}
BookMarkStruct QHexDocument::bookMarkByIndex(qsizetype index) {
if (index >= 0 && index < bookmarks.count()) {
return bookmarks.at(index);
} else {
BookMarkStruct b;
b.pos = -1;
return b;
}
}
bool QHexDocument::RemoveBookMarks(QList<qsizetype> &pos) {
bool QHexDocument::RemoveBookMarks(const QList<qsizetype> &pos) {
if (!m_keepsize)
return false;
m_undostack->beginMacro("RemoveBookMarks");
for (auto p : pos) {
m_undostack->push(
new BookMarkRemoveCommand(this, p, bookMarkComment(p)));
m_undostack->push(new BookMarkRemoveCommand(this, p, bookMark(p)));
}
m_undostack->endMacro();
emit documentChanged();
return true;
}
bool QHexDocument::RemoveBookMark(qsizetype index) {
if (!m_keepsize)
return false;
auto b = bookmarks.at(index);
m_undostack->push(new BookMarkRemoveCommand(this, b.pos, b.comment));
return true;
}
bool QHexDocument::removeBookMark(qsizetype pos) {
if (m_keepsize && pos >= 0 && pos < m_buffer->length()) {
int index = 0;
for (auto item : bookmarks) {
if (pos == item.pos) {
bookmarks.removeAt(index);
setDocSaved(false);
emit documentChanged();
emit bookMarkChanged();
break;
}
index++;
if (m_keepsize) {
auto ret = _bookmarks.remove(pos) != 0;
if (ret) {
setDocSaved(false);
}
return true;
return ret;
}
return false;
}
bool QHexDocument::removeBookMarkByIndex(qsizetype index) {
if (m_keepsize && index >= 0 && index < bookmarks.count()) {
bookmarks.removeAt(index);
setDocSaved(false);
emit documentChanged();
emit bookMarkChanged();
return true;
}
return false;
}
bool QHexDocument::modBookMark(qsizetype pos, QString comment) {
if (m_keepsize && pos > 0 && pos < m_buffer->length()) {
for (auto &item : bookmarks) {
if (item.pos == pos) {
item.comment = comment;
setDocSaved(false);
emit bookMarkChanged();
return true;
}
bool QHexDocument::modBookMark(qsizetype pos, const QString &comment) {
if (m_keepsize) {
if (_bookmarks.contains(pos)) {
_bookmarks[pos] = comment;
setDocSaved(false);
return true;
}
}
return false;
@ -256,7 +260,7 @@ bool QHexDocument::modBookMark(qsizetype pos, QString comment) {
bool QHexDocument::clearBookMark() {
if (m_keepsize) {
bookmarks.clear();
_bookmarks.clear();
setDocSaved(false);
emit documentChanged();
emit bookMarkChanged();
@ -266,22 +270,13 @@ bool QHexDocument::clearBookMark() {
}
bool QHexDocument::existBookMark(qsizetype pos) {
for (auto item : bookmarks) {
if (item.pos == pos) {
return true;
}
}
return false;
return _bookmarks.contains(pos);
}
const QList<BookMarkStruct> &QHexDocument::getAllBookMarks() {
return bookmarks;
}
qsizetype QHexDocument::bookMarksCount() const { return _bookmarks.count(); }
qsizetype QHexDocument::bookMarksCount() const { return bookmarks.count(); }
void QHexDocument::applyBookMarks(const QList<BookMarkStruct> &books) {
bookmarks.append(books);
void QHexDocument::applyBookMarks(const QMap<qsizetype, QString> &books) {
_bookmarks = books;
setDocSaved(false);
emit documentChanged();
}
@ -338,10 +333,7 @@ bool QHexDocument::insert(qsizetype offset, const QByteArray &data) {
if (m_keepsize || m_readonly || m_islocked ||
(offset < m_buffer->length() && m_metadata->hasMetadata()))
return false;
m_buffer->insert(offset, data);
setDocSaved(false);
emit documentChanged();
return true;
return this->_insert(offset, data);
}
bool QHexDocument::replace(qsizetype offset, uchar b) {
@ -353,16 +345,44 @@ bool QHexDocument::replace(qsizetype offset, uchar b) {
bool QHexDocument::replace(qsizetype offset, const QByteArray &data) {
if (m_readonly || m_islocked)
return false;
return this->_replace(offset, data);
}
bool QHexDocument::remove(qsizetype offset, qsizetype len) {
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
return false;
return this->_remove(offset, len);
}
bool QHexDocument::_insert(qsizetype offset, uchar b) {
return this->_insert(offset, QByteArray(1, char(b)));
}
bool QHexDocument::_insert(qsizetype offset, const QByteArray &data) {
m_buffer->insert(offset, data);
auto len = data.size();
insertBookMarkAdjust(offset, len);
m_metadata->insertAdjust(offset, len);
setDocSaved(false);
emit documentChanged();
return true;
}
bool QHexDocument::_replace(qsizetype offset, uchar b) {
return this->_replace(offset, QByteArray(1, char(b)));
}
bool QHexDocument::_replace(qsizetype offset, const QByteArray &data) {
m_buffer->replace(offset, data);
setDocSaved(false);
emit documentChanged();
return true;
}
bool QHexDocument::remove(qsizetype offset, qsizetype len) {
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
return false;
bool QHexDocument::_remove(qsizetype offset, qsizetype len) {
m_buffer->remove(offset, len);
removeBookMarkAdjust(offset, len);
m_metadata->removeAdjust(offset, len);
setDocSaved(false);
emit documentChanged();
return true;
@ -392,8 +412,10 @@ QHexDocument::QHexDocument(QHexBuffer *buffer, bool readonly)
m_metadata = new QHexMetadata(m_undostack, this);
m_metadata->setLineWidth(m_hexlinewidth);
connect(m_metadata, &QHexMetadata::metadataChanged, this,
&QHexDocument::metaDataChanged);
connect(m_metadata, &QHexMetadata::metadataChanged, this, [this] {
setDocSaved(false);
emit metaDataChanged();
});
/*=======================*/
// added by wingsummer
@ -425,9 +447,6 @@ void QHexDocument::setHexLineWidth(quint8 value) {
}
QHexMetadata *QHexDocument::metadata() const { return m_metadata; }
QByteArray QHexDocument::read(qsizetype offset, qsizetype len) {
return m_buffer->read(offset, len);
}
char QHexDocument::at(qsizetype offset) const {
return char(m_buffer->at(offset));
@ -457,6 +476,12 @@ void QHexDocument::redo() {
emit documentChanged();
}
void QHexDocument::beginMarco(const QString &text) {
m_undostack->beginMacro(text);
}
void QHexDocument::endMarco() { m_undostack->endMacro(); }
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset, uchar b,
int nibbleindex) {
if (m_keepsize || m_readonly || m_islocked)
@ -473,14 +498,12 @@ void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset, uchar b,
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset,
const QByteArray &data, int nibbleindex) {
if (m_keepsize || m_readonly || m_islocked ||
(offset < m_buffer->length() && m_metadata->hasMetadata()))
if (m_keepsize || m_readonly || m_islocked)
return;
if (!m_metadata->hasMetadata())
m_undostack->push(
new InsertCommand(m_buffer, offset, data, cursor, nibbleindex));
else
m_buffer->insert(offset, data);
m_undostack->push(
new InsertCommand(this, cursor, offset, data, nibbleindex));
emit documentChanged();
}
@ -489,7 +512,7 @@ void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset,
if (m_readonly || m_islocked)
return;
m_undostack->push(
new ReplaceCommand(m_buffer, offset, data, cursor, nibbleindex));
new ReplaceCommand(this, offset, data, cursor, nibbleindex));
emit documentChanged();
}
@ -498,7 +521,7 @@ bool QHexDocument::Remove(QHexCursor *cursor, qsizetype offset, qsizetype len,
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
return false;
m_undostack->push(
new RemoveCommand(m_buffer, offset, len, cursor, nibbleindex));
new RemoveCommand(this, offset, len, cursor, nibbleindex));
emit documentChanged();
return true;
}
@ -539,7 +562,8 @@ QHexDocument *QHexDocument::fromLargeFile(const QString &filename,
if (!filename.isEmpty()) {
f->setFileName(filename);
QHexBuffer *hexbuffer = new QFileBuffer();
if (hexbuffer->read(f)) {
if (f->open(readonly ? QFile::ReadOnly : QFile::ReadWrite) &&
hexbuffer->read(f)) {
return new QHexDocument(hexbuffer,
readonly); // modified by wingsummer
} else {
@ -558,8 +582,10 @@ QHexDocument *QHexDocument::fromStorageDriver(const QStorageInfo &storage,
#ifdef Q_OS_WIN
auto f = new QStorageDevice;
f->setStorage(storage);
auto hexbuffer = new QWinDriverBuffer();
if (hexbuffer->read(f)) {
auto hexbuffer = new QFileBuffer();
if (f->open(readonly ? QStorageDevice::ReadOnly
: QStorageDevice::ReadWrite) &&
hexbuffer->read(f)) {
return new QHexDocument(hexbuffer, readonly);
} else {
delete hexbuffer;
@ -569,3 +595,5 @@ QHexDocument *QHexDocument::fromStorageDriver(const QStorageInfo &storage,
return fromLargeFile(storage.device(), readonly);
#endif
}
QHexBuffer *QHexDocument::buffer() const { return m_buffer; }

View File

@ -9,16 +9,6 @@
#include <QStorageInfo>
#include <QUndoStack>
/*=========================*/
// added by wingsummer
struct BookMarkStruct {
qsizetype pos;
QString comment;
};
/*=========================*/
class QHexDocument : public QObject {
Q_OBJECT
@ -44,7 +34,7 @@ public:
void addUndoCommand(QUndoCommand *command);
bool lineHasBookMark(qsizetype line);
QList<qsizetype> getsBookmarkPos(qsizetype line);
QList<qsizetype> getLineBookmarksPos(qsizetype line);
bool setLockedFile(bool b);
bool setKeepSize(bool b);
@ -54,28 +44,27 @@ public:
//----------------------------------
bool AddBookMark(qsizetype pos, QString comment);
bool RemoveBookMark(qsizetype index);
bool RemoveBookMarks(QList<qsizetype> &pos);
bool RemoveBookMark(qsizetype pos);
bool RemoveBookMarks(const QList<qsizetype> &pos);
bool ModBookMark(qsizetype pos, QString comment);
bool ClearBookMark();
//----------------------------------
bool addBookMark(qsizetype pos, QString comment);
bool modBookMark(qsizetype pos, QString comment);
bool modBookMark(qsizetype pos, const QString &comment);
BookMarkStruct bookMarkByIndex(qsizetype index);
BookMarkStruct bookMark(qsizetype pos);
QString bookMark(qsizetype pos);
bool bookMarkExists(qsizetype pos);
// note: maybe changed when bookmarks are chaged
qsizetype bookMarkPos(qsizetype index);
QString bookMarkComment(qsizetype pos);
const QList<BookMarkStruct> &getAllBookMarks();
qsizetype bookMarksCount() const;
void applyBookMarks(const QList<BookMarkStruct> &books);
bool removeBookMarkByIndex(qsizetype index);
void applyBookMarks(const QMap<qsizetype, QString> &books);
bool removeBookMark(qsizetype pos);
bool clearBookMark();
QList<BookMarkStruct> *bookMarksPtr();
const QList<BookMarkStruct> &bookMarks() const;
const QMap<qsizetype, QString> &bookMarks() const;
bool existBookMark(qsizetype pos);
@ -98,10 +87,13 @@ public:
bool metabgVisible();
bool metaCommentVisible();
void insertBookMarkAdjust(qsizetype offset, qsizetype length);
void removeBookMarkAdjust(qsizetype offset, qsizetype length);
/*======================*/
public:
QByteArray read(qsizetype offset, qsizetype len = -1);
QByteArray read(qsizetype offset, qsizetype len = -1) const;
char at(qsizetype offset) const;
void SetBaseAddress(quintptr baseaddress);
@ -112,6 +104,9 @@ public slots:
void undo();
void redo();
void beginMarco(const QString &text);
void endMarco();
void Insert(QHexCursor *cursor, qsizetype offset, uchar b, int nibbleindex);
void Insert(QHexCursor *cursor, qsizetype offset, const QByteArray &data,
int nibbleindex);
@ -122,7 +117,6 @@ public slots:
bool Remove(QHexCursor *cursor, qsizetype offset, qsizetype len,
int nibbleindex = 0);
QByteArray read(qsizetype offset, qsizetype len) const;
bool saveTo(QIODevice *device, bool cleanUndo);
// qsizetype searchForward(const QByteArray &ba);
@ -140,6 +134,12 @@ public slots:
bool replace(qsizetype offset, const QByteArray &data);
bool remove(qsizetype offset, qsizetype len);
bool _insert(qsizetype offset, uchar b);
bool _insert(qsizetype offset, const QByteArray &data);
bool _replace(qsizetype offset, uchar b);
bool _replace(qsizetype offset, const QByteArray &data);
bool _remove(qsizetype offset, qsizetype len);
/*================================*/
/*================================*/
@ -166,6 +166,8 @@ public:
static QHexDocument *fromStorageDriver(const QStorageInfo &storage,
bool readonly = false);
QHexBuffer *buffer() const;
signals:
/*================================*/
@ -202,10 +204,12 @@ private:
/*======================*/
// added by wingsummer
bool m_isSaved = true;
bool m_readonly;
bool m_keepsize;
bool m_islocked;
QList<BookMarkStruct> bookmarks;
QMap<qsizetype, QString> _bookmarks;
bool m_metafg = true;
bool m_metabg = true;

View File

@ -5,12 +5,23 @@
#include "commands/meta/metaremoveposcommand.h"
#include "commands/meta/metareplacecommand.h"
#include <QtAlgorithms>
#include <QtConcurrent/QtConcurrentMap>
QHexMetadata::QHexMetadata(QUndoStack *undo, QObject *parent)
: QObject(parent), m_undo(undo) {}
const QHexLineMetadata &QHexMetadata::get(qsizetype line) const {
auto it = m_metadata.find(line);
return it.value();
QHexLineMetadata QHexMetadata::get(qsizetype line) const {
if (!m_linemeta.contains(line)) {
return {};
}
QHexLineMetadata ret;
for (auto &item : m_linemeta[line]) {
ret.append(item);
}
return ret;
}
/*==================================*/
@ -18,13 +29,12 @@ const QHexLineMetadata &QHexMetadata::get(qsizetype line) const {
//----------undo redo wrapper----------
void QHexMetadata::ModifyMetadata(QHexMetadataAbsoluteItem newmeta,
QHexMetadataAbsoluteItem oldmeta) {
void QHexMetadata::ModifyMetadata(QHexMetadataItem newmeta,
QHexMetadataItem oldmeta) {
m_undo->push(new MetaReplaceCommand(this, newmeta, oldmeta));
}
void QHexMetadata::RemoveMetadatas(
const QList<QHexMetadataAbsoluteItem> &items) {
void QHexMetadata::RemoveMetadatas(const QList<QHexMetadataItem> &items) {
m_undo->beginMacro("RemoveMetadatas");
for (auto &item : items) {
RemoveMetadata(item);
@ -32,7 +42,7 @@ void QHexMetadata::RemoveMetadatas(
m_undo->endMacro();
}
void QHexMetadata::RemoveMetadata(QHexMetadataAbsoluteItem item) {
void QHexMetadata::RemoveMetadata(QHexMetadataItem item) {
m_undo->push(new MetaRemoveCommand(this, item));
}
@ -43,81 +53,98 @@ void QHexMetadata::RemoveMetadata(qsizetype offset) {
void QHexMetadata::Metadata(qsizetype begin, qsizetype end,
const QColor &fgcolor, const QColor &bgcolor,
const QString &comment) {
QHexMetadataAbsoluteItem absi{begin, end, fgcolor, bgcolor, comment};
QHexMetadataItem absi{begin, end, fgcolor, bgcolor, comment};
m_undo->push(new MetaAddCommand(this, absi));
}
void QHexMetadata::Clear() {
m_undo->push(new MetaClearCommand(this, getallMetas()));
m_undo->push(new MetaClearCommand(this, this->getAllMetadata()));
}
//-------- the real function-----------
void QHexMetadata::undo() { m_undo->undo(); }
void QHexMetadata::redo() { m_undo->redo(); }
bool QHexMetadata::canUndo() { return m_undo->canUndo(); }
bool QHexMetadata::canRedo() { return m_undo->canRedo(); }
QList<QHexMetadataAbsoluteItem> QHexMetadata::getallMetas() {
return m_absoluteMetadata;
}
const QList<QHexMetadataAbsoluteItem> &QHexMetadata::getallMetasPtr() {
return m_absoluteMetadata;
}
void QHexMetadata::modifyMetadata(QHexMetadataAbsoluteItem newmeta,
QHexMetadataAbsoluteItem oldmeta) {
removeMetadata(oldmeta);
metadata(newmeta.begin, newmeta.end, newmeta.foreground, newmeta.background,
newmeta.comment);
}
void QHexMetadata::removeMetadata(QHexMetadataAbsoluteItem item) {
auto firstRow = item.begin / m_lineWidth;
auto lastRow = item.end / m_lineWidth;
for (auto i = firstRow; i <= lastRow; i++) {
QList<QHexMetadataItem> delmeta;
auto it = m_metadata.find(i);
if (it != m_metadata.end()) {
for (auto iitem : *it) {
if (iitem.foreground == item.foreground &&
iitem.background == item.background &&
iitem.comment == item.comment) {
delmeta.push_back(iitem);
}
}
for (auto iitem : delmeta) {
it->remove(iitem);
}
m_absoluteMetadata.removeOne(item);
}
bool QHexMetadata::modifyMetadata(const QHexMetadataItem &newmeta,
const QHexMetadataItem &oldmeta) {
if (removeMetadata(oldmeta)) {
metadata(newmeta.begin, newmeta.end, newmeta.foreground,
newmeta.background, newmeta.comment);
return true;
}
return false;
}
bool QHexMetadata::removeMetadata(const QHexMetadataItem &item) {
auto index = m_metadata.indexOf(item);
if (index < 0) {
return false;
}
m_metadata.removeAt(index);
for (auto &l : m_linemeta) {
l.remove(item);
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_linemeta.erase(std::remove_if(
m_linemeta.begin(), m_linemeta.end(),
[](const QHash<QHexMetadataItem, QHexLineMetadata> &item) {
return item.isEmpty();
}));
#else
m_linemeta.removeIf(
[](const QPair<qsizetype, QHash<QHexMetadataItem, QHexLineMetadata>>
&item) { return item.second.isEmpty(); });
#endif
emit metadataChanged();
return true;
}
void QHexMetadata::removeMetadata(qsizetype offset) {
auto rmfn = [offset, this](const QHexMetadataItem &item) {
auto r = offset >= item.begin && offset <= item.end;
if (r) {
for (auto &l : m_linemeta) {
l.remove(item);
}
}
return r;
};
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_metadata.erase(
std::remove_if(m_metadata.begin(), m_metadata.end(), rmfn));
#else
m_metadata.removeIf(rmfn);
#endif
emit metadataChanged();
}
void QHexMetadata::removeMetadata(qsizetype offset) {
QList<QHexMetadataAbsoluteItem> delneeded;
for (auto item : m_absoluteMetadata) {
if (offset >= item.begin && offset <= item.end) {
removeMetadata(item);
}
}
QVector<QHexMetadataItem> QHexMetadata::getAllMetadata() const {
return m_metadata;
}
QList<QHexMetadataAbsoluteItem> QHexMetadata::gets(qsizetype offset) {
return m_absoluteMetadata;
QVector<QHexMetadataItem> QHexMetadata::gets(qsizetype offset) {
QVector<QHexMetadataItem> ret;
std::copy_if(
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_metadata.begin(), m_metadata.end(),
#else
m_metadata.constBegin(), m_metadata.constEnd(),
#endif
std::back_inserter(ret), [offset](const QHexMetadataItem &item) {
return offset >= item.begin && offset <= item.end;
});
return ret;
}
void QHexMetadata::applyMetas(QList<QHexMetadataAbsoluteItem> metas) {
for (auto item : metas) {
metadata(item.begin, item.end, item.foreground, item.background,
item.comment);
}
void QHexMetadata::applyMetas(const QVector<QHexMetadataItem> &metas) {
m_metadata = metas;
}
bool QHexMetadata::hasMetadata() { return m_absoluteMetadata.count() > 0; }
bool QHexMetadata::hasMetadata() { return m_metadata.count() > 0; }
/*==================================*/
@ -145,41 +172,148 @@ QString QHexMetadata::comments(qsizetype line, qsizetype column) const {
}
bool QHexMetadata::lineHasMetadata(qsizetype line) const {
return m_metadata.contains(line);
return m_linemeta.contains(line);
}
qsizetype QHexMetadata::size() const { return m_absoluteMetadata.size(); }
qsizetype QHexMetadata::size() const { return m_metadata.size(); }
void QHexMetadata::beginMarco(const QString &text) { m_undo->beginMacro(text); }
void QHexMetadata::endMarco() { m_undo->endMacro(); }
void QHexMetadata::clear() {
m_absoluteMetadata.clear();
m_linemeta.clear();
m_metadata.clear();
emit metadataChanged();
}
void QHexMetadata::metadata(qsizetype begin, qsizetype end,
bool QHexMetadata::metadata(qsizetype begin, qsizetype end,
const QColor &fgcolor, const QColor &bgcolor,
const QString &comment) {
QHexMetadataAbsoluteItem absi{begin, end, fgcolor, bgcolor, comment};
m_absoluteMetadata.append(absi);
setAbsoluteMetadata(absi);
if (begin > end)
return false;
if (!fgcolor.isValid() || fgcolor.alpha() == 0) {
if (!bgcolor.isValid() || bgcolor.alpha() == 0) {
if (comment.isEmpty()) {
return false;
}
}
}
QHexMetadataItem absi{begin, end, fgcolor, bgcolor, comment};
addMetadata(absi);
emit metadataChanged();
return true;
}
void QHexMetadata::setAbsoluteMetadata(const QHexMetadataAbsoluteItem &mai) {
Q_ASSERT(m_lineWidth > 0);
void QHexMetadata::setLineWidth(quint8 width) {
if (width != m_lineWidth) {
m_lineWidth = width;
const auto firstRow = mai.begin / m_lineWidth;
const auto lastRow = mai.end / m_lineWidth;
m_linemeta.clear();
for (auto &item : m_metadata) {
addMetadata(item);
}
emit metadataChanged();
}
}
void QHexMetadata::insertAdjust(qsizetype offset, qsizetype length) {
m_linemeta.clear();
QtConcurrent::blockingMap(
m_metadata, [offset, length](QHexMetadataItem &meta) {
if (meta.end < offset) {
return;
}
if (meta.begin <= offset && meta.end > offset) {
meta.end += length;
} else {
meta.begin += length;
meta.end += length;
}
});
for (auto &meta : m_metadata) {
addMetaLines(meta);
}
}
void QHexMetadata::removeAdjust(qsizetype offset, qsizetype length) {
m_linemeta.clear();
QtConcurrent::blockingMap(
m_metadata, [offset, length](QHexMetadataItem &meta) {
if (meta.end < offset) {
return;
}
if (meta.begin <= offset && meta.end > offset) {
meta.end -= length;
if (meta.begin > meta.end) {
meta.flag = true;
}
} else {
meta.begin -= length;
meta.end -= length;
}
});
auto rmfn = [](const QHexMetadataItem &meta) { return meta.flag; };
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_metadata.erase(
std::remove_if(m_metadata.begin(), m_metadata.end(), rmfn));
#else
m_metadata.removeIf(rmfn);
#endif
for (auto &meta : m_metadata) {
addMetaLines(meta);
}
}
bool QHexMetadata::color(qsizetype begin, qsizetype end, const QColor &fgcolor,
const QColor &bgcolor) {
return this->metadata(begin, end, fgcolor, bgcolor, QString());
}
bool QHexMetadata::foreground(qsizetype begin, qsizetype end,
const QColor &fgcolor) {
return this->color(begin, end, fgcolor, QColor());
}
bool QHexMetadata::background(qsizetype begin, qsizetype end,
const QColor &bgcolor) {
return this->color(begin, end, QColor(), bgcolor);
}
bool QHexMetadata::comment(qsizetype begin, qsizetype end,
const QString &comment) {
return this->metadata(begin, end, QColor(), QColor(), comment);
}
void QHexMetadata::addMetadata(const QHexMetadataItem &mi) {
addMetaLines(mi);
m_metadata << mi;
}
void QHexMetadata::addMetaLines(const QHexMetadataItem &mi) {
const auto firstRow = mi.begin / m_lineWidth;
const auto lastRow = mi.end / m_lineWidth;
for (auto row = firstRow; row <= lastRow; ++row) {
qsizetype start, length;
if (row == firstRow) {
start = mai.begin % m_lineWidth;
Q_ASSERT(m_lineWidth > 0);
start = mi.begin % m_lineWidth;
} else {
start = 0;
}
if (row == lastRow) {
const int lastChar = mai.end % m_lineWidth;
Q_ASSERT(m_lineWidth > 0);
const int lastChar = mi.end % m_lineWidth;
length = lastChar - start;
} else {
// fix the bug by wingsummer
@ -190,69 +324,8 @@ void QHexMetadata::setAbsoluteMetadata(const QHexMetadataAbsoluteItem &mai) {
}
if (length > 0) {
setMetadata({row, start, length, mai.foreground, mai.background,
mai.comment});
m_linemeta[row][mi].append(
{start, length, mi.foreground, mi.background, mi.comment});
}
}
}
void QHexMetadata::setLineWidth(quint8 width) {
if (width != m_lineWidth) {
m_lineWidth = width;
// clean m_metadata
m_metadata.clear();
// and regenerate with new line width size
for (int i = 0; i < m_absoluteMetadata.size(); ++i) {
setAbsoluteMetadata(m_absoluteMetadata[i]);
}
}
}
void QHexMetadata::metadata(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor, const QColor &bgcolor,
const QString &comment) {
const qsizetype begin = qsizetype(line * m_lineWidth + uint(start));
const qsizetype end = begin + length;
// delegate to the new interface
this->metadata(begin, end, fgcolor, bgcolor, comment);
emit metadataChanged();
}
void QHexMetadata::color(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor, const QColor &bgcolor) {
this->metadata(line, start, length, fgcolor, bgcolor, QString());
}
void QHexMetadata::foreground(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor) {
this->color(line, start, length, fgcolor, QColor());
}
void QHexMetadata::background(qsizetype line, qsizetype start, qsizetype length,
const QColor &bgcolor) {
this->color(line, start, length, QColor(), bgcolor);
}
void QHexMetadata::comment(qsizetype line, qsizetype start, qsizetype length,
const QString &comment) {
this->metadata(line, start, length, QColor(), QColor(), comment);
}
void QHexMetadata::setMetadata(const QHexMetadataItem &mi) {
if (!m_metadata.contains(mi.line)) {
QHexLineMetadata linemetadata;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
linemetadata << mi;
#else
linemetadata.push_back(mi);
#endif
m_metadata[mi.line] = linemetadata;
} else {
QHexLineMetadata &linemetadata = m_metadata[mi.line];
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
linemetadata << mi;
#else
linemetadata.push_back(mi);
#endif
}
}

View File

@ -2,55 +2,82 @@
#define QHEXMETADATA_H
#include <QObject>
#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
#include <QLinkedList>
#else
#include <list>
#endif
#include <QColor>
#include <QHash>
#include <QMap>
#include <QUndoStack>
#include <QVector>
struct QHexMetadataAbsoluteItem {
qsizetype begin;
qsizetype end;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
using qhash_result_t = uint;
// copying from QT6 source code for supporting QT5's qHashMulti
namespace QtPrivate {
template <typename T>
inline constexpr bool
QNothrowHashableHelper_v = noexcept(qHash(std::declval<const T &>()));
template <typename T, typename Enable = void>
struct QNothrowHashable : std::false_type {};
template <typename T>
struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>>
: std::true_type {};
template <typename T>
constexpr inline bool QNothrowHashable_v = QNothrowHashable<T>::value;
} // namespace QtPrivate
template <typename... T>
constexpr qhash_result_t
qHashMulti(qhash_result_t seed, const T &...args) noexcept(
std::conjunction_v<QtPrivate::QNothrowHashable<T>...>) {
QtPrivate::QHashCombine hash;
return ((seed = hash(seed, args)), ...), seed;
}
#else
using qhash_result_t = size_t;
#endif
struct QHexMetadataItem {
qsizetype begin = -1;
qsizetype end = -1;
QColor foreground, background;
QString comment;
bool flag = false;
// added by wingsummer
bool operator==(const QHexMetadataAbsoluteItem &item) const {
bool operator==(const QHexMetadataItem &item) const {
return begin == item.begin && end == item.end &&
foreground == item.foreground && background == item.background &&
comment == item.comment;
}
};
struct QHexMetadataItem {
qsizetype line;
qsizetype start, length;
inline qhash_result_t qHash(const QHexMetadataItem &c,
qhash_result_t seed) noexcept {
return qHashMulti(seed, c.begin, c.end, c.foreground.rgba(),
c.background.rgba(), c.comment);
}
// only for rendering
struct QHexLineMetadataItem {
qsizetype start = -1, length = 0;
QColor foreground, background;
QString comment;
// added by wingsummer
bool operator==(const QHexMetadataItem &item) const {
return line == item.line && start == item.start &&
foreground == item.foreground && background == item.background &&
comment == item.comment;
}
QHexMetadataItem *parent = nullptr;
};
typedef std::list<QHexMetadataItem> QHexLineMetadata;
typedef QList<QHexLineMetadataItem> QHexLineMetadata;
class QHexMetadata : public QObject {
Q_OBJECT
public:
explicit QHexMetadata(QUndoStack *undo, QObject *parent = nullptr);
const QHexLineMetadata &get(qsizetype line) const;
QHexLineMetadata get(qsizetype line) const;
QString comments(qsizetype line, qsizetype column) const;
bool lineHasMetadata(qsizetype line) const; // modified by wingsummer
@ -59,10 +86,12 @@ public:
/*============================*/
// added by wingsummer
void ModifyMetadata(QHexMetadataAbsoluteItem newmeta,
QHexMetadataAbsoluteItem oldmeta);
void RemoveMetadatas(const QList<QHexMetadataAbsoluteItem> &items);
void RemoveMetadata(QHexMetadataAbsoluteItem item);
void beginMarco(const QString &text);
void endMarco();
void ModifyMetadata(QHexMetadataItem newmeta, QHexMetadataItem oldmeta);
void RemoveMetadatas(const QList<QHexMetadataItem> &items);
void RemoveMetadata(QHexMetadataItem item);
void RemoveMetadata(qsizetype offset);
void Metadata(qsizetype begin, qsizetype end, const QColor &fgcolor,
const QColor &bgcolor, const QString &comment);
@ -70,17 +99,15 @@ public:
//---------------------------------------------------------
void modifyMetadata(QHexMetadataAbsoluteItem newmeta,
QHexMetadataAbsoluteItem oldmeta);
void removeMetadata(QHexMetadataAbsoluteItem item);
bool modifyMetadata(const QHexMetadataItem &newmeta,
const QHexMetadataItem &oldmeta);
bool removeMetadata(const QHexMetadataItem &item);
void removeMetadata(qsizetype offset);
QList<QHexMetadataAbsoluteItem> gets(qsizetype offset);
void applyMetas(QList<QHexMetadataAbsoluteItem> metas);
void redo();
void undo();
bool canRedo();
bool canUndo();
QVector<QHexMetadataItem> getAllMetadata() const;
QVector<QHexMetadataItem> gets(qsizetype offset);
void applyMetas(const QVector<QHexMetadataItem> &metas);
bool hasMetadata();
/*============================*/
@ -88,44 +115,35 @@ public:
void clear();
void setLineWidth(quint8 width);
void insertAdjust(qsizetype offset, qsizetype length);
void removeAdjust(qsizetype offset, qsizetype length);
public:
// new interface with begin, end
void metadata(qsizetype begin, qsizetype end, const QColor &fgcolor,
bool metadata(qsizetype begin, qsizetype end, const QColor &fgcolor,
const QColor &bgcolor, const QString &comment);
// old interface with line, start, length
void metadata(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor, const QColor &bgcolor,
const QString &comment);
void color(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor, const QColor &bgcolor);
void foreground(qsizetype line, qsizetype start, qsizetype length,
const QColor &fgcolor);
void background(qsizetype line, qsizetype start, qsizetype length,
const QColor &bgcolor);
void comment(qsizetype line, qsizetype start, qsizetype length,
const QString &comment);
QList<QHexMetadataAbsoluteItem>
getallMetas(); // added by wingsummer to support workspace
const QList<QHexMetadataAbsoluteItem> &
getallMetasPtr(); // added by wingsummer to support workspace
bool color(qsizetype begin, qsizetype end, const QColor &fgcolor,
const QColor &bgcolor);
bool foreground(qsizetype begin, qsizetype end, const QColor &fgcolor);
bool background(qsizetype begin, qsizetype end, const QColor &bgcolor);
bool comment(qsizetype begin, qsizetype end, const QString &comment);
private:
void setMetadata(const QHexMetadataItem &mi);
void setAbsoluteMetadata(const QHexMetadataAbsoluteItem &mi);
void addMetadata(const QHexMetadataItem &mi);
void addMetaLines(const QHexMetadataItem &mi);
signals:
void metadataChanged();
private:
quint8 m_lineWidth;
QHash<qsizetype, QHexLineMetadata> m_metadata;
QList<QHexMetadataAbsoluteItem> m_absoluteMetadata;
QUndoStack *m_undo; // added by wingsummer
QMap<qsizetype, QHash<QHexMetadataItem, QHexLineMetadata>> m_linemeta;
QVector<QHexMetadataItem> m_metadata;
QUndoStack *m_undo = nullptr; // added by wingsummer
};
#endif // QHEXMETADATA_H

View File

@ -5,7 +5,6 @@
#include <QTextCursor>
#include <QWidget>
#include <cctype>
#include <cmath>
#include <cwctype>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@ -23,21 +22,21 @@ bool QHexRenderer::stringVisible() { return m_asciiVisible; }
void QHexRenderer::setStringVisible(bool b) {
m_asciiVisible = b;
m_document->documentChanged();
emit m_document->documentChanged();
}
bool QHexRenderer::headerVisible() { return m_headerVisible; }
void QHexRenderer::setHeaderVisible(bool b) {
m_headerVisible = b;
m_document->documentChanged();
emit m_document->documentChanged();
}
bool QHexRenderer::addressVisible() { return m_addressVisible; }
void QHexRenderer::setAddressVisible(bool b) {
m_addressVisible = b;
m_document->documentChanged();
emit m_document->documentChanged();
}
QString QHexRenderer::encoding() {
@ -66,7 +65,7 @@ bool QHexRenderer::setEncoding(const QString &encoding) {
if (encoding.compare(QStringLiteral("ISO-8859-1"), Qt::CaseInsensitive) ==
0) {
m_encoding = QStringLiteral("ASCII");
m_document->documentChanged();
emit m_document->documentChanged();
return true;
}
if (QStringConverter::encodingForName(enc.toUtf8())) {
@ -74,7 +73,7 @@ bool QHexRenderer::setEncoding(const QString &encoding) {
if (QTextCodec::codecForName(encoding.toUtf8())) {
#endif
m_encoding = encoding;
m_document->documentChanged();
emit m_document->documentChanged();
return true;
}
return false;
@ -406,7 +405,7 @@ void QHexRenderer::applyMetadata(QTextCursor &textcursor, qsizetype line,
return;
const QHexLineMetadata &linemetadata = metadata->get(line);
for (const QHexMetadataItem &mi : linemetadata) {
for (auto &mi : linemetadata) {
QTextCharFormat charformat;
if (m_document->metabgVisible() && mi.background.isValid() &&
mi.background.rgba())
@ -430,8 +429,31 @@ void QHexRenderer::applySelection(QTextCursor &textcursor, qsizetype line,
if (!m_cursor->isLineSelected(line))
return;
const QHexPosition &startsel = m_cursor->selectionStart();
const QHexPosition &endsel = m_cursor->selectionEnd();
auto total = m_cursor->selectionCount();
for (int i = 0; i < total; ++i) {
applySelection(m_cursor->selection(i), textcursor, line, factor, false,
false);
}
if (m_cursor->hasPreviewSelection()) {
applySelection(
m_cursor->previewSelection().normalized(), textcursor, line, factor,
m_cursor->previewSelectionMode() == QHexCursor::SelectionRemove,
m_cursor->previewSelectionMode() == QHexCursor::SelectionNormal &&
m_cursor->hasInternalSelection());
}
}
void QHexRenderer::applySelection(const QHexSelection &selection,
QTextCursor &textcursor, qsizetype line,
Factor factor, bool strikeOut,
bool hasSelection) const {
if (!selection.isLineSelected(line)) {
return;
}
const QHexPosition &startsel = selection.start;
const QHexPosition &endsel = selection.end;
if (startsel.line == endsel.line) {
textcursor.setPosition(startsel.column * factor);
@ -456,8 +478,13 @@ void QHexRenderer::applySelection(QTextCursor &textcursor, qsizetype line,
textcursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
QTextCharFormat charformat;
charformat.setBackground(m_selBackgroundColor);
charformat.setForeground(m_selectionColor);
charformat.setBackground(strikeOut || hasSelection
? m_selBackgroundColor.darker()
: m_selBackgroundColor);
charformat.setForeground(strikeOut ? m_selectionColor.darker()
: m_selectionColor);
charformat.setFontStrikeOut(strikeOut);
charformat.setFontItalic(strikeOut);
textcursor.mergeCharFormat(charformat);
}
@ -544,7 +571,7 @@ void QHexRenderer::drawHex(QPainter *painter, const QRect &linerect,
textcursor.insertText(this->hexString(line, &rawline));
if (line == this->documentLastLine())
textcursor.insertText(" ");
textcursor.insertText(QStringLiteral(" "));
QRect hexrect = linerect;
hexrect.setX(this->getHexColumnX() + this->borderSize());
@ -577,7 +604,7 @@ void QHexRenderer::applyBookMark(QTextCursor &textcursor, qsizetype line,
if (!m_document->lineHasBookMark(line))
return;
auto pos = m_document->getsBookmarkPos(line);
auto pos = m_document->getLineBookmarksPos(line);
for (auto item : pos) {
textcursor.setPosition(int((item % hexLineWidth()) * factor) + 2);
auto charformat = textcursor.charFormat();

View File

@ -120,8 +120,13 @@ private:
Factor factor) const;
void applyMetadata(QTextCursor &textcursor, qsizetype line,
Factor factor) const;
void applySelection(QTextCursor &textcursor, qsizetype line,
Factor factor) const;
void applySelection(const QHexSelection &selection, QTextCursor &textcursor,
qsizetype line, Factor factor, bool strikeOut,
bool hasSelection) const;
void applyBookMark(QTextCursor &textcursor, qsizetype line,
Factor factor); // added by wingsummer
void applyCursorAscii(QTextCursor &textcursor, qsizetype line) const;

View File

@ -1,7 +1,12 @@
#include "qstoragedevice.h"
#include "qstorageinfo.h"
QStorageDevice::QStorageDevice() : QIODevice() {}
#ifdef Q_OS_WIN
#include <QDebug>
QStorageDevice::QStorageDevice(QObject *parent)
: QIODevice(parent), hDevice(INVALID_HANDLE_VALUE), CHUNK_SIZE(0),
_size(0) {}
void QStorageDevice::setStorage(const QStorageInfo &storage) {
_storage = storage;
@ -9,6 +14,236 @@ void QStorageDevice::setStorage(const QStorageInfo &storage) {
QStorageInfo QStorageDevice::storage() const { return _storage; }
qint64 QStorageDevice::readData(char *data, qint64 maxlen) { return -1; }
DWORD QStorageDevice::cacheSize() const { return 20 * 1024 * CHUNK_SIZE; }
qint64 QStorageDevice::writeData(const char *data, qint64 len) { return -1; }
bool QStorageDevice::isSequential() const { return false; }
bool QStorageDevice::open(OpenMode mode) {
if (hDevice != INVALID_HANDLE_VALUE) {
setErrorString(QStringLiteral("A Storage file is still opened"));
return false;
}
if (mode == OpenModeFlag::ReadOnly || mode == OpenModeFlag::WriteOnly ||
mode == OpenModeFlag::ReadWrite) {
auto device = _storage.device();
auto devicePrefix = QStringLiteral("\\\\.\\");
QString dd = devicePrefix +
device.mid(devicePrefix.length(),
device.length() - devicePrefix.length() - 1);
DWORD flag =
(mode.testFlag(OpenModeFlag::ReadOnly) ? GENERIC_READ : 0) |
(mode.testFlag(OpenModeFlag::WriteOnly) ? GENERIC_WRITE : 0);
// Open the physical drive using WinAPI
hDevice = CreateFileW(
reinterpret_cast<LPCWSTR>(dd.utf16()), flag,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, nullptr);
if (hDevice == INVALID_HANDLE_VALUE) {
qWarning() << "Failed to open device:" << device;
return false;
}
DISK_GEOMETRY diskGeometry;
DWORD bytesReturned;
if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0,
&diskGeometry, sizeof(diskGeometry),
&bytesReturned, nullptr)) {
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
return false;
}
this->CHUNK_SIZE = diskGeometry.BytesPerSector;
_cache.buffer = std::make_unique<char[]>(cacheSize());
_cache.length = 0;
// dont use ioDevice.bytesTotal(),
// because it's use GetDiskFreeSpaceEx API to get.
// QFile::size() is zero
_size = diskGeometry.Cylinders.QuadPart *
diskGeometry.TracksPerCylinder * diskGeometry.SectorsPerTrack *
diskGeometry.BytesPerSector;
return QIODevice::open(mode);
} else {
qWarning() << "Only OpenModeFlag::ReadOnly and OpenModeFlag::WriteOnly "
"are supported";
return false;
}
}
void QStorageDevice::close() {
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
_cache.clear();
}
QIODevice::close();
}
qint64 QStorageDevice::size() const { return _size; }
bool QStorageDevice::seek(qint64 pos) {
if (hDevice == INVALID_HANDLE_VALUE) {
return false;
}
return QIODevice::seek(pos);
}
bool QStorageDevice::canReadLine() const { return false; }
qint64 QStorageDevice::readData(char *data, qint64 maxlen) {
if (hDevice == INVALID_HANDLE_VALUE || !maxlen) {
return -1;
}
if (maxlen > std::numeric_limits<DWORD>::max() ||
(maxlen < 0 && _size > 1024 * 1024 * 1024)) {
qWarning() << "Read a lot mount of data once is not allowed";
return -1;
}
if (maxlen < 0) {
maxlen = _size;
}
auto rp = std::div(this->pos(), CHUNK_SIZE);
auto off = rp.quot * CHUNK_SIZE;
if (_cache.offset < 0 || this->pos() < _cache.offset ||
this->pos() + maxlen >= _cache.offset + _cache.length) {
OVERLAPPED overlapped{0};
LARGE_INTEGER offset;
offset.QuadPart = off;
overlapped.Offset = offset.LowPart;
overlapped.OffsetHigh = offset.HighPart;
if (!ReadFile(hDevice, _cache.buffer.get(), cacheSize(), nullptr,
&overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &_cache.length,
TRUE)) {
return -1;
}
} else {
return -1;
}
}
_cache.offset = off;
}
std::memcpy(data, _cache.buffer.get() + this->pos() - _cache.offset,
maxlen);
return maxlen;
}
qint64 QStorageDevice::writeData(const char *data, qint64 len) {
// qt will check writeable attr
if (!isOpen()) {
return false;
}
// Ensure maxSize is a multiple of the sector size
auto rp = std::div(this->pos(), CHUNK_SIZE);
auto header = CHUNK_SIZE - rp.rem;
auto r = std::div(len - header, CHUNK_SIZE);
auto alignLen = r.quot * CHUNK_SIZE;
OVERLAPPED overlapped{0};
LARGE_INTEGER offset;
DWORD length = 0;
if (rp.rem) {
// read some and write back
offset.QuadPart = rp.quot * CHUNK_SIZE;
auto buffer = std::make_unique<char[]>(CHUNK_SIZE);
if (!ReadFile(hDevice, buffer.get(), CHUNK_SIZE, nullptr,
&overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &length, TRUE)) {
return -1;
}
} else {
return -1;
}
}
std::memcpy(buffer.get(), data, CHUNK_SIZE - rp.rem);
if (!WriteFile(hDevice, buffer.get(), CHUNK_SIZE, nullptr,
&overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &length, TRUE)) {
return -1;
}
} else {
return -1;
}
}
}
offset.QuadPart += CHUNK_SIZE;
overlapped.Offset = offset.LowPart;
overlapped.OffsetHigh = offset.HighPart;
// write aligned
if (!WriteFile(hDevice, data - header, alignLen, nullptr, &overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &length, TRUE)) {
return header;
}
} else {
return header;
}
}
if (r.rem) {
offset.QuadPart += alignLen;
overlapped.Offset = offset.LowPart;
overlapped.OffsetHigh = offset.HighPart;
auto buffer = std::make_unique<char[]>(CHUNK_SIZE);
if (!ReadFile(hDevice, buffer.get(), CHUNK_SIZE, nullptr,
&overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &length, TRUE)) {
return header + alignLen;
}
} else {
return header + alignLen;
}
}
std::memcpy(buffer.get(), data + len - r.rem, r.rem);
if (!WriteFile(hDevice, buffer.get(), CHUNK_SIZE, nullptr,
&overlapped)) {
auto lastError = GetLastError();
if (lastError == ERROR_IO_PENDING) {
if (!GetOverlappedResult(hDevice, &overlapped, &length, TRUE)) {
return header + alignLen;
}
} else {
return header + alignLen;
}
}
}
return len;
}
#endif

View File

@ -1,25 +1,60 @@
#ifndef QSTORAGEDEVICE_H
#define QSTORAGEDEVICE_H
#include <QtGlobal>
#ifdef Q_OS_WIN
#include <QIODevice>
#include <QStorageInfo>
#include <memory>
#include <Windows.h>
class QStorageDevice : public QIODevice {
Q_OBJECT
public:
QStorageDevice();
QStorageDevice(QObject *parent = nullptr);
void setStorage(const QStorageInfo &storage);
QStorageInfo storage() const;
private:
struct Buffer {
qint64 offset = -1;
// length is usually 20 * 1024 * CHUNK_SIZE = 10 MB
std::unique_ptr<char[]> buffer;
DWORD length = 0;
void clear() {
offset = -1;
length = 0;
}
} _cache;
DWORD cacheSize() const;
private:
QStorageInfo _storage;
HANDLE hDevice;
DWORD CHUNK_SIZE;
qint64 _size;
// QIODevice interface
public:
virtual bool isSequential() const override;
virtual bool open(OpenMode mode) override;
virtual void close() override;
virtual qint64 size() const override;
virtual bool seek(qint64 pos) override;
virtual bool canReadLine() const override;
protected:
virtual qint64 readData(char *data, qint64 maxlen) override;
virtual qint64 writeData(const char *data, qint64 len) override;
};
#endif
#endif // QSTORAGEDEVICE_H

View File

@ -44,7 +44,13 @@ qsizetype QHexView::currentRow() { return m_cursor->currentLine(); }
qsizetype QHexView::currentColumn() { return m_cursor->currentColumn(); }
qsizetype QHexView::currentOffset() { return m_cursor->position().offset(); }
qsizetype QHexView::selectlength() { return m_cursor->selectionLength(); }
qsizetype QHexView::currentSelectionLength() {
return m_cursor->currentSelectionLength();
}
qsizetype QHexView::selectionCount() { return m_cursor->selectionCount(); }
bool QHexView::hasSelection() { return m_cursor->hasSelection(); }
bool QHexView::asciiVisible() { return m_renderer->stringVisible(); }
@ -100,13 +106,15 @@ void QHexView::getStatus() {
}
void QHexView::establishSignal(QHexDocument *doc) {
connect(doc, &QHexDocument::documentChanged, this, [&]() {
connect(doc, &QHexDocument::documentChanged, this, [this]() {
this->adjustScrollBars();
this->viewport()->update();
});
connect(m_cursor, &QHexCursor::positionChanged, this,
&QHexView::moveToSelection);
connect(m_cursor, &QHexCursor::selectionChanged, this,
[this]() { this->viewport()->update(); });
connect(m_cursor, &QHexCursor::insertionModeChanged, this,
&QHexView::renderCurrentLine);
connect(doc, &QHexDocument::canUndoChanged, this,
@ -115,16 +123,16 @@ void QHexView::establishSignal(QHexDocument *doc) {
&QHexView::canRedoChanged);
connect(doc, &QHexDocument::documentSaved, this, &QHexView::documentSaved);
connect(doc, &QHexDocument::metabgVisibleChanged, this, [=](bool b) {
QHexView::metabgVisibleChanged(b);
emit this->metaStatusChanged();
emit metabgVisibleChanged(b);
emit metaStatusChanged();
});
connect(doc, &QHexDocument::metafgVisibleChanged, this, [=](bool b) {
QHexView::metafgVisibleChanged(b);
emit this->metaStatusChanged();
emit metafgVisibleChanged(b);
emit metaStatusChanged();
});
connect(doc, &QHexDocument::metaCommentVisibleChanged, this, [=](bool b) {
QHexView::metaCommentVisibleChanged(b);
emit this->metaStatusChanged();
emit metaCommentVisibleChanged(b);
emit metaStatusChanged();
});
connect(doc, &QHexDocument::metaDataChanged, this,
[=] { this->viewport()->update(); });
@ -283,43 +291,27 @@ qsizetype QHexView::searchBackward(qsizetype begin, const QByteArray &ba) {
qsizetype startPos;
if (begin < 0) {
startPos = m_cursor->position().offset() - 1;
if (m_cursor->hasSelection()) {
startPos = m_cursor->selectionStart().offset() - 1;
}
} else {
startPos = begin;
}
return m_document->searchBackward(startPos, ba);
}
void QHexView::gotoBookMark(qsizetype index) {
if (index >= 0 && index < m_document->bookMarksCount()) {
auto bookmark = m_document->bookMarkByIndex(index);
m_cursor->moveTo(bookmark.pos);
}
}
bool QHexView::existBookMarkByIndex(qsizetype &index) {
auto curpos = m_cursor->position().offset();
int i = 0;
for (auto &item : m_document->getAllBookMarks()) {
if (item.pos == curpos) {
index = i;
return true;
}
i++;
}
return false;
}
bool QHexView::RemoveSelection(int nibbleindex) {
if (!m_cursor->hasSelection())
return false;
auto res = m_document->Remove(m_cursor, m_cursor->selectionStart().offset(),
m_cursor->selectionLength(), nibbleindex);
if (res)
m_cursor->clearSelection();
auto total = m_cursor->selectionCount();
bool res = true;
m_document->beginMarco(QStringLiteral(""));
for (int i = 0; i < total; ++i) {
res &=
m_document->Remove(m_cursor, m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i), nibbleindex);
}
m_document->endMarco();
m_cursor->clearSelection();
return res;
}
@ -327,10 +319,16 @@ bool QHexView::removeSelection() {
if (!m_cursor->hasSelection())
return false;
auto res = m_document->remove(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
if (res)
m_cursor->clearSelection();
// We essure selections are ordered by desending
// by selection-start, so it's safe to remove
auto total = m_cursor->selectionCount();
bool res = true;
for (int i = 0; i < total; ++i) {
res &= m_document->remove(m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i));
}
m_cursor->clearSelection();
return res;
}
@ -338,16 +336,27 @@ bool QHexView::atEnd() const {
return m_cursor->position().offset() >= m_document->length();
}
void QHexView::gotoMetaData(qsizetype index) {
m_cursor->moveTo(m_document->metadata()->getallMetasPtr().at(index).begin);
QByteArray QHexView::selectedBytes(qsizetype index) const {
return m_document->read(m_cursor->selectionStart(index).offset(),
m_cursor->currentSelectionLength());
}
QByteArray QHexView::selectedBytes() const {
if (!m_cursor->hasSelection())
return QByteArray();
QByteArray QHexView::previewSelectedBytes() const {
auto sel = m_cursor->previewSelection().normalized();
return m_document->read(sel.start.offset(), sel.length());
}
return m_document->read(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
QByteArrayList QHexView::selectedBytes() const {
if (!m_cursor->hasSelection())
return {};
QByteArrayList res;
auto total = m_cursor->selectionCount();
for (int i = 0; i < total; ++i) {
res << m_document->read(m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i));
}
return res;
}
void QHexView::paste(bool hex) {
@ -436,7 +445,7 @@ bool QHexView::copy(bool hex) {
QClipboard *c = qApp->clipboard();
auto len = m_cursor->selectionLength();
auto len = currentSelectionLength();
// 如果拷贝字节超过 ? MB 阻止
if (len > 1024 * 1024 * m_copylimit) {
@ -444,7 +453,7 @@ bool QHexView::copy(bool hex) {
return false;
}
QByteArray bytes = this->selectedBytes();
QByteArray bytes = this->selectedBytes().join();
if (hex)
bytes = bytes.toHex(' ').toUpper();
@ -545,8 +554,18 @@ void QHexView::mousePressEvent(QMouseEvent *e) {
m_renderer->selectArea(abspos);
if (m_renderer->editableArea(m_renderer->selectedArea()))
m_cursor->moveTo(position);
if (m_renderer->editableArea(m_renderer->selectedArea())) {
auto m = getSelectionMode();
bool clearSelection = false;
if (m == QHexCursor::SelectionNormal) {
clearSelection = m_cursor->selectionCount() <= 1 ||
e->modifiers().testFlag(Qt::ControlModifier);
} else if (m == QHexCursor::SelectionSingle) {
clearSelection = true;
}
m_cursor->moveTo(position, clearSelection);
}
e->accept();
}
@ -570,7 +589,9 @@ void QHexView::mouseMoveEvent(QMouseEvent *e) {
if (!m_renderer->hitTest(abspos, &position, this->firstVisibleLine()))
return;
cursor->select(position.line, position.column, 0);
cursor->select(position.line, position.column, 0,
QHexCursor::SelectionModes(
getSelectionMode() | QHexCursor::SelectionPreview));
e->accept();
}
@ -591,6 +612,13 @@ void QHexView::mouseReleaseEvent(QMouseEvent *e) {
return;
if (!m_blinktimer->isActive())
m_blinktimer->start();
if (m_cursor->hasPreviewSelection()) {
auto sel = m_cursor->previewSelection();
m_cursor->mergePreviewSelection();
m_cursor->moveTo(sel.end);
}
e->accept();
}
@ -730,7 +758,7 @@ void QHexView::moveNext(bool select) {
if (select)
cur->select(line, std::min(m_renderer->hexLineWidth() - 1, int(column)),
nibbleindex);
nibbleindex, QHexCursor::SelectionAdd);
else
cur->moveTo(line, std::min(m_renderer->hexLineWidth() - 1, int(column)),
nibbleindex);
@ -773,6 +801,34 @@ void QHexView::movePrevious(bool select) {
cur->moveTo(line, std::max(0, column), nibbleindex);
}
QHexCursor::SelectionMode QHexView::getSelectionMode() const {
auto mods = qApp->keyboardModifiers();
bool pressedShift = mods.testFlag(Qt::ShiftModifier);
bool pressedAlt = mods.testFlag(Qt::AltModifier);
bool pressedControl = mods.testFlag(Qt::ControlModifier);
if (pressedAlt && pressedShift) {
pressedShift = false;
pressedAlt = false;
pressedControl = true;
}
if (pressedControl) {
return QHexCursor::SelectionSingle;
}
if (pressedShift) {
return QHexCursor::SelectionAdd;
}
if (pressedAlt) {
return QHexCursor::SelectionRemove;
}
return QHexCursor::SelectionNormal;
}
void QHexView::renderCurrentLine() {
if (m_document)
this->renderLine(m_cursor->currentLine());
@ -821,12 +877,15 @@ bool QHexView::processAction(QHexCursor *cur, QKeyEvent *e) {
// modified by wingsummer
if (isKeepSize()) {
if (e->key() == Qt::Key_Backspace)
m_document->Replace(m_cursor, cur->position().offset() - 1,
uchar(0), 0);
else
m_document->Replace(m_cursor, cur->position().offset(),
uchar(0), 0);
if (cur->insertionMode() == QHexCursor::OverwriteMode) {
if (e->key() == Qt::Key_Backspace)
m_document->Replace(m_cursor,
cur->position().offset() - 1,
uchar(0), 0);
else
m_document->Replace(m_cursor, cur->position().offset(),
uchar(0), 0);
}
} else {
if (e->key() == Qt::Key_Backspace)
m_document->Remove(m_cursor, cur->position().offset() - 1,
@ -917,7 +976,7 @@ bool QHexView::processMove(QHexCursor *cur, QKeyEvent *e) {
if (e->matches(QKeySequence::MoveToEndOfDocument))
cur->moveTo(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
int(m_renderer->documentLastColumn()));
else
cur->select(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
@ -932,7 +991,7 @@ bool QHexView::processMove(QHexCursor *cur, QKeyEvent *e) {
if (e->matches(QKeySequence::MoveToEndOfLine)) {
if (cur->currentLine() == m_renderer->documentLastLine())
cur->moveTo(cur->currentLine(),
m_renderer->documentLastColumn());
int(m_renderer->documentLastColumn()));
else
cur->moveTo(cur->currentLine(), m_renderer->hexLineWidth() - 1,
0);
@ -954,11 +1013,12 @@ bool QHexView::processTextInput(QHexCursor *cur, QKeyEvent *e) {
if (isReadOnly() || isLocked() || (e->modifiers() & Qt::ControlModifier))
return false;
if (e->text().isEmpty()) {
auto text = e->text();
if (text.isEmpty()) {
return false;
}
uchar key = static_cast<uchar>(e->text()[0].toLatin1());
uchar key = static_cast<uchar>(text[0].toLatin1());
if ((m_renderer->selectedArea() == QHexRenderer::HexArea)) {
if (!((key >= '0' && key <= '9') ||

View File

@ -51,7 +51,10 @@ public:
qsizetype currentRow();
qsizetype currentColumn();
qsizetype currentOffset();
qsizetype selectlength();
qsizetype currentSelectionLength();
qsizetype selectionCount();
bool hasSelection();
void setAsciiVisible(bool b);
bool asciiVisible();
@ -97,15 +100,13 @@ public:
qsizetype searchForward(qsizetype begin, const QByteArray &ba);
qsizetype searchBackward(qsizetype begin, const QByteArray &ba);
void gotoBookMark(qsizetype index);
bool existBookMarkByIndex(qsizetype &index);
bool RemoveSelection(int nibbleindex = 1);
bool removeSelection();
bool atEnd() const;
void gotoMetaData(qsizetype index);
QByteArray selectedBytes() const;
QByteArray selectedBytes(qsizetype index) const;
QByteArray previewSelectedBytes() const;
QByteArrayList selectedBytes() const;
bool cut(bool hex);
bool copy(bool hex = false);
@ -172,6 +173,8 @@ private:
void moveNext(bool select = false);
void movePrevious(bool select = false);
QHexCursor::SelectionMode getSelectionMode() const;
private:
bool processMove(QHexCursor *cur, QKeyEvent *e);
bool processTextInput(QHexCursor *cur, QKeyEvent *e);

View File

@ -60,6 +60,12 @@ RibbonTabContent *Ribbon::addTab(const QString &tabName) {
return ribbonTabContent;
}
void Ribbon::addTab(RibbonTabContent *tabContent, const QString &tabName) {
if (tabContent) {
QTabWidget::addTab(tabContent, tabName);
}
}
RibbonTabContent *Ribbon::addTab(const QIcon &tabIcon, const QString &tabName) {
// Note: superclass QTabWidget also has a function addTab()
RibbonTabContent *ribbonTabContent = new RibbonTabContent;

View File

@ -29,6 +29,11 @@ public:
/// \param[in] tabName Name of the tab
RibbonTabContent *addTab(const QString &tabName);
/// Add a tab to the ribbon.
///
/// \param[in] tabContent pointer of the tab
void addTab(RibbonTabContent *tabContent, const QString &tabName);
/// Add a tab to the ribbon.
///
/// \param[in] tabIcon Icon of the tab

1
3rdparty/json vendored Submodule

@ -0,0 +1 @@
Subproject commit a006a7a48bb30a247f0344b788c62c2806edd90b

View File

@ -40,9 +40,7 @@ set(WIDGETS_SRC
lib/widgets/qlinenumberpanel.cpp
lib/widgets/qlinenumberpanel.h
lib/widgets/qpanel.cpp
lib/widgets/qpanel.h
lib/widgets/qsimplecolorpicker.cpp
lib/widgets/qsimplecolorpicker.h)
lib/widgets/qpanel.h)
set(QNFA_SRC
lib/qnfa/light_vector.h lib/qnfa/qnfadefinition.h lib/qnfa/qnfa.h
@ -54,12 +52,9 @@ set(SNIPPET_SRC
lib/snippets/qsnippet_p.h
lib/snippets/qsnippetbinding.cpp
lib/snippets/qsnippetbinding.h
lib/snippets/qsnippetedit.cpp
lib/snippets/qsnippetedit.h
lib/snippets/qsnippetmanager.cpp
lib/snippets/qsnippetmanager.h
lib/snippets/qsnippetpatternloader.h
lib/snippets/snippetedit.ui)
lib/snippets/qsnippetpatternloader.h)
set(SOURCE_FILES
lib/qce-config.h

File diff suppressed because it is too large Load Diff

View File

@ -186,24 +186,23 @@ public:
QFormatScheme *formatScheme() const;
void setFormatScheme(QFormatScheme *f);
int lineSpacing() const;
int getNextGroupId();
void releaseGroupId(int groupId);
void clearMatches(int groupId);
void flushMatches(int groupId);
void addMatch(int groupId, int line, int pos, int len, int format);
static QFont font();
static void setFont(const QFont &f);
static const QFontMetrics &fontMetrics();
QFont font();
void setFont(const QFont &f);
const QFontMetrics &fontMetrics();
static LineEnding defaultLineEnding();
static void setDefaultLineEnding(LineEnding le);
int tabStop();
void setTabStop(int n);
static int tabStop();
static void setTabStop(int n);
static WhiteSpaceMode showSpaces();
static void setShowSpaces(WhiteSpaceMode y);
WhiteSpaceMode showSpaces();
void setShowSpaces(WhiteSpaceMode y);
static QFormatScheme *defaultFormatScheme();
static void setDefaultFormatScheme(QFormatScheme *f);
@ -214,7 +213,7 @@ public:
static int screenLength(const QChar *d, int l, int tabStop);
static QString screenable(const QChar *d, int l, int tabStop);
inline void markViewDirty() { formatsChanged(); }
inline void markViewDirty() { emit formatsChanged(); }
bool isClean() const;
@ -257,6 +256,8 @@ signals:
void lineEndingChanged(int lineEnding);
void fontChanged(const QFont &font);
private:
QString m_leftOver;
QDocumentPrivate *m_impl;

View File

@ -54,6 +54,7 @@ Q_DECLARE_TYPEINFO(QDocumentSelection, Q_PRIMITIVE_TYPE);
class QCE_EXPORT QDocumentPrivate {
friend class QEditConfig;
friend class QEditor;
friend class QDocument;
friend class QDocumentCommand;
friend class QDocumentLineHandle;
@ -67,7 +68,7 @@ public:
void draw(QPainter *p, QDocument::PaintContext &cxt);
QDocumentLineHandle *lineForPosition(int &position) const;
QDocumentLineHandle *lineForPosition(int position) const;
int position(const QDocumentLineHandle *l) const;
QDocumentLineHandle *at(int line) const;
@ -86,7 +87,7 @@ public:
void setWidth();
void setHeight();
static void setFont(const QFont &f);
void setFont(const QFont &f);
void beginChangeBlock();
void endChangeBlock();
@ -120,7 +121,6 @@ public:
void setWidth(int width);
void emitFormatsChanged();
void emitContentsChanged();
void emitLineDeleted(QDocumentLineHandle *h);
@ -165,7 +165,7 @@ private:
struct Match {
int line;
QFormatRange range;
QDocumentLineHandle *h;
QDocumentLineHandle *h = nullptr;
};
struct MatchList : QList<Match> {
@ -182,21 +182,24 @@ private:
int m_width, m_height;
int m_tabStop;
static int m_defaultTabStop;
static QFont *m_font;
static bool m_fixedPitch;
static QFontMetrics *m_fontMetrics;
static int m_leftMargin;
static QDocument::WhiteSpaceMode m_showSpaces;
QFont m_font;
bool m_fixedPitch;
QFontMetrics m_fontMetrics;
int m_leftMargin;
QDocument::WhiteSpaceMode m_showSpaces;
int m_lineHeight;
int m_lineSpacing;
int m_spaceWidth;
int m_ascent;
int m_descent;
int m_leading;
int m_wrapMargin;
static QFont m_defaultFont;
static int m_defaultTabStop;
static QDocument::LineEnding m_defaultLineEnding;
static int m_lineHeight;
static int m_lineSpacing;
static int m_spaceWidth;
static int m_ascent;
static int m_descent;
static int m_leading;
static int m_wrapMargin;
static QDocument::WhiteSpaceMode m_defaultShowSpaces;
QFormatScheme *m_formatScheme;
QLanguageDefinition *m_language;

View File

@ -21,6 +21,7 @@
*/
#include "qdocument_p.h"
#include "qformatscheme.h"
/*!
\ingroup document
@ -142,7 +143,8 @@ void QDocumentCommand::setUndoOffset(int off) { m_undoOffset = off; }
This helper method is provided so that subclasses may actually
modify the document contents without using private API.
*/
void QDocumentCommand::insertText(int line, int pos, const QString &s) {
void QDocumentCommand::insertText(int line, int pos, const QString &s,
const QString &sfmtID) {
if (!m_doc)
return;
@ -155,6 +157,21 @@ void QDocumentCommand::insertText(int line, int pos, const QString &s) {
h->textBuffer().insert(pos, s);
h->shiftOverlays(pos, s.length());
if (!sfmtID.isEmpty()) {
auto fmt = m_doc->formatScheme();
if (fmt) {
auto id = fmt->id(sfmtID);
if (id) {
QFormatRange over;
over.format = id;
over.offset = pos;
over.length = s.length();
h->addOverlay(over);
}
}
}
pd->adjustWidth(line);
}
@ -484,8 +501,9 @@ void QDocumentCommand::markUndone(QDocumentLineHandle *h) {
QDocumentInsertCommand::QDocumentInsertCommand(int l, int offset,
const QString &text,
QDocument *doc,
const QString &sfmtID,
QDocumentCommand *p)
: QDocumentCommand(Insert, doc, p) {
: QDocumentCommand(Insert, doc, p), m_sfmtID(sfmtID) {
QStringList lines = text.split(QLatin1Char('\n'), Qt::KeepEmptyParts);
if (!m_doc || text.isEmpty())
@ -497,8 +515,19 @@ QDocumentInsertCommand::QDocumentInsertCommand(int l, int offset,
m_data.begin = lines.takeAt(0);
m_data.endOffset = lines.count() ? lines.last().length() : -1;
foreach (const QString &s, lines)
m_data.handles << new QDocumentLineHandle(s, m_doc);
for (auto &s : lines) {
auto lh = new QDocumentLineHandle(s, m_doc);
QFormatRange over;
auto fmt = m_doc->formatScheme();
auto id = fmt->id(sfmtID);
if (id) {
over.format = id;
over.offset = 0;
over.length = s.length();
lh->addOverlay(over);
}
m_data.handles << lh;
}
QDocumentLine bl = m_doc->line(l);
@ -541,7 +570,7 @@ void QDocumentInsertCommand::redo() {
removeText(m_data.lineNumber, m_data.startOffset, m_data.end.length());
}
insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
insertText(m_data.lineNumber, m_data.startOffset, m_data.begin, m_sfmtID);
insertLines(m_data.lineNumber, m_data.handles);

View File

@ -41,7 +41,7 @@ public:
QList<QDocumentLineHandle *> handles;
};
QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p = 0);
QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p = nullptr);
virtual ~QDocumentCommand();
virtual int id() const;
@ -77,7 +77,8 @@ protected:
void updateTarget(int l, int offset);
void insertText(int line, int pos, const QString &s);
void insertText(int line, int pos, const QString &s,
const QString &sfmtID = {});
void removeText(int line, int pos, int length);
void insertLines(int after, const QList<QDocumentLineHandle *> &l);
@ -102,7 +103,8 @@ Q_DECLARE_TYPEINFO(QDocumentCommand::TextCommandData, Q_MOVABLE_TYPE);
class QCE_EXPORT QDocumentInsertCommand : public QDocumentCommand {
public:
QDocumentInsertCommand(int l, int offset, const QString &text,
QDocument *doc, QDocumentCommand *p = 0);
QDocument *doc, const QString &sfmtID = 0,
QDocumentCommand *p = nullptr);
virtual ~QDocumentInsertCommand();
@ -113,12 +115,13 @@ public:
private:
TextCommandData m_data;
QString m_sfmtID;
};
class QCE_EXPORT QDocumentEraseCommand : public QDocumentCommand {
public:
QDocumentEraseCommand(int bl, int bo, int el, int eo, QDocument *doc,
QDocumentCommand *p = 0);
QDocumentCommand *p = nullptr);
virtual ~QDocumentEraseCommand();

View File

@ -418,16 +418,6 @@ void QDocumentCursor::shift(int offset) {
m_handle->shift(offset);
}
/*!
\brief Set the text position of the cursor (within the whole document)
Remark made about position() applies.
*/
void QDocumentCursor::setPosition(int pos, MoveMode m) {
if (m_handle)
m_handle->setPosition(pos, m);
}
/*!
\brief Moves the cursor position
\param offset number of times the selected move will be done
@ -515,7 +505,7 @@ void QDocumentCursor::eraseLine() {
*/
void QDocumentCursor::insertLine(bool keepAnchor) {
if (m_handle)
m_handle->insertText("\n", keepAnchor);
m_handle->insertText(QStringLiteral("\n"), keepAnchor);
}
/*!
@ -525,9 +515,10 @@ void QDocumentCursor::insertLine(bool keepAnchor) {
\note Nothing happens if \a s is empty
*/
void QDocumentCursor::insertText(const QString &s, bool keepAnchor) {
void QDocumentCursor::insertText(const QString &s, bool keepAnchor,
const QString &sfmtID) {
if (m_handle)
m_handle->insertText(s, keepAnchor);
m_handle->insertText(s, keepAnchor, sfmtID);
}
/*!

View File

@ -18,6 +18,8 @@
#include "qce-config.h"
#include <QMetaType>
/*!
\file qdocumentcursor.h
\brief Definition of the QDocumentCursor class
@ -132,7 +134,6 @@ public:
QDocumentLine anchorLine() const;
void shift(int offset);
void setPosition(int pos, MoveMode m = MoveAnchor);
bool movePosition(int offset, MoveOperation op = NextCharacter,
MoveMode m = MoveAnchor);
@ -142,7 +143,8 @@ public:
void eraseLine();
void insertLine(bool keepAnchor = false);
void insertText(const QString &s, bool keepAnchor = false);
void insertText(const QString &s, bool keepAnchor = false,
const QString &sfmtID = {});
QDocumentCursor selectionStart() const;
QDocumentCursor selectionEnd() const;
@ -181,4 +183,6 @@ private:
QDocumentCursorHandle *m_handle;
};
Q_DECLARE_METATYPE(QDocumentCursor);
#endif

View File

@ -90,10 +90,11 @@ public:
int position() const;
void shift(int offset);
void setPosition(int pos, int m);
bool movePosition(int offset, int op, int m);
bool movePosition(int offset, QDocumentCursor::MoveOperation op,
QDocumentCursor::MoveMode m);
void insertText(const QString &s, bool keepAnchor = false);
void insertText(const QString &s, bool keepAnchor = false,
const QString &sfmtID = {});
QChar nextChar() const;
QChar previousChar() const;

View File

@ -59,11 +59,11 @@ void addDataPath(const QString &path);
template <typename Registerable>
class Registar {
public:
Registar() { Registerable::_register(); }
constexpr Registar() { Registerable::_register(); }
};
// added by wingsummer
[[maybe_unused]] static QStringList getEncodings() {
Q_DECL_UNUSED static QStringList getEncodings() {
static QStringList encodings;
if (encodings.isEmpty()) {
@ -91,8 +91,8 @@ public:
return encodings;
}
[[maybe_unused]] static QString convertString(const QString &encoding,
const QByteArray &data) {
Q_DECL_UNUSED static QString convertString(const QString &encoding,
const QByteArray &data) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto enc = QStringConverter::encodingForName(encoding.toUtf8());
if (enc) {
@ -113,8 +113,8 @@ public:
#endif
}
[[maybe_unused]] static QByteArray convertByteArray(const QString &encoding,
const QString &data) {
Q_DECL_UNUSED static QByteArray convertByteArray(const QString &encoding,
const QString &data) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto enc = QStringConverter::encodingForName(encoding.toUtf8());
if (enc) {

View File

@ -26,15 +26,11 @@
#include <QKeyEvent>
#include <QTextCursor>
#ifdef _QCODE_MODEL_
#include "qcodebuffer.h"
#endif
/*!
*/
QCodeCompletionEngine::QCodeCompletionEngine(QObject *p)
: QObject(p), m_max(0) {
: QObject(p), m_max(0), m_trigWordLen(-1) {
pForcedTrigger = new QAction(tr("&Trigger completion"), this);
connect(pForcedTrigger, SIGNAL(triggered()), this, SLOT(complete()));
@ -84,11 +80,6 @@ void QCodeCompletionEngine::removeTrigger(const QString &s) {
/*!
*/
void QCodeCompletionEngine::setCodeModel(QCodeModel *m) { Q_UNUSED(m) }
/*!
*/
QEditor *QCodeCompletionEngine::editor() const { return pEdit; }
@ -97,7 +88,7 @@ QEditor *QCodeCompletionEngine::editor() const { return pEdit; }
*/
void QCodeCompletionEngine::setEditor(QEditor *e) {
if (pEdit) {
pEdit->removeAction(pForcedTrigger, "&Edit");
pEdit->removeAction(pForcedTrigger, tr("&Edit"));
// pEdit->removeEventFilter(this);
disconnect(pEdit, SIGNAL(textEdited(QKeyEvent *)), this,
@ -108,10 +99,9 @@ void QCodeCompletionEngine::setEditor(QEditor *e) {
if (pEdit) {
// pEdit->installEventFilter(this);
pEdit->addAction(pForcedTrigger, "&Edit");
connect(pEdit, SIGNAL(textEdited(QKeyEvent *)), this,
SLOT(textEdited(QKeyEvent *)));
pEdit->addAction(pForcedTrigger, tr("&Edit"));
connect(pEdit, &QEditor::textEdited, this,
&QCodeCompletionEngine::textEdited);
}
}
@ -150,8 +140,14 @@ void QCodeCompletionEngine::textEdited(QKeyEvent *k) {
auto count = txt.length();
if (txt.isEmpty() || m_triggers.isEmpty())
if (txt.isEmpty()) {
return;
}
if (m_triggers.isEmpty()) {
triggerWordLenComplete();
return;
}
// qDebug("should trigger completion? (bis)");
@ -170,7 +166,6 @@ void QCodeCompletionEngine::textEdited(QKeyEvent *k) {
}
// qDebug("text : %s", qPrintable(txt));
for (auto &trig : m_triggers) {
if (txt.endsWith(trig)) {
cur = editor()->cursor();
@ -184,8 +179,11 @@ void QCodeCompletionEngine::textEdited(QKeyEvent *k) {
// trigger completion
complete(cur, trig);
return;
}
}
triggerWordLenComplete();
}
/*!
@ -253,38 +251,23 @@ bool QCodeCompletionEngine::eventFilter(QObject *o, QEvent *e) {
*/
void QCodeCompletionEngine::complete(const QDocumentCursor &c,
const QString &trigger) {
#ifdef _QCODE_MODEL_
// TODO :
// * use a more efficient design by avoiding deep copy of the data
// * only lex the requested part (stop at cursor or topmost frame required
// for proper class hierarchy)
QDocumentCursor cc = c;
cc.movePosition(1, QDocumentCursor::Start, QDocumentCursor::KeepAnchor);
// qDebug("%s", qPrintable(cc.selectedText()));
QCodeBuffer buffer(cc.selectedText());
// QCodeBuffer buffer(c.document()->text());
complete(&buffer, trigger);
#else
Q_UNUSED(c)
Q_UNUSED(trigger)
qWarning("From complete(QDocumentCursor, QString)");
qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should "
"reimplement at least on of the complete() method...");
#endif
"reimplement at least one of the complete() method...");
}
/*!
\overload
\brief Overloaded completion callback
*/
void QCodeCompletionEngine::complete(QCodeStream *s, const QString &trigger) {
Q_UNUSED(s)
Q_UNUSED(trigger)
qWarning("From complete(QCodeStream*, QString)");
qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should"
"reimplement at least on of the complete() method...");
void QCodeCompletionEngine::triggerWordLenComplete() {
if (m_trigWordLen > 0) {
QDocumentCursor cur = editor()->cursor();
emit completionTriggered({});
complete(cur, {});
}
}
qsizetype QCodeCompletionEngine::trigWordLen() const { return m_trigWordLen; }
void QCodeCompletionEngine::setTrigWordLen(qsizetype newTrigWordLen) {
m_trigWordLen = newTrigWordLen;
}

View File

@ -50,17 +50,18 @@ public:
QAction *triggerAction() const;
QEditor *editor() const;
void setEditor(QEditor *e);
virtual void setEditor(QEditor *e);
QStringList triggers() const;
void addTrigger(const QString &s);
void removeTrigger(const QString &s);
virtual void setCodeModel(QCodeModel *m);
virtual void retranslate();
qsizetype trigWordLen() const;
void setTrigWordLen(qsizetype newTrigWordLen);
signals:
void popup();
void cloned(QCodeCompletionEngine *e);
@ -74,11 +75,15 @@ protected:
virtual void run();
virtual bool eventFilter(QObject *o, QEvent *e);
virtual void complete(QCodeStream *s, const QString &trigger);
virtual void complete(const QDocumentCursor &c, const QString &trigger);
private:
void triggerWordLenComplete();
private:
qsizetype m_max;
qsizetype m_trigWordLen;
QString m_trig;
QDocumentCursor m_cur;
QAction *pForcedTrigger;

View File

@ -222,7 +222,7 @@ QPanelLayout *QCodeEdit::panelLayout() const { return m_layout; }
QAction *QCodeEdit::addPanel(QPanel *panel, Position pos, bool _add) {
panel->attach(m_editor);
QAction *a = new QAction(panel->type(), m_editor);
QAction *a = new QAction(panel->name(), m_editor);
a->setCheckable(true);
a->setChecked(panel->defaultVisibility());

File diff suppressed because it is too large Load Diff

View File

@ -33,10 +33,6 @@
#include "qdocument.h"
#include "qdocumentcursor.h"
#ifdef _QMDI_
#include "qmdiclient.h"
#endif
class QMenu;
class QAction;
class QMimeData;
@ -51,12 +47,7 @@ class QCodeCompletionEngine;
class QEditorInputBindingInterface;
class QCE_EXPORT QEditor : public QAbstractScrollArea
#ifdef _QMDI_
,
public qmdiClient
#endif
{
class QCE_EXPORT QEditor : public QAbstractScrollArea {
friend class QEditConfig;
friend class QEditorFactory;
@ -129,10 +120,8 @@ public:
QList<QDocumentCursor> mirrors;
};
QEditor(QWidget *p = nullptr);
QEditor(bool actions, QWidget *p = nullptr);
QEditor(const QString &s, QWidget *p = nullptr);
QEditor(const QString &s, bool actions, QWidget *p = nullptr);
explicit QEditor(QWidget *p = nullptr);
explicit QEditor(bool actions, QWidget *p = nullptr);
virtual ~QEditor();
bool flag(EditFlag) const;
@ -165,12 +154,10 @@ public:
virtual QRect lineRect(const QDocumentLine &l) const;
virtual QRect cursorRect(const QDocumentCursor &c) const;
#ifndef _QMDI_
QString name() const;
QString fileName() const;
bool isContentModified() const;
#endif
bool isInConflict() const;
@ -198,11 +185,25 @@ public:
point.y() - verticalOffset());
}
void createSimpleBasicContextMenu(bool shortcut, bool extTool);
virtual bool protectedCursor(const QDocumentCursor &c) const;
static int defaultFlags();
static void setDefaultFlags(int f);
static QFont defaultFont();
static void setDefaultFont(const QFont &font);
static int defaultTabStop();
static void setDefaultTabStop(int tabstop);
static QDocument::LineEnding defaultLineEnding();
static void setDefaultLineEnding(QDocument::LineEnding le);
static QDocument::WhiteSpaceMode defaultShowSpaces();
static void setDefaultShowSpaces(QDocument::WhiteSpaceMode y);
static QString defaultCodecName();
static void setDefaultCodec(const QString &name, int update);
@ -221,9 +222,11 @@ public slots:
void undo();
void redo();
void cut();
void copy();
void paste();
virtual void cut();
virtual void copy();
virtual void paste();
void clear();
void selectAll();
@ -248,7 +251,7 @@ public slots:
virtual void retranslate();
virtual void write(const QString &s);
virtual void write(const QString &s, const QString &sfmtID = {});
void addAction(QAction *a, const QString &menu,
const QString &toolbar = QString());
@ -274,8 +277,6 @@ public slots:
void setScaleRate(qreal rate);
qreal scaleRate() const;
void setPanelMargins(int l, int t, int r, int b);
void getPanelMargins(int *l, int *t, int *r, int *b) const;
@ -285,19 +286,26 @@ public slots:
void clearPlaceHolders();
void removePlaceHolder(int i);
void addPlaceHolder(const PlaceHolder &p, bool autoUpdate = true);
int placeHolderCount() const;
int currentPlaceHolder() const;
void addPlaceHolder(const QEditor::PlaceHolder &p, bool autoUpdate = true);
void nextPlaceHolder();
void previousPlaceHolder();
void setPlaceHolder(int i);
void setUndoRedoEnabled(bool b);
void setCursorMirrorEnabled(bool b);
virtual void setFileName(const QString &f);
public:
int placeHolderCount() const;
int currentPlaceHolder() const;
qreal scaleRate() const;
signals:
void loaded(QEditor *e, const QString &s);
void needLoading();
void saved(QEditor *e, const QString &s);
void contentModified(bool y);
@ -356,8 +364,6 @@ protected:
virtual void contextMenuEvent(QContextMenuEvent *e);
virtual void closeEvent(QCloseEvent *e);
virtual bool focusNextPrevChild(bool next);
virtual bool moveKeyEvent(QDocumentCursor &c, QKeyEvent *e, bool *leave);
@ -377,15 +383,14 @@ public:
void pageUp(QDocumentCursor::MoveMode moveMode);
void pageDown(QDocumentCursor::MoveMode moveMode);
void selectionChange(bool force = false);
void repaintCursor();
void ensureCursorVisible();
void ensureVisible(int line);
void ensureVisible(const QRect &rect);
void preInsert(QDocumentCursor &c, const QString &text);
void insertText(QDocumentCursor &c, const QString &text);
void insertText(QDocumentCursor &c, const QString &text,
const QString &sfmtID = {});
QDocumentLine lineAtPosition(const QPoint &p) const;
QDocumentCursor cursorForPosition(const QPoint &p) const;
@ -399,6 +404,17 @@ public:
void clearCursorMirrors();
void addCursorMirror(const QDocumentCursor &c);
bool undoRedoEnabled() const;
bool cursorMirrorEnabled() const;
private:
bool unindent(const QDocumentCursor &cur);
bool isAutoCloseChar(const QString &ch);
QString getPairedCloseChar(const QString &ch);
protected slots:
void documentWidthChanged(int newWidth);
void documentHeightChanged(int newWidth);
@ -406,29 +422,21 @@ protected slots:
void repaintContent(int i, int n);
void updateContent(int i, int n);
void markChanged(QDocumentLineHandle *l, int mark, bool on);
void emitMarkChanged(QDocumentLineHandle *l, int mark, bool on);
void bindingSelected(QAction *a);
void lineEndingSelected(QAction *a);
void lineEndingChanged(int lineEnding);
protected:
enum SaveState { Undefined, Saving, Saved, Conflict };
void init(bool actions = true);
void updateBindingsMenu();
#ifndef _QMDI_
QString m_name, m_fileName;
#endif
QMenu *pMenu;
QHash<QString, QAction *> m_actions;
QMenu *m_lineEndingsMenu;
QActionGroup *m_lineEndingsActions;
QMenu *m_bindingsMenu;
QAction *aDefaultBinding;
QActionGroup *m_bindingsActions;
@ -450,6 +458,9 @@ protected:
int m_curPlaceHolder, m_cphOffset;
QList<PlaceHolder> m_placeHolders;
bool m_undoRedoEnabled = true;
bool m_cursorMirrorEnabled = true;
int m_state;
bool m_selection;
QRect m_crect, m_margins;

View File

@ -91,9 +91,7 @@ QStringList QLanguageFactory::fileFilters() const {
QStringList l;
foreach (QString lng, m_languages)
l << tr("%1 files (*.%2)")
.arg(lng)
.arg(m_data[lng].extensions.join(" *."));
l << tr("%1 files (*.%2)").arg(lng, m_data[lng].extensions.join(" *."));
l << tr("All files (*)");
@ -240,18 +238,6 @@ QLanguageFactory::languageData(const QString &lang) {
return m_data[lang];
}
/*!
\brief Registers a new completion engine
\note This engine will NOT be used if there are no language definition
for the language it supports...
*/
void QLanguageFactory::addLanguageDefinition(QLanguageDefinition *l) {
Q_UNUSED(l)
qWarning("New design does not allow this sorry...");
}
/*!
\brief Registers a new completion engine

View File

@ -68,7 +68,6 @@ public:
public slots:
void addLanguage(const LangData &d);
void addLanguageDefinition(QLanguageDefinition *l);
void addCompletionEngine(QCodeCompletionEngine *e);
virtual void setLanguage(QEditor *e, const QString &f);

View File

@ -516,7 +516,7 @@ void QLineMarksInfoCenter::cursorMoved(QEditor *e) {
\internal
*/
void QLineMarksInfoCenter::lineDeleted(QDocumentLineHandle *h) {
QLineMarkHandleList::iterator i = m_lineMarks.begin();
auto i = m_lineMarks.begin();
while (i != m_lineMarks.end()) {
if (i->line == h) {

View File

@ -156,6 +156,8 @@ public slots:
void toggleLineMark(const QLineMarkHandle &mark);
void removeLineMark(const QLineMarkHandle &mark);
void lineDeleted(QDocumentLineHandle *h);
void flush(const QString &file);
signals:
@ -168,7 +170,6 @@ protected:
protected slots:
void cursorMoved(QEditor *e);
void lineDeleted(QDocumentLineHandle *h);
void markChanged(const QString &f, QDocumentLineHandle *h, int mark,
bool on);

View File

@ -20,34 +20,24 @@
\brief Implementation of the QPanelLayout class.
*/
#include "qdebug.h"
#include "qeditor.h"
#include "qpanel.h"
#include <QScrollBar>
#include <QWidget>
#ifdef Q_WS_WIN
// panel position fix required on some systems to work around a bug in
// QAbstractScrollArea
#define _PANEL_POSITION_FIX_
#endif
/*!
\class QPanelLayout
\brief A specialized layout taking care of panel display
The panel layout is specialized in several ways :
<ul>
<li>It only operates on specific widgets (which inherit QPanel)</li>
<li>It can only layout widgets in the viewport margins of a QEditor
(could work with any QAbstractScrollArea if a single method was made public
instead of protected...) so it does not qualify as a "real" layout (contrary
to grid/box layouts)</li> <li>It positions widgets on the border of the
editor in the same way the Border Layout example does (most of the layout
code actually comes from there).</li> <li>It provides
serialization/deserialization of its layout structure</li>
</ul>
The panel layout is specialized in several ways :
<ul>
<li>It only operates on specific widgets (which inherit QPanel)</li>
<li>It can only layout widgets in the viewport margins of a QEditor (could work
with any QAbstractScrollArea if a single method was made public instead of
protected...) so it does not qualify as a "real" layout (contrary to grid/box
layouts)</li> <li>It positions widgets on the border of the editor in the same
way the Border Layout example does (most of the layout code actually comes from
there).</li> <li>It provides serialization/deserialization of its layout
structure</li>
</ul>
*/
/*
@ -88,8 +78,8 @@ QString QPanelLayout::serialized() const {
/*
Scheme :
QPanelLayout::Position '{' comma-separated list of identifiers '}'
*/
QPanelLayout::Position '{' comma-separated list of identifiers '}'
*/
QHash<int, QString> posMap;
@ -108,11 +98,12 @@ QString QPanelLayout::serialized() const {
} else {
QString &ref = posMap[position];
ref.insert(ref.size() - 2, QString(",") + panel->id());
ref.insert(ref.length() - 2, QStringLiteral(",") + panel->id());
}
}
return QStringList(posMap.values()).join("");
auto values = posMap.values();
return values.join("");
}
/*!
@ -146,7 +137,8 @@ void QPanelLayout::addSerialized(const QString &layout) {
}
} else if (layout.at(i) == '{') {
inList = true;
position = Position(layout.mid(last, i - last).toInt());
auto pos = layout.mid(last, i - last);
position = Position(pos.toInt());
// qDebug("position : %i [%s]", position,
// qPrintable(layout.mid(last, i - last)));
@ -233,7 +225,12 @@ QLayoutItem *QPanelLayout::itemAt(int idx) const {
QLayoutItem *QPanelLayout::takeAt(int idx) {
if ((idx >= 0) && (idx < m_list.size())) {
PanelWrapper *layoutStruct = m_list.takeAt(idx);
return layoutStruct->item;
Q_ASSERT(layoutStruct);
if (!layoutStruct)
return 0;
QLayoutItem *li = layoutStruct->item;
delete layoutStruct;
return li;
}
return 0;
@ -243,17 +240,14 @@ QLayoutItem *QPanelLayout::takeAt(int idx) {
\internal
*/
void QPanelLayout::setGeometry(const QRect &r) {
// qDebug("laying out %i panels", count());
#ifdef _PANEL_POSITION_FIX_
// qDebug("laying out %i panels", count());
QScrollBar *vb = m_parent->verticalScrollBar(),
*hb = m_parent->horizontalScrollBar();
QRect rect(r.x(), r.y(),
r.width() - (vb->isVisibleTo(m_parent) ? vb->width() : 0),
r.height() - (hb->isVisibleTo(m_parent) ? hb->height() : 0));
#else
QRect rect(r.x(), r.y(), r.width(), r.height());
#endif
int i, eastWidth = 0, westWidth = 0, northHeight = 0, southHeight = 0,
centerHeight = 0;
@ -269,13 +263,17 @@ void QPanelLayout::setGeometry(const QRect &r) {
continue;
if (position == North) {
item->setGeometry(QRect(rect.x(), northHeight, rect.width(),
item->sizeHint().height()));
item->setGeometry(QRect(rect.x(), rect.y() + northHeight,
rect.width(), item->sizeHint().height()));
northHeight += item->geometry().height() + spacing();
} else if (position == South) {
int ht = item->sizeHint().height();
if (item->hasHeightForWidth()) {
ht = item->heightForWidth(rect.width());
}
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
rect.width(), item->sizeHint().height()));
rect.width(), ht));
southHeight += item->geometry().height() + spacing();
@ -296,7 +294,8 @@ void QPanelLayout::setGeometry(const QRect &r) {
continue;
if (position == West) {
item->setGeometry(QRect(rect.x() + westWidth, northHeight,
item->setGeometry(QRect(rect.x() + westWidth,
rect.y() + northHeight,
item->sizeHint().width(), centerHeight));
westWidth += item->geometry().width() + spacing();
@ -306,23 +305,15 @@ void QPanelLayout::setGeometry(const QRect &r) {
eastWidth += item->geometry().width() + spacing();
item->setGeometry(QRect(
rect.x() + rect.width() - eastWidth + spacing(), northHeight,
item->geometry().width(), item->geometry().height()));
item->setGeometry(
QRect(rect.x() + rect.width() - eastWidth + spacing(),
rect.y() + northHeight, item->geometry().width(),
item->geometry().height()));
}
}
/*
if ( center )
center->item->setGeometry(QRect(westWidth, northHeight,
rect.width()
- eastWidth - westWidth, centerHeight));
*/
// qDebug("{%i, %i, %i, %i}", westWidth, northHeight, eastWidth,
// southHeight);
// qDebug() << westWidth;
m_parent->setPanelMargins(westWidth, northHeight, eastWidth, southHeight);
m_parent->setPanelMargins(westWidth, rect.y() + northHeight, eastWidth,
southHeight);
}
/*!

View File

@ -69,7 +69,7 @@ void QSnippetManager::removeSnippet(int i, bool cleanup) {
QSnippet *snip = m_snippets.takeAt(i);
emit snippetRemoved(i);
emit snippetRemovedByIndex(i);
emit snippetRemoved(snip);
if (cleanup)
@ -84,7 +84,7 @@ void QSnippetManager::removeSnippet(QSnippet *snip) {
m_snippets.removeAt(idx);
emit snippetRemoved(idx);
emit snippetRemovedByIndex(idx);
emit snippetRemoved(snip);
}
@ -157,7 +157,7 @@ QSnippetManager::patternLoader(const QString &type) const {
return pl;
}
return 0;
return nullptr;
}
void QSnippetManager::saveSnippetsToDirectory(const QString &path) {
@ -179,14 +179,9 @@ void QSnippetManager::saveSnippetsToDirectory(const QString &path) {
void QSnippetManager::loadSnippetsFromDirectory(const QString &path) {
QDir d(path);
QFileInfoList l = d.entryInfoList(QDir::Files | QDir::Readable);
foreach (const QFileInfo &info, l) {
if (info.suffix() != "qcs")
continue;
// TODO : pattern selection?
loadSnippetFromFile(info.absoluteFilePath(), "Simple");
for (auto &info : d.entryInfoList({QStringLiteral("*.qcs")},
QDir::Files | QDir::Readable)) {
loadSnippetFromFile(info.absoluteFilePath(), QStringLiteral("Simple"));
}
}

View File

@ -33,7 +33,7 @@ class QCE_EXPORT QSnippetManager : public QObject {
Q_OBJECT
public:
QSnippetManager(QObject *p = 0);
explicit QSnippetManager(QObject *p = nullptr);
virtual ~QSnippetManager();
int snippetCount() const;
@ -57,8 +57,7 @@ public slots:
signals:
void snippetAdded(QSnippet *s);
void snippetRemoved(int i);
void snippetRemovedByIndex(int i);
void snippetRemoved(QSnippet *s);
private:

View File

@ -1,17 +1,19 @@
/****************************************************************************
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
** 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 file is part of the Edyuk project <http://edyuk.org>
** 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.
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
** 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 "qcalltip.h"
@ -23,6 +25,8 @@
#include <QMouseEvent>
#include <QPainter>
#include <QToolTip>
/*!
\class QCallTip
\brief A widget dedicated to calltips display
@ -32,6 +36,11 @@ QCallTip::QCallTip(QWidget *p) : QWidget(p), m_index(0) {
setCursor(Qt::ArrowCursor);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_DeleteOnClose);
auto palette = QToolTip::palette();
_background = palette.color(QPalette::ToolTipBase);
_foreground = palette.color(QPalette::ToolTipText);
_borderColor = palette.color(QPalette::Shadow);
}
QCallTip::~QCallTip() {}
@ -49,6 +58,8 @@ void QCallTip::paintEvent(QPaintEvent *e) {
Q_UNUSED(e)
QPainter p(this);
p.setOpacity(_opacity);
QFontMetrics fm = fontMetrics();
m_up = m_down = QRect();
@ -66,21 +77,18 @@ void QCallTip::paintEvent(QPaintEvent *e) {
bg.setWidth(bg.width() + arrowWidth);
}
p.fillRect(bg, QColor(0xca, 0xff, 0x70));
p.fillRect(bg, _background);
// p.drawRect(bg);
p.save();
p.setPen(QColor(0x00, 0x00, 0x00));
p.setPen(_borderColor);
p.drawLine(0, height() - 1, bg.width() - 1, height() - 1);
p.drawLine(bg.width() - 1, height() - 1, bg.width() - 1, 0);
p.setPen(QColor(0xc0, 0xc0, 0xc0));
p.drawLine(0, height() - 1, 0, 0);
p.drawLine(0, 0, bg.width() - 1, 0);
p.restore();
int top = height() / 3, bottom = height() - height() / 3;
if (bPrev) {
@ -107,8 +115,11 @@ void QCallTip::paintEvent(QPaintEvent *e) {
offset += arrowWidth;
}
p.setPen(_foreground);
p.drawText(offset, fm.ascent() + 2, m_tips.at(m_index));
p.restore();
setFixedSize(bg.size() + QSize(1, 1));
}
@ -124,7 +135,7 @@ void QCallTip::keyPressEvent(QKeyEvent *e) {
return;
}
QString prefix, text = e->text();
QString text = e->text();
switch (e->key()) {
case Qt::Key_Escape:
@ -231,3 +242,39 @@ void QCallTip::mousePressEvent(QMouseEvent *e) {
}
void QCallTip::mouseReleaseEvent(QMouseEvent *e) { e->accept(); }
qreal QCallTip::opacity() const { return _opacity; }
void QCallTip::setOpacity(qreal newOpacity) {
if (qFuzzyCompare(_opacity, newOpacity))
return;
_opacity = newOpacity;
emit opacityChanged();
}
QColor QCallTip::borderColor() const { return _borderColor; }
void QCallTip::setBorderColor(const QColor &newBorderColor) {
if (_borderColor == newBorderColor)
return;
_borderColor = newBorderColor;
emit borderColorChanged();
}
QColor QCallTip::foreground() const { return _foreground; }
void QCallTip::setForeground(const QColor &newForeground) {
if (_foreground == newForeground)
return;
_foreground = newForeground;
emit foregroundChanged();
}
QColor QCallTip::background() const { return _background; }
void QCallTip::setBackground(const QColor &newBackground) {
if (_background == newBackground)
return;
_background = newBackground;
emit backgroundChanged();
}

View File

@ -1,17 +1,19 @@
/****************************************************************************
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
** 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 file is part of the Edyuk project <http://edyuk.org>
** 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.
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
** 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/>.
** =============================================================================
*/
#ifndef _QCALL_TIP_H_
#define _QCALL_TIP_H_
@ -26,6 +28,17 @@
#include <QWidget>
class QCE_EXPORT QCallTip : public QWidget {
Q_OBJECT
Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY
backgroundChanged FINAL)
Q_PROPERTY(QColor foreground READ foreground WRITE setForeground NOTIFY
foregroundChanged FINAL)
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY
borderColorChanged FINAL)
Q_PROPERTY(
qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL)
public:
QCallTip(QWidget *p = nullptr);
virtual ~QCallTip();
@ -33,18 +46,43 @@ public:
QStringList tips() const;
void setTips(const QStringList &l);
QColor background() const;
void setBackground(const QColor &newBackground);
QColor foreground() const;
void setForeground(const QColor &newForeground);
QColor borderColor() const;
void setBorderColor(const QColor &newBorderColor);
qreal opacity() const;
void setOpacity(qreal newOpacity);
signals:
void backgroundChanged();
void foregroundChanged();
void borderColorChanged();
void opacityChanged();
protected:
virtual void paintEvent(QPaintEvent *e);
virtual void keyPressEvent(QKeyEvent *e);
virtual void focusInEvent(QFocusEvent *e);
virtual void focusOutEvent(QFocusEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void paintEvent(QPaintEvent *e) override;
virtual void keyPressEvent(QKeyEvent *e) override;
virtual void focusInEvent(QFocusEvent *e) override;
virtual void focusOutEvent(QFocusEvent *e) override;
virtual void mousePressEvent(QMouseEvent *e) override;
virtual void mouseReleaseEvent(QMouseEvent *e) override;
private:
int m_index;
QStringList m_tips;
QRect m_up, m_down;
QColor _background;
QColor _foreground;
QColor _borderColor;
qreal _opacity = 1;
};
#endif

View File

@ -63,6 +63,8 @@ QFoldPanel::~QFoldPanel() {}
*/
QString QFoldPanel::type() const { return "Fold indicators"; }
QString QFoldPanel::name() const { return tr("Fold Panel"); }
/*!
*/
@ -102,12 +104,12 @@ void QFoldPanel::mousePressEvent(QMouseEvent *e) {
/*!
*/
bool QFoldPanel::paint(QPainter *p, QEditor *e) {
void QFoldPanel::paint(QPainter *p, QEditor *e) {
QDocument *doc = editor()->document();
QLanguageDefinition *def = e->languageDefinition();
if (!def || !doc) {
return true;
return;
}
m_rects.clear();
@ -249,8 +251,6 @@ bool QFoldPanel::paint(QPainter *p, QEditor *e) {
pos += len;
}
return true;
}
QRect QFoldPanel::drawIcon(QPainter *p, QEditor *, int x, int y,

View File

@ -37,10 +37,11 @@ public:
virtual ~QFoldPanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual void mousePressEvent(QMouseEvent *e);
virtual bool paint(QPainter *p, QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
QRect drawIcon(QPainter *p, QEditor *e, int x, int y, bool expand);

View File

@ -60,12 +60,14 @@ QLineChangePanel::~QLineChangePanel() {}
*/
QString QLineChangePanel::type() const { return "Line changes"; }
QString QLineChangePanel::name() const { return tr("Line Change Panel"); }
/*!
\internal
*/
bool QLineChangePanel::paint(QPainter *p, QEditor *e) {
void QLineChangePanel::paint(QPainter *p, QEditor *e) {
if (!e || !e->document())
return true;
return;
const QFontMetrics fm(e->document()->font());
@ -73,8 +75,6 @@ bool QLineChangePanel::paint(QPainter *p, QEditor *e) {
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
QString txt;
QDocument *d = e->document();
n = d->lineNumber(contentsY);
posY = 2 + d->y(n) - contentsY;
@ -99,8 +99,6 @@ bool QLineChangePanel::paint(QPainter *p, QEditor *e) {
posY += ls * span;
}
return true;
}
/*! @} */

View File

@ -40,9 +40,10 @@ public:
virtual ~QLineChangePanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual bool paint(QPainter *p, QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
private:
};

View File

@ -65,9 +65,9 @@ QString QLineMarkPanel::type() const { return "Line marks"; }
/*!
\internal
*/
bool QLineMarkPanel::paint(QPainter *p, QEditor *e) {
void QLineMarkPanel::paint(QPainter *p, QEditor *e) {
if (!e || !e->document())
return true;
return;
m_rects.clear();
m_lines.clear();
@ -130,7 +130,6 @@ bool QLineMarkPanel::paint(QPainter *p, QEditor *e) {
// qDebug("</session>");
// setFixedWidth(sfm.width(txt) + 5);
return true;
}
/*!

View File

@ -45,7 +45,7 @@ signals:
void onToggleMark(int lineIndex);
protected:
virtual bool paint(QPainter *p, QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void contextMenuEvent(QContextMenuEvent *e);

View File

@ -47,6 +47,7 @@ QCE_AUTO_REGISTER(QLineNumberPanel)
*/
QLineNumberPanel::QLineNumberPanel(QWidget *p) : QPanel(p), m_verbose(false) {
setFixedWidth(20);
setObjectName("lineNumberPanel");
}
/*!
@ -57,7 +58,11 @@ QLineNumberPanel::~QLineNumberPanel() {}
/*!
*/
QString QLineNumberPanel::type() const { return "Line numbers"; }
QString QLineNumberPanel::type() const {
return QStringLiteral("Line numbers");
}
QString QLineNumberPanel::name() const { return tr("Line Number Panel"); }
/*!
@ -72,6 +77,8 @@ void QLineNumberPanel::setVerboseMode(bool y) {
update();
}
void QLineNumberPanel::setFont_slot(const QFont &font) { setFont(font); }
/*!
*/
@ -79,58 +86,70 @@ void QLineNumberPanel::editorChange(QEditor *e) {
if (editor()) {
disconnect(editor(), SIGNAL(cursorPositionChanged()), this,
SLOT(update()));
disconnect(editor()->document(), SIGNAL(fontChanged(QFont)), this,
SLOT(setFont_slot(QFont)));
}
if (e) {
setFixedWidth(
QFontMetrics(e->document()->font())
.horizontalAdvance(QString::number(e->document()->lines())) +
5);
setFixedWidth(fontMetrics().horizontalAdvance(
QString::number(e->document()->lines())) +
5);
connect(e, SIGNAL(cursorPositionChanged()), this, SLOT(update()));
connect(e, &QEditor::zoomed, this, [=] {
setFixedWidth(QFontMetrics(e->document()->font())
.horizontalAdvance(
QString::number(e->document()->lines())) +
5);
});
connect(e, &QEditor::cursorPositionChanged, this,
QOverload<>::of(&QLineNumberPanel::update));
connect(e->document(), &QDocument::fontChanged, this,
&QLineNumberPanel::setFont_slot);
}
}
/*!
*/
bool QLineNumberPanel::paint(QPainter *p, QEditor *e) {
void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
/*
possible Unicode caracter for wrapping arrow :
0x21B3
0x2937
*/
possible Unicode caracter for wrapping arrow :
0x21B3
0x2937
*/
QFont f(font());
f.setWeight(QFont::Bold);
// f.setWeight(QFont::Bold);
const QFontMetrics sfm(f);
bool specialFontUsage = false;
QFont specialFont(font());
#ifndef WIN32
static const QChar wrappingArrow(0x2937);
const QFontMetrics specialSfm(sfm);
#if QT_VERSION >= 0x050000 && defined Q_OS_MAC && (QT_VERSION < 0x050200)
if (!specialSfm.inFont(wrappingArrow)) {
specialFontUsage = true;
specialFont.setFamily("Gothic Regular");
// specialSfm(specialFont);
}
#endif
#else
// 0xC4 gives a decent wrapping arrow in Wingdings fonts, availables on all
// windows systems this is a hackish fallback to workaround Windows issues
// with Unicode...
// windows systems
// this is a hackish fallback to workaround Windows issues with Unicode...
static const QChar wrappingArrow(0xC4);
QFont specialFont(font());
specialFont.setFamily("Wingdings");
const QFontMetrics specialSfm(specialFont);
specialFontUsage = true;
#endif
const int max = e->document()->lines();
const int panelWidth = sfm.horizontalAdvance(QString::number(max)) + 5;
int max = e->document()->lines();
if (max < 100)
max = 100; // always reserve 3 line number columns to avoid ugly jumping
// of width
QString s_width = QString::number(max);
s_width.fill('6');
const int panelWidth = sfm.horizontalAdvance(s_width) + 5;
setFixedWidth(panelWidth);
const QFontMetrics fm(e->document()->font());
int n, posY, as = fm.ascent(), ls = fm.lineSpacing(),
int n, posY, as = QFontMetrics(e->document()->font()).ascent(),
ls = e->document()->lineSpacing(),
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
@ -144,12 +163,6 @@ bool QLineNumberPanel::paint(QPainter *p, QEditor *e) {
// qDebug("first = %i; last = %i", first, last);
// qDebug("beg pos : %i", posY);
p->save();
f = p->font();
f.setPointSize(d->font().pointSize());
p->setFont(f);
for (;; ++n) {
// qDebug("n = %i; pos = %i", n, posY);
QDocumentLine line = d->line(n);
@ -163,22 +176,42 @@ bool QLineNumberPanel::paint(QPainter *p, QEditor *e) {
bool draw = true;
if (!m_verbose) {
draw = !((n + 1) % 10) || !n || line.marks().count();
draw = !((n + 1) % 10) || !n || !line.marks().empty();
}
txt = QString::number(n + 1);
if (n == cursorLine) {
draw = true;
p->save();
auto f = p->font();
QFont f = p->font();
f.setBold(true);
f.setUnderline(true);
p->setFont(f);
}
if (draw) {
p->drawText(width() - 2 - sfm.horizontalAdvance(txt), posY, txt);
if (specialFontUsage) {
if (line.lineSpan() > 1) {
p->save();
specialFont.setBold(n ==
cursorLine); // todo: only get bold on
// the current wrapped line
p->setFont(specialFont);
}
}
for (int i = 1; i < line.lineSpan(); ++i)
p->drawText(width() - 2 -
specialSfm.horizontalAdvance(wrappingArrow),
posY + i * ls, wrappingArrow);
if (specialFontUsage) {
if (line.lineSpan() > 1)
p->restore();
}
} else {
int yOff = posY - (as + 1) + ls / 2;
@ -188,30 +221,6 @@ bool QLineNumberPanel::paint(QPainter *p, QEditor *e) {
p->drawLine(width() - 7, yOff, width() - 2, yOff);
}
if (line.lineSpan() > 1) {
#ifdef Q_OS_WIN32
p->save();
specialFont.setBold(
n ==
cursorLine); // todo: only get bold on the current wrapped line
specialFont.setPointSize(d->font().pointSize());
p->setFont(specialFont);
#endif
for (int i = 1; i < line.lineSpan(); ++i) {
// draw line wrapping indicators
// p->drawText(width() - 2 - sfm.width(wrappingArrow), posY + i
// * ls, wrappingArrow);
p->drawText(width() - 1 -
specialSfm.horizontalAdvance(wrappingArrow),
posY + i * ls, wrappingArrow);
}
#ifdef Q_OS_WIN32
p->restore();
#endif
}
if (n == cursorLine) {
p->restore();
}
@ -219,13 +228,12 @@ bool QLineNumberPanel::paint(QPainter *p, QEditor *e) {
posY += ls * line.lineSpan();
}
p->restore();
// p->setPen(Qt::DotLine);
// p->drawLine(width()-1, 0, width()-1, pageBottom);
// setFixedWidth(sfm.width(txt) + 5);
return true;
}
/*! @} */
QSize QLineNumberPanel::sizeHint() const { return QSize(_fixWidth, 0); }

View File

@ -37,16 +37,22 @@ public:
bool isVerboseMode() const;
virtual QString type() const;
virtual QString name() const;
virtual QSize sizeHint() const;
public slots:
void setVerboseMode(bool y);
void setFont_slot(const QFont &font);
protected:
virtual void editorChange(QEditor *e);
virtual bool paint(QPainter *p, QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
bool m_verbose;
int mutable m_minWidth = 0;
int _fixWidth = 0;
};
#endif // _QLINE_NUMBER_PANEL_H_

View File

@ -88,6 +88,8 @@ QPanel::~QPanel() {
// qDebug("Panels cleared.");
}
QString QPanel::name() const { return type(); }
/*!
*/
QEditor *QPanel::editor() { return m_editor; }
@ -107,7 +109,7 @@ void QPanel::attach(QEditor *e) {
this, SLOT(update()));
}
editorChange(e);
QPanel::editorChange(e);
m_editor = e;
setParent(e);
@ -243,6 +245,8 @@ void QPanel::hideEvent(QHideEvent *e) {
\internal
*/
void QPanel::paintEvent(QPaintEvent *e) {
QWidget::paintEvent(e);
if (!m_editor || !m_editor->document()) {
e->ignore();
return;
@ -251,22 +255,12 @@ void QPanel::paintEvent(QPaintEvent *e) {
e->accept();
QPainter p(this);
if (!paint(&p, m_editor))
QWidget::paintEvent(e);
paint(&p, m_editor);
}
/*!
\internal
*/
bool QPanel::paint(QPainter *, QEditor *) {
/*
qWarning("Bad panel implementation : "
"QPanel::paint(QPainter*, QEditor*)"
" is a stub that should not get called."
"\nCheck out the code of %s", qPrintable(type()));
*/
return false;
}
void QPanel::paint(QPainter *, QEditor *) {}
/* @} */

View File

@ -46,6 +46,7 @@ public:
virtual QString id() const = 0;
virtual QString type() const = 0;
virtual QString name() const;
QEditor *editor();
void attach(QEditor *e);
@ -70,7 +71,7 @@ protected:
virtual void showEvent(QShowEvent *e);
virtual void hideEvent(QHideEvent *e);
virtual void paintEvent(QPaintEvent *e);
virtual bool paint(QPainter *p, QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
private:
QPointer<QEditor> m_editor;

View File

@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qsimplecolorpicker.h"
/*!
\file qsimplecolorpicker.cpp
\brief Implementation of the QSimpleColorPicker class
*/
#include <QColorDialog>
#include <QIcon>
#include <QPainter>
#include <QPixmap>
#include <QResizeEvent>
QSimpleColorPicker::QSimpleColorPicker(QWidget *w) : QToolButton(w) {
setColor(QColor());
connect(this, SIGNAL(clicked()), this, SLOT(clicked()));
}
QSimpleColorPicker::QSimpleColorPicker(const QColor &c, QWidget *w)
: QToolButton(w) {
setColor(c);
connect(this, SIGNAL(clicked()), this, SLOT(clicked()));
}
const QColor &QSimpleColorPicker::color() const { return m_color; }
void QSimpleColorPicker::setColor(const QColor &c) {
m_color = c;
updateIcon(size());
}
void QSimpleColorPicker::resizeEvent(QResizeEvent *e) {
updateIcon(e->size());
QToolButton::resizeEvent(e);
}
void QSimpleColorPicker::contextMenuEvent(QContextMenuEvent *e) {
setColor(QColor());
e->accept();
QToolButton::contextMenuEvent(e);
}
void QSimpleColorPicker::updateIcon(const QSize &sz) {
QPixmap px(sz.width() - 3, sz.height() - 3);
QPainter p(&px);
if (m_color.isValid()) {
p.fillRect(0, 0, px.width(), px.height(), m_color);
setIcon(QIcon(px));
} else {
// p.fillRect(0, 0, px.width(), px.height(), palette().window());
setIcon(QIcon());
}
}
void QSimpleColorPicker::clicked() {
QColor c = QColorDialog::getColor(m_color);
if (c.isValid()) {
setColor(c);
}
}

View File

@ -1,55 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QSIMPLE_COLOR_PICKER_H_
#define _QSIMPLE_COLOR_PICKER_H_
#include "qce-config.h"
/*!
\file qsimplecolorpicker.h
\brief Definition of the QSimpleColorPicker class
*/
#include <QToolButton>
class QCE_EXPORT QSimpleColorPicker : public QToolButton {
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
QSimpleColorPicker(QWidget *w = 0);
QSimpleColorPicker(const QColor &c, QWidget *w = 0);
const QColor &color() const;
protected:
void resizeEvent(QResizeEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
public slots:
void setColor(const QColor &c);
void updateIcon(const QSize &sz);
private slots:
void clicked();
private:
QColor m_color;
};
#endif

View File

@ -1,50 +0,0 @@
cmake_minimum_required(VERSION 3.6)
project(QCodeModel2 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Gui)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Gui)
add_definitions(-D_QCODE_MODEL_BUILD_STATIC_)
add_library(
QCodeModel2 STATIC
qcm-config.h
qcodemodel.h
qcodeproxymodel.h
qcodenode.h
qcodenodepool.h
qsourcecodewatcher.h
qcodeview.h
qcodeserializer.h
qcodestream.h
qcodedevice.h
qcodebuffer.h
qcodelexer.h
qcodeparser.h
qcodeloader.h
qcodemodel.cpp
qcodeproxymodel.cpp
qcodenode.cpp
qcodenodepool.cpp
qsourcecodewatcher.cpp
qcodeview.cpp
qcodeserializer.cpp
qcodestream.cpp
qcodedevice.cpp
qcodebuffer.cpp
qcodelexer.cpp
qcodeparser.cpp
qcodeloader.cpp)
target_include_directories(QCodeModel2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(QCodeModel2 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Gui)
target_compile_definitions(QCodeModel2 PUBLIC -D_QCODE_MODEL_BUILD_STATIC_)

View File

@ -1,46 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCM_CONFIG_H_
#define _QCM_CONFIG_H_
#include <qglobal.h>
/*!
\macro QCM_EXPORT
Allow a cross-platform and sure possibility to link in static or dynamic
way, depending to what's needed...
*/
#ifdef _QCODE_MODEL_BUILD_DLL_
#if (defined(QT_SHARED) || defined(QT_DLL)) && !defined(QT_PLUGIN)
#define QCM_EXPORT Q_DECL_EXPORT
#endif
#else
#ifdef _QCODE_MODEL_BUILD_STATIC_
#define QCM_EXPORT
#else
#define QCM_EXPORT Q_DECL_IMPORT
#endif
#endif
class QByteArray;
template <typename T>
class QList;
typedef QByteArray QToken;
typedef QList<QToken> QTokenList;
#endif // _QCM_CONFIG_H_

View File

@ -1,84 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qcodebuffer.h"
/*!
\file qcodebuffer.cpp
\brief Implementation of the QCodebuffer class.
*/
#include <QString>
/*!
\class QCodebuffer
\brief Code stream that operates on a static string buffer
*/
/*!
\brief Constructs a code buffer from an Unicode string
\note The string is converted to local8Bit()
*/
QCodeBuffer::QCodeBuffer(const QString &s)
: QCodeStream(), iPos(0), sBuffer(s.toLocal8Bit()) {
sBuffer.replace("\r\n", "\n");
sBuffer.replace("\r", "\n");
}
/*!
\brief Constructs a code buffer from a byte array
*/
QCodeBuffer::QCodeBuffer(const QByteArray &s)
: QCodeStream(), iPos(0), sBuffer(s) {
sBuffer.replace("\r\n", "\n");
sBuffer.replace("\r", "\n");
}
/*!
\brief return the char pointed to by the internal pointer and update the
pointer
*/
char QCodeBuffer::getChar() {
if (iPos < sBuffer.length())
return sBuffer.at(iPos++);
else
return '\0';
}
/*!
\brief Move back by one character
*/
void QCodeBuffer::ungetChar(char) {
if (iPos > 0)
--iPos;
}
/*!
\return the content of the current line
*/
QByteArray QCodeBuffer::readLine() {
char c;
QByteArray s;
while ((c = getChar())) {
if (c == '\n')
break;
s += c;
}
return s;
}

Some files were not shown because too many files have changed in this diff Show More