Skip to content

Comments

pick v20 -v25#410

Merged
deepin-bot[bot] merged 4 commits intolinuxdeepin:masterfrom
pppanghu77:master
Dec 18, 2025
Merged

pick v20 -v25#410
deepin-bot[bot] merged 4 commits intolinuxdeepin:masterfrom
pppanghu77:master

Conversation

@pppanghu77
Copy link
Contributor

@pppanghu77 pppanghu77 commented Dec 18, 2025

Summary by Sourcery

Add window-wide save-all behavior on close, improve resource cleanup timing, and refine tab interaction and file handling behavior.

New Features:

  • Add a save-all-files flow when closing a window, prompting per-tab save decisions and handling drafts and temporary/backup files.
  • Enable middle-click to close tabs and allow the tab bar to accept drag-and-drop operations.

Bug Fixes:

  • Improve shortcut popup screen selection logic for older DTK versions to avoid incorrect placement on rotated screens.
  • Use content-based MIME type detection when checking file support to avoid misclassification based solely on file extension.
  • Prevent auto-backup processing when no windows are open to avoid unnecessary work or errors.

Enhancements:

  • Introduce delayed heap memory trimming via StartManager, invoked after wrapper removal, tabbar reload checks, and before application quit to optimize memory usage.
  • Record window close behavior to save backups only after successfully saving all open files.

shuaijie and others added 4 commits December 18, 2025 13:07
优化文本编辑器事件处理与1043编译问题

Bug: https://pms.uniontech.com/bug-view-307387.html
Log: 优化文本编辑器事件处理与1043编译问题
…n#349)

- Change MIME type detection to use content-based matching for more accurate file type recognition
- Add application/x-troff-man MIME type to supported file types list

This improves file type detection accuracy by examining file contents
rather than relying solely on file extensions.

Log: improve MIME type detection and add man page support
Bug: https://pms.uniontech.com//bug-view-314393.html
修复关闭窗口保存提示

Bug: https://pms.uniontech.com/bug-view-315439.html
Log: 修复关闭窗口保存提示
@sourcery-ai
Copy link

sourcery-ai bot commented Dec 18, 2025

Reviewer's Guide

Adds delayed heap memory trimming, a save-all-files workflow on window close, improved screen selection for shortcuts, better MIME detection, and tab bar UX tweaks such as middle-click close and accepting drag-and-drop, plus a safety check in auto backup when no windows exist.

Sequence diagram for delayed heap memory trimming

sequenceDiagram
    participant Window
    participant StartManager
    participant QBasicTimer
    participant SystemAllocator

    Note over Window,StartManager: delayMallocTrim is invoked after wrapper removal, tabbar reload, and before app quit.

    Window->>StartManager: delayMallocTrim()
    activate StartManager
    alt m_FreeMemTimer not active
        StartManager->>QBasicTimer: start(1000, this)
    else already active
        StartManager->>StartManager: do nothing
    end
    deactivate StartManager

    QBasicTimer-->>StartManager: timerEvent(e) after 1000ms
    activate StartManager
    StartManager->>StartManager: check e->timerId() == m_FreeMemTimer.timerId()
    alt matches FreeMemTimer
        StartManager->>QBasicTimer: stop()
        StartManager->>SystemAllocator: malloc_trim(0)
    end
    deactivate StartManager
Loading

Updated class diagram for Window, StartManager, and Tabbar

classDiagram
    class Window {
        // Existing responsibilities omitted
        +void backupFile()
        +bool closeAllFiles()
        +bool saveAllFiles()
        +void removeWrapper(QString filePath, bool isDelete)
        +void displayShortcuts()
        +void checkTabbarForReload()
        +void closeEvent(QCloseEvent *e)
    }

    class StartManager {
        +static StartManager* instance()
        +void autoBackupFile()
        +void slotCloseWindow()
        +void slotDelayBackupFile()
        +void delayMallocTrim()
        +void timerEvent(QTimerEvent *e)
        QList~Window*~ m_windows
        bool m_bIsTagDragging
        QBasicTimer m_FreeMemTimer
        Window *pFocusWindow
    }

    class Tabbar {
        +Tabbar(QWidget *parent)
        +bool eventFilter(QObject *object, QEvent *event)
        +void dropEvent(QDropEvent *event)
        +void resizeEvent(QResizeEvent *event)
        +QSize tabSizeHint(int index) const
        +QSize minimumTabSizeHint(int index) const
        +QSize maximumTabSizeHint(int index) const
        +void setAcceptDrops(bool on)
        +void setDragable(bool dragable)
        +void setVisibleAddButton(bool visible)
        +void setTabsClosable(bool closable)
        +void setTabPalette(QString normalColor, QString selectedColor)
        +signal tabCloseRequested(int index)
    }

    class EditWrapper {
        +bool isDraftFile() const
        +bool isModified() const
        +bool isTemFile() const
        +bool saveFile()
        +void saveDraftFile(QString newFilePath)
    }

    Window --> Tabbar : uses
    Window --> EditWrapper : manages m_wrappers
    StartManager --> Window : manages m_windows
    StartManager --> QBasicTimer : uses m_FreeMemTimer
Loading

File-Level Changes

Change Details Files
Introduce delayed heap memory trimming via StartManager and hook it into window/file lifecycle events.
  • Include <malloc.h> and add a QBasicTimer member to StartManager to schedule deferred memory freeing
  • Implement StartManager::delayMallocTrim() to start a one-shot timer and handle it in timerEvent() to call malloc_trim(0)
  • Invoke delayMallocTrim() after wrapper removal, after tabbar reload checks, and before final application quit to free heap memory after heavy operations
  • Guard autoBackupFile() to early-return when no windows are present
src/startmanager.cpp
src/startmanager.h
src/widgets/window.cpp
Add a save-all-files routine that prompts per-tab and integrate it into window close handling.
  • Add Window::saveAllFiles() to iterate over tabs, prompt the user to save modified files, and handle draft and temporary/backup files appropriately
  • Modify closeEvent() to call saveAllFiles() before backupFile(), aborting window close if the user cancels or dialog is closed
src/widgets/window.cpp
src/widgets/window.h
Improve shortcut popup positioning based on DTK version and tablet environment.
  • Wrap DGuiApplicationHelper::isTabletEnvironment() logic in a DTK version check
  • Fallback to using QGuiApplication::screenAt(QCursor::pos()) when DTK version is too old
src/widgets/window.cpp
Refine MIME type detection to be content-based.
  • Change isMimeTypeSupport() to use QMimeDatabase::mimeTypeForFile with MatchContent mode instead of default detection
src/common/utils.cpp
Enhance Tabbar usability with drag-and-drop acceptance and middle-click close behavior.
  • Enable drag-and-drop on the tab bar by calling setAcceptDrops(true)
  • Handle middle mouse button presses in eventFilter() to emit tabCloseRequested() for the clicked tab instead of relying on an overridden mousePressEvent
src/controls/tabbar.cpp
src/controls/tabbar.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link

  • 敏感词检查失败, 检测到1个文件存在敏感词
详情
{
    "src/widgets/window.cpp": [
        {
            "line": "    QString key = \"base/enable\";",
            "line_number": 388,
            "rule": "S106",
            "reason": "Var naming | 64f28539d9"
        }
    ]
}

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and found some issues that need to be addressed.

  • In Window::saveAllFiles(), the loop for (int i = wrappers.count() - 1; i > 0; i--) skips index 0 and uses m_wrappers instead of the copied wrappers; consider iterating down to i >= 0 and consistently using a single source of truth (e.g., m_wrappers only) to avoid missing the first tab and potential stale-map issues.
  • The early return false paths in saveAllFiles() for cases like empty filePath or missing wrapper will abort the entire save-all operation on one bad tab; if the intent is to save as many files as possible, switching these to continue (and maybe logging) would make the behavior more robust.
  • In StartManager::timerEvent, the existing auto-backup logic (m_pTimer) now runs for every timer event, including m_FreeMemTimer; it would be safer to structure this with separate if/else if branches per timerId so the malloc-trim timer doesn't inadvertently trigger or modify backup-related timers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Window::saveAllFiles()`, the loop `for (int i = wrappers.count() - 1; i > 0; i--)` skips index 0 and uses `m_wrappers` instead of the copied `wrappers`; consider iterating down to `i >= 0` and consistently using a single source of truth (e.g., `m_wrappers` only) to avoid missing the first tab and potential stale-map issues.
- The early `return false` paths in `saveAllFiles()` for cases like empty `filePath` or missing `wrapper` will abort the entire save-all operation on one bad tab; if the intent is to save as many files as possible, switching these to `continue` (and maybe logging) would make the behavior more robust.
- In `StartManager::timerEvent`, the existing auto-backup logic (`m_pTimer`) now runs for every timer event, including `m_FreeMemTimer`; it would be safer to structure this with separate `if/else if` branches per `timerId` so the malloc-trim timer doesn't inadvertently trigger or modify backup-related timers.

## Individual Comments

### Comment 1
<location> `src/widgets/window.cpp:2942-2946` </location>
<code_context>
     return true;
 }

+bool Window::saveAllFiles()
+{
+    qInfo() << "begin saveAllFiles()";
+    QMap<QString, EditWrapper *> wrappers = m_wrappers;
+    for (int i = wrappers.count() - 1; i > 0; i--) {
+        const QString &filePath = m_tabbar->fileAt(i);
+        // 避免异常情况重入时当前已无标签页的情况
</code_context>

<issue_to_address>
**issue (bug_risk):** Loop skips index 0, so the first tab is never processed during save-all.

Because the loop uses `i > 0`, index 0 is never visited, so the first tab is never checked or saved in `saveAllFiles()`. This can leave the leftmost file unsaved when closing. Please update the loop (e.g., `i >= 0` with a `wrappers.count() > 0` guard) or otherwise ensure index 0 is handled.
</issue_to_address>

### Comment 2
<location> `src/widgets/window.cpp:2958-2967` </location>
<code_context>
+        bool bIsBackupFile = false;
</code_context>

<issue_to_address>
**suggestion:** Backup and normal file branches duplicate logic and `bIsBackupFile` is unnecessary.

`bIsBackupFile` is only set from `wrapper->isTemFile()` and both branches run the same `if (!wrapper->saveFile()) { saveAsFile(); }` logic, so it doesn’t change behavior. Consider removing `bIsBackupFile` and merging the branches into a single `else` for simpler, clearer code.

Suggested implementation:

```cpp
        bool isDraftFile = wrapper->isDraftFile();
        bool isModified = wrapper->isModified();

        if (isModified) {

```

`bIsBackupFile` is likely used later in this same function to decide between a “backup file” branch and a “normal file” branch around the `saveFile` / `saveAsFile` calls. To fully implement your comment:
1. Find the `if (bIsBackupFile)` or similar conditional later in this function.
2. Replace that `if/else` with a single branch that executes the shared logic:
   - Call `wrapper->saveFile()`.
   - If it returns `false`, call `saveAsFile()` (or the existing equivalent).
3. Remove any remaining references to `bIsBackupFile` in this function, since the flag is now gone and behavior is unified.
</issue_to_address>

### Comment 3
<location> `src/controls/tabbar.cpp:751-755` </location>
<code_context>
             }
         }
-
+        if (mouseEvent->button() == Qt::MidButton) {
+            emit tabCloseRequested(tabAt(QPoint(mouseEvent->x(), mouseEvent->y())));
+            return true;
+        }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Middle-click close should guard against `tabAt` returning -1.

`tabAt(...)` may return -1 if the middle click is outside any tab, and that value will be propagated via `tabCloseRequested`. Some consumers may not handle negative indexes correctly. Please store the result of `tabAt(...)` in a local variable, emit the signal only when the index is >= 0, and use `mouseEvent->pos()` instead of constructing a `QPoint` from `x()`/`y()` manually.

```suggestion
        }
        if (mouseEvent->button() == Qt::MidButton) {
            const int index = tabAt(mouseEvent->pos());
            if (index >= 0) {
                emit tabCloseRequested(index);
            }
            return true;
        }
```
</issue_to_address>

### Comment 4
<location> `src/startmanager.cpp:176-177` </location>
<code_context>
     QFileInfo fileInfo;
     m_qlistTemFile.clear();
     listBackupInfo = Settings::instance()->settings->option("advance.editor.browsing_history_temfile")->value().toStringList();
+    if (m_windows.isEmpty()) {
+        return;
+    }
</code_context>

<issue_to_address>
**question (bug_risk):** Early return when `m_windows` is empty changes backup behavior for stored temp files.

This early return prevents `autoBackupFile` from reconciling `listBackupInfo` when there are no open windows, which may leave backup records stale if prior behavior depended on that cleanup. If the change is intentional, consider moving the early return before loading `listBackupInfo` to avoid the now-unnecessary read.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +2958 to +2967
bool bIsBackupFile = false;

if (wrapper->isTemFile()) {
bIsBackupFile = true;
}

if (isModified) {
DDialog *dialog = createDialog(tr("Do you want to save this file?"), "");
int res = dialog->exec();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Backup and normal file branches duplicate logic and bIsBackupFile is unnecessary.

bIsBackupFile is only set from wrapper->isTemFile() and both branches run the same if (!wrapper->saveFile()) { saveAsFile(); } logic, so it doesn’t change behavior. Consider removing bIsBackupFile and merging the branches into a single else for simpler, clearer code.

Suggested implementation:

        bool isDraftFile = wrapper->isDraftFile();
        bool isModified = wrapper->isModified();

        if (isModified) {

bIsBackupFile is likely used later in this same function to decide between a “backup file” branch and a “normal file” branch around the saveFile / saveAsFile calls. To fully implement your comment:

  1. Find the if (bIsBackupFile) or similar conditional later in this function.
  2. Replace that if/else with a single branch that executes the shared logic:
    • Call wrapper->saveFile().
    • If it returns false, call saveAsFile() (or the existing equivalent).
  3. Remove any remaining references to bIsBackupFile in this function, since the flag is now gone and behavior is unified.

@deepin-ci-robot
Copy link

deepin pr auto review

我来对这段代码进行审查,从语法逻辑、代码质量、性能和安全几个方面进行分析:

  1. utils.cpp 中的修改:
QString mimeType = QMimeDatabase().mimeTypeForFile(filepath, QMimeDatabase::MatchMode::MatchContent).name();

改进建议:

  • 这个改动是好的,使用 MatchContent 可以更准确地判断文件类型,而不是仅依赖文件扩展名
  • 但建议缓存 QMimeDatabase 实例,避免每次调用都创建新对象
  • 建议添加错误处理,当文件不存在或无法读取时应有适当的处理
  1. tabbar.cpp 中的修改:
setAcceptDrops(true);

if (mouseEvent->button() == Qt::MidButton) {
    emit tabCloseRequested(tabAt(QPoint(mouseEvent->x(), mouseEvent->y())));
    return true;
}

改进建议:

  • MidButton 关闭标签页的功能很好,但应该添加一个配置选项让用户可以禁用此功能
  • 建议添加视觉反馈,当用户使用中键点击时显示提示
  • 拖放功能需要添加更多的安全检查,防止恶意文件
  1. startmanager.cpp 中的修改:
void StartManager::delayMallocTrim()
{
    if (!m_FreeMemTimer.isActive()) {
        m_FreeMemTimer.start(1000, this);
    }
}

改进建议:

  • 内存优化是好的,但 malloc_trim 的使用需要谨慎,频繁调用可能影响性能
  • 建议添加条件判断,只在内存使用超过阈值时才触发
  • 1秒的延迟可能太短,建议根据实际情况调整
  1. window.cpp 中的修改:
bool Window::saveAllFiles()
{
    // ... 保存所有文件的逻辑
}

改进建议:

  • 保存逻辑存在性能问题,建议使用异步保存
  • 错误处理不够完善,应该添加更多的异常处理
  • 用户界面应该显示保存进度
  • 建议添加保存失败的重试机制
  1. 安全性建议:
  • 文件操作需要添加权限检查
  • 临时文件的处理需要更安全
  • 建议添加文件完整性检查
  • 需要防止路径遍历攻击
  1. 性能优化建议:
  • 文件操作建议使用异步方式
  • 大文件处理应该添加进度显示
  • 内存管理可以更精细化
  • 建议添加缓存机制
  1. 代码质量建议:
  • 添加更多的注释说明
  • 错误处理需要更完善
  • 建议添加更多的单元测试
  • 部分函数过长,建议拆分
  1. 其他建议:
  • 添加配置选项让用户可以自定义行为
  • 建议添加更多的日志记录
  • 考虑添加国际化支持
  • 建议添加更多的用户反馈机制

总体来说,这些修改主要是功能增强,但还需要在错误处理、性能优化和安全性方面做更多工作。建议优先处理安全性相关的问题,然后逐步完善其他方面。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, pppanghu77

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@pppanghu77
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Dec 18, 2025

This pr force merged! (status: unstable)

@deepin-bot deepin-bot bot merged commit c56b1c3 into linuxdeepin:master Dec 18, 2025
19 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants