Skip to content

Commit

Permalink
fix: restore column selection after undo
Browse files Browse the repository at this point in the history
As title.
update backward / forward delete;
update unit test.

Log: Restore column selection after undo.
Bug: https://pms.uniontech.com/bug-view-273663.html
Influence: column-editing
  • Loading branch information
rb-union committed Sep 25, 2024
1 parent 432c884 commit 889fa19
Show file tree
Hide file tree
Showing 9 changed files with 391 additions and 104 deletions.
71 changes: 44 additions & 27 deletions src/common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@
#include <QDBusReply>

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) if((p)) { delete (p); (p) = nullptr;}
#define SAFE_DELETE(p) \
if ((p)) { \
delete (p); \
(p) = nullptr; \
}
#endif

#define DEEPIN_THEME QString("%1share/deepin-editor/themes/deepin.theme").arg(LINGLONG_PREFIX)
#define DEEPIN_DARK_THEME QString("%1share/deepin-editor/themes/deepin_dark.theme").arg(LINGLONG_PREFIX)
#define DATA_SIZE_1024 1024
#define TEXT_EIDT_MARK_ALL "MARK_ALL"
#define PROC_MEMINFO_PATH "/proc/meminfo"
#define COPY_CONSUME_MEMORY_MULTIPLE 9 //复制文本时内存占用系数
#define PASTE_CONSUME_MEMORY_MULTIPLE 7 //粘贴文本时内存占用系数
#define DEEPIN_THEME QString("%1share/deepin-editor/themes/deepin.theme").arg(LINGLONG_PREFIX)
#define DEEPIN_DARK_THEME QString("%1share/deepin-editor/themes/deepin_dark.theme").arg(LINGLONG_PREFIX)
#define DATA_SIZE_1024 1024
#define TEXT_EIDT_MARK_ALL "MARK_ALL"
#define PROC_MEMINFO_PATH "/proc/meminfo"
#define COPY_CONSUME_MEMORY_MULTIPLE 9 // 复制文本时内存占用系数
#define PASTE_CONSUME_MEMORY_MULTIPLE 7 // 粘贴文本时内存占用系数

class Utils
{
Expand All @@ -33,13 +37,13 @@ class Utils
* @brief 区间交叉类型
*/
enum RegionIntersectType {
ELeft, ///< 活动区间在固定区间左侧 例如 [0, 9] 和 [-5, -1]
ERight, ///< 活动区间在固定区间右侧 例如 [0, 9] 和 [10, 15]
ELeft, ///< 活动区间在固定区间左侧 例如 [0, 9] 和 [-5, -1]
ERight, ///< 活动区间在固定区间右侧 例如 [0, 9] 和 [10, 15]

EIntersectLeft, ///< 活动区间在固定区间左侧存在范围重叠 例如 [0, 9] 和 [-5, 5]
EIntersectRight, ///< 活动区间在固定区间右侧存在范围重叠 例如 [0, 9] 和 [5, 15]
EIntersectOutter, ///< 活动区间包含固定区间 例如 [0, 9] 和 [-10, 10]
EIntersectInner, ///< 活动区间处于固定区间内部 例如 [0, 9] 和 [5, 6]
EIntersectLeft, ///< 活动区间在固定区间左侧存在范围重叠 例如 [0, 9] 和 [-5, 5]
EIntersectRight, ///< 活动区间在固定区间右侧存在范围重叠 例如 [0, 9] 和 [5, 15]
EIntersectOutter, ///< 活动区间包含固定区间 例如 [0, 9] 和 [-10, 10]
EIntersectInner, ///< 活动区间处于固定区间内部 例如 [0, 9] 和 [5, 6]
};

/**
Expand All @@ -50,6 +54,18 @@ class Utils
V23,
};

// TODO: annother command type
enum UndoCommandId {
IdDefault = -1, // default QUndoCommand::id() return
IdUnknown = 256, // sa: QTextUndoCommand::Command::Custom
IdInsert,
IdDelete,

IdColumnEdit = 0x1000, // column edit mark
IdColumnEditInsert = IdColumnEdit | IdInsert,
IdColumnEditDelete = IdColumnEdit | IdDelete, // column editing delete command
};

static QString getQrcPath(const QString &imageName);
static QString getQssPath(const QString &qssName);
static QSize getRenderSize(int fontSize, const QString &string);
Expand Down Expand Up @@ -89,45 +105,46 @@ class Utils
安全考虑,不要全局使用.仅在个别控件中使用
*******************************************************************************/
static void clearChildrenFocus(QObject *objParent);
//清除 控件及子控件所以焦点 梁卫东 2020-09-14 10:34:19
// 清除 控件及子控件所以焦点 梁卫东 2020-09-14 10:34:19
static void clearChildrenFoucusEx(QWidget *pWidget);
//设置所有控件焦点 梁卫东 2020-09-15 17:55:18
// 设置所有控件焦点 梁卫东 2020-09-15 17:55:18
static void setChildrenFocus(QWidget *pWidget, Qt::FocusPolicy policy = Qt::StrongFocus);
//根据指定名称获取进程数量 秦浩玲 2021-01-26
// 根据指定名称获取进程数量 秦浩玲 2021-01-26
static int getProcessCountByName(const char *pstrName);
//批量结束指定名称的进程 秦浩玲 2021-01-26
// 批量结束指定名称的进程 秦浩玲 2021-01-26
static void killProcessByName(const char *pstrName);
//计算字符串MD5哈希值 秦浩玲 2021-01-28
// 计算字符串MD5哈希值 秦浩玲 2021-01-28
static QString getStringMD5Hash(const QString &input);
//通过dbus接口从任务栏激活窗口 add by guoshaoyu 2021-04-07
// 通过dbus接口从任务栏激活窗口 add by guoshaoyu 2021-04-07
static bool activeWindowFromDock(quintptr winId);

//判断是否共享文件夹且只读
// 判断是否共享文件夹且只读
static bool isShareDirAndReadOnly(const QString &filePath);

static float codecConfidenceForData(const QTextCodec *codec, const QByteArray &data, const QLocale::Country &country);

//return system language
// return system language
static QString getSystemLan();
// 取得系统版本是否为 V23
static SystemVersion getSystemVersion();

static bool isWayland();
static bool isTreeland();

// 计算换行内容 text: 原始文本内容, nWidth: 一行最大宽度, font:字体大小, nElideRow: 最大显示行数,超出最大行时,中间内容加···省略号显示
// 计算换行内容 text: 原始文本内容, nWidth: 一行最大宽度, font:字体大小, nElideRow:
// 最大显示行数,超出最大行时,中间内容加···省略号显示
static QString lineFeed(const QString &text, int nWidth, const QFont &font, int nElidedRow = 2);

// 判断 [x1, y1] 和 [x2, y2] 区间是否存在交集,返回交集类型
static RegionIntersectType checkRegionIntersect(int x1, int y1, int x2, int y2);
// 取得当前文本编辑器支持的编码格式,从文件 :/encodes/encodes.ini 中读取
static QVector<QPair<QString,QStringList>> getSupportEncoding();
static QVector<QPair<QString, QStringList>> getSupportEncoding();
static QStringList getSupportEncodingList();

/**
* @brief libPath 动态库路径
* @param strlib 路径的字符串
*/
* @brief libPath 动态库路径
* @param strlib 路径的字符串
*/
static QString libPath(const QString &strlib);

// 加载外部定制库,如ZPD定制库的等
Expand Down
100 changes: 69 additions & 31 deletions src/editor/deletebackcommond.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#include "deletebackcommond.h"

#include <QTextBlock>

#include "dtextedit.h"

DeleteBackCommand::DeleteBackCommand(QTextCursor cursor, QPlainTextEdit *edit)
: m_cursor(cursor)
, m_edit(edit)
Expand Down Expand Up @@ -33,33 +36,52 @@ void DeleteBackCommand::redo()
m_cursor.setPosition(m_delPos + m_delText.size(), QTextCursor::KeepAnchor);
m_cursor.deleteChar();

// 撤销恢复时光标移回要撤销的位置
// restore cursor position
m_edit->setTextCursor(m_cursor);
}

DeleteBackAltCommand::DeleteBackAltCommand(const QList<QTextEdit::ExtraSelection> &selections, QPlainTextEdit *edit)
: m_ColumnEditSelections(selections)
/**
@brief Delete column selection with 'Backsapce' or 'Delete'
The \a backward is default delete character direction (if not selected).
The 'Backspace' button is forward, and the 'Delete' button is backward.
*/
DeleteBackAltCommand::DeleteBackAltCommand(const QList<QTextEdit::ExtraSelection> &selections,
TextEdit *edit,
bool backward)
: m_columnEditSelections(selections)
, m_edit(edit)
{
int size = m_ColumnEditSelections.size();
int sum = 0;
for (int i = 0; i < size; i++) {
for (int i = 0; i < m_columnEditSelections.size(); i++) {
QString text;
auto cursor = m_ColumnEditSelections[i].cursor;

if (!cursor.hasSelection() && !cursor.atBlockEnd()) {
cursor.setPosition(cursor.position() + 1, QTextCursor::KeepAnchor);
auto cursor = m_columnEditSelections[i].cursor;

if (!cursor.hasSelection()) {
// keyboard 'delete' button
if (backward) {
if (!cursor.atEnd()) {
cursor.setPosition(cursor.position() + 1, QTextCursor::KeepAnchor);
}

} else {
// keyboard 'backspace' button
if (!cursor.atStart()) {
cursor.setPosition(cursor.position() - 1);
cursor.setPosition(cursor.position() + 1, QTextCursor::KeepAnchor);
}
}
}

text = cursor.selectedText();
if (!text.isEmpty()) {
int pos = std::min(cursor.anchor(), cursor.position());
DelNode node;
node.m_cursor = cursor;
node.m_insertPos = pos;
node.m_delPos = pos - sum;
node.m_delText = text;
node.m_id_in_Column = i;
node.cursor = cursor;
node.insertPos = pos;
node.delPos = pos - sum;
node.delText = text;
node.idInColumn = i;
node.leftToRight = cursor.anchor() < cursor.position();
m_deletions.push_back(node);

sum += text.size();
Expand All @@ -71,36 +93,52 @@ DeleteBackAltCommand::~DeleteBackAltCommand() {}

void DeleteBackAltCommand::undo()
{
int size = m_deletions.size();
for (int i = 0; i < size; i++) {
auto cursor = m_deletions[i].m_cursor;
int pos = m_deletions[i].m_insertPos;
QString text = m_deletions[i].m_delText;
for (const DelNode &node : m_deletions) {
auto cursor = node.cursor;
const int pos = node.insertPos;
const QString text = node.delText;
cursor.setPosition(pos, QTextCursor::MoveAnchor);
cursor.insertText(text);

cursor.setPosition(pos, QTextCursor::MoveAnchor);
int id = m_deletions[i].m_id_in_Column;

if (0 <= id && id < m_ColumnEditSelections.size()) {
m_ColumnEditSelections[id].cursor = cursor;
m_edit->setTextCursor(cursor);
if (0 <= node.idInColumn && node.idInColumn < m_columnEditSelections.size()) {
const int endPos = pos + text.size();
if (node.leftToRight) {
cursor.setPosition(pos);
cursor.setPosition(endPos, QTextCursor::KeepAnchor);
} else {
cursor.setPosition(endPos);
cursor.setPosition(pos, QTextCursor::KeepAnchor);
}
m_columnEditSelections[node.idInColumn].cursor = cursor;
}
}

if (m_edit && !m_columnEditSelections.isEmpty()) {
m_edit->restoreColumnEditSelection(m_columnEditSelections);
m_edit->setTextCursor(m_columnEditSelections.last().cursor);
}
}

void DeleteBackAltCommand::redo()
{
int size = m_deletions.size();

for (int i = 0; i < size; i++) {
auto cursor = m_deletions[i].m_cursor;
int pos = m_deletions[i].m_delPos;
QString text = m_deletions[i].m_delText;
for (int i = 0; i < m_deletions.size(); i++) {
auto cursor = m_deletions[i].cursor;
const int pos = m_deletions[i].delPos;
const QString text = m_deletions[i].delText;
cursor.setPosition(pos, QTextCursor::MoveAnchor);

for (int j = 0; j < text.size(); j++) {
cursor.deleteChar();
}
}

if (m_edit && !m_columnEditSelections.isEmpty()) {
m_edit->restoreColumnEditSelection(m_columnEditSelections);
m_edit->setTextCursor(m_columnEditSelections.last().cursor);
}
}

int DeleteBackAltCommand::id() const
{
return Utils::IdColumnEditDelete;
}
39 changes: 23 additions & 16 deletions src/editor/deletebackcommond.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@

#ifndef DELETEBACKCOMMOND_H
#define DELETEBACKCOMMOND_H

#include <QUndoCommand>
#include <QTextCursor>
#include <QTextEdit>
#include <qplaintextedit.h>
// 向后删除单一文字或选中文字的撤销重做

class TextEdit;

// Delete selected text or charactor (if not selected) backward
class DeleteBackCommand : public QUndoCommand
{
public:
DeleteBackCommand(QTextCursor cursor, QPlainTextEdit *edit);
virtual ~DeleteBackCommand();
virtual void undo();
virtual void redo();
~DeleteBackCommand() override;
void undo() override;
void redo() override;

private:
QTextCursor m_cursor;
Expand All @@ -26,29 +30,32 @@ class DeleteBackCommand : public QUndoCommand
QPlainTextEdit *m_edit;
};

// 列模式下向后删除的撤销重做
// Delete redo / undo on column editing
class DeleteBackAltCommand : public QUndoCommand
{
public:
DeleteBackAltCommand(const QList<QTextEdit::ExtraSelection> &selections, QPlainTextEdit *edit);
virtual ~DeleteBackAltCommand();
virtual void undo();
virtual void redo();
DeleteBackAltCommand(const QList<QTextEdit::ExtraSelection> &selections, TextEdit *edit, bool backward = false);
~DeleteBackAltCommand() override;
void undo() override;
void redo() override;

int id() const override;

public:
struct DelNode
{
QString m_delText;
int m_delPos;
int m_insertPos;
int m_id_in_Column;
QTextCursor m_cursor;
QString delText;
int delPos;
int insertPos;
int idInColumn;
QTextCursor cursor;
bool leftToRight; // select orientation
};

private:
QList<QTextEdit::ExtraSelection> m_ColumnEditSelections;
QList<QTextEdit::ExtraSelection> m_columnEditSelections;
QList<DelNode> m_deletions;
QPlainTextEdit *m_edit;
TextEdit *m_edit;
};

#endif // DELETEBACKCOMMOND_H
14 changes: 12 additions & 2 deletions src/editor/deletetextundocommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include <QDebug>
#include <QTextBlock>

DeleteTextUndoCommand::DeleteTextUndoCommand(QTextCursor textcursor, QPlainTextEdit *edit, QUndoCommand *parent)
#include "dtextedit.h"

DeleteTextUndoCommand::DeleteTextUndoCommand(QTextCursor textcursor, TextEdit *edit, QUndoCommand *parent)
: QUndoCommand(parent)
, m_edit(edit)
, m_textCursor(textcursor)
Expand All @@ -27,7 +29,7 @@ DeleteTextUndoCommand::DeleteTextUndoCommand(QTextCursor textcursor, QPlainTextE
}

DeleteTextUndoCommand::DeleteTextUndoCommand(QList<QTextEdit::ExtraSelection> &selections,
QPlainTextEdit *edit,
TextEdit *edit,
QUndoCommand *parent)
: QUndoCommand(parent)
, m_edit(edit)
Expand Down Expand Up @@ -72,6 +74,7 @@ void DeleteTextUndoCommand::undo()
}

if (m_edit && !m_ColumnEditSelections.isEmpty()) {
m_edit->restoreColumnEditSelection(m_ColumnEditSelections);
m_edit->setTextCursor(m_ColumnEditSelections.last().cursor);
}
}
Expand All @@ -93,11 +96,18 @@ void DeleteTextUndoCommand::redo()
}

if (m_edit && !m_ColumnEditSelections.isEmpty()) {
m_edit->restoreColumnEditSelection(m_ColumnEditSelections);
m_edit->setTextCursor(m_ColumnEditSelections.last().cursor);
}
}
}

int DeleteTextUndoCommand::id() const
{
return m_ColumnEditSelections.isEmpty() ? Utils::IdDelete
: Utils::IdColumnEditDelete;
}

DeleteTextUndoCommand2::DeleteTextUndoCommand2(QTextCursor textcursor, QString text, QPlainTextEdit *edit, bool currLine)
: m_textCursor(textcursor)
, m_sInsertText(text)
Expand Down
Loading

0 comments on commit 889fa19

Please sign in to comment.