diff --git a/src/controls/tabbar.cpp b/src/controls/tabbar.cpp index 1cd425ba..5ef8df96 100644 --- a/src/controls/tabbar.cpp +++ b/src/controls/tabbar.cpp @@ -440,6 +440,7 @@ QPixmap Tabbar::createDragPixmapFromTab(int index, const QStyleOptionTab &option Window *window = static_cast(this->window()); EditWrapper *wrapper = window->wrapper(fileAt(index)); + if (!wrapper) return QPixmap(); //加载大文本不允许拖拽 //if(wrapper && wrapper->getFileLoading()) return QPixmap(); diff --git a/src/startmanager.cpp b/src/startmanager.cpp index a4f59384..f4aadff9 100644 --- a/src/startmanager.cpp +++ b/src/startmanager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2011-2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2011-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -291,7 +291,21 @@ int StartManager::recoverFile(Window *window) int windowIndex = -1; - //根据备份信息恢复文件 + // Struct to collect recovery entry info for two-pass approach + struct RecoverEntry { + Window *win; + QString openPath; + QString tabName; + QString truePath; + QString lastModifiedTime; + bool isTemFile; + bool isFocus; + bool hasTemFile; + QList bookmarks; + }; + QList entries; + + // First pass: collect all valid entries qDebug() << "Processing" << m_qlistTemFile.count() << "temporary files for recovery"; for (int i = 0; i < m_qlistTemFile.count(); i++) { QJsonParseError jsonError; @@ -367,84 +381,86 @@ int StartManager::recoverFile(Window *window) } } + // Determine if this is the focus tab + bool isFocusTab = false; + if (object.contains("focus")) { + QJsonValue value = object.value("focus"); + if (value.isBool() && value.toBool()) { + isFocusTab = true; + } + } + + // Parse bookmarks for later use + QList parsedBookmarks; + if (object.contains("bookMark")) { + QJsonValue value = object.value("bookMark"); + if (value.isString()) { + parsedBookmarks = analyzeBookmakeInfo(value.toString()); + } + } + //打开文件 if (!temFilePath.isEmpty()) { if (Utils::fileExists(temFilePath)) { - qDebug() << "Opening temporary file:" << temFilePath << "for" << fileInfo.fileName(); - window->addTemFileTab(temFilePath, fileInfo.fileName(), localPath, lastmodifiedtime, bIsTemFile); - - //打开文件后设置书签 - if (object.contains("bookMark")) { // 包含指定的 key - QJsonValue value = object.value("bookMark"); // 获取指定 key 对应的 value - - if (value.isString()) { - QList bookmarkList; - bookmarkList = analyzeBookmakeInfo(value.toString()); - qDebug() << "Setting bookmarks from file config:" << bookmarkList; - window->wrapper(temFilePath)->textEditor()->setBookMarkList(bookmarkList); - } - } else if (m_bookmarkTable.contains(temFilePath)) { - // 若文件已有配置,则以文件为准,否则以全局配置为准 - qDebug() << "Setting bookmarks from global config for:" << temFilePath; - window->wrapper(localPath)->textEditor()->setBookMarkList(m_bookmarkTable.value(temFilePath)); - } - - if (object.contains("focus")) { // 包含指定的 key - QJsonValue value = object.value("focus"); // 获取指定 key 对应的 value + qDebug() << "Collecting temporary file:" << temFilePath << "for" << fileInfo.fileName(); - if (value.isBool() && value.toBool()) { - qDebug() << "Setting focus to file:" << temFilePath; - pFocusWindow = window; - focusPath = temFilePath; - } + if (isFocusTab) { + qDebug() << "Setting focus to file:" << temFilePath; + pFocusWindow = window; + focusPath = temFilePath; } + RecoverEntry entry; + entry.win = window; + entry.openPath = temFilePath; + entry.tabName = fileInfo.fileName(); + entry.truePath = localPath; + entry.lastModifiedTime = lastmodifiedtime; + entry.isTemFile = bIsTemFile; + entry.isFocus = isFocusTab; + entry.hasTemFile = true; + entry.bookmarks = parsedBookmarks; + entries.append(entry); + recFilesSum++; } } else { if (!localPath.isEmpty() && Utils::fileExists(localPath)) { - qDebug() << "Opening local file:" << localPath; + qDebug() << "Collecting local file:" << localPath; + QString tabName; // 若为草稿文件或不支持的MIMETYPE文件,显示默认名称标签 if (Utils::isDraftFile(localPath) || !Utils::isMimeTypeSupport(localPath)) { //得到新建文件名称 int index = files.indexOf(QFileInfo(localPath).fileName()); - if (index >= 0) { - QString fileName = tr("Untitled %1").arg(index + 1); - qDebug() << "Using untitled name for draft file:" << fileName; - window->addTemFileTab(localPath, fileName, localPath, lastmodifiedtime, bIsTemFile); - + tabName = tr("Untitled %1").arg(index + 1); + qDebug() << "Using untitled name for draft file:" << tabName; + } else { + qDebug() << "Skipping draft file, not in file list:" << localPath; + continue; } } else { - qDebug() << "Using file name for regular file:" << fileInfo.fileName(); - window->addTemFileTab(localPath, fileInfo.fileName(), localPath, lastmodifiedtime, bIsTemFile); + tabName = fileInfo.fileName(); + qDebug() << "Using file name for regular file:" << tabName; } - //打开文件后设置书签 - if (object.contains("bookMark")) { // 包含指定的 key - QJsonValue value = object.value("bookMark"); // 获取指定 key 对应的 value - - if (value.isString()) { - QList bookmarkList; - bookmarkList = analyzeBookmakeInfo(value.toString()); - qDebug() << "Setting bookmarks from file config:" << bookmarkList; - window->wrapper(localPath)->textEditor()->setBookMarkList(bookmarkList); - } - } else if (m_bookmarkTable.contains(localPath)) { - // 若文件已有配置,则以文件为准,否则以全局配置为准 - qDebug() << "Setting bookmarks from global config for:" << localPath; - window->wrapper(localPath)->textEditor()->setBookMarkList(m_bookmarkTable.value(localPath)); + if (isFocusTab) { + qDebug() << "Setting focus to file:" << localPath; + pFocusWindow = window; + focusPath = localPath; } - if (object.contains("focus")) { // 包含指定的 key - QJsonValue value = object.value("focus"); // 获取指定 key 对应的 value - - if (value.isBool() && value.toBool()) { - qDebug() << "Setting focus to file:" << localPath; - pFocusWindow = window; - focusPath = localPath; - } - } + RecoverEntry entry; + entry.win = window; + entry.openPath = localPath; + entry.tabName = tabName; + entry.truePath = localPath; + entry.lastModifiedTime = lastmodifiedtime; + entry.isTemFile = bIsTemFile; + entry.isFocus = isFocusTab; + entry.hasTemFile = false; + entry.bookmarks = parsedBookmarks; + entries.append(entry); recFilesSum++; } @@ -455,6 +471,26 @@ int StartManager::recoverFile(Window *window) } } + // Second pass: create tabs - focus tab gets full load, others get lazy load + for (const RecoverEntry &entry : entries) { + if (entry.isFocus) { + // Focus tab: fully load with addTemFileTab + entry.win->addTemFileTab(entry.openPath, entry.tabName, entry.truePath, entry.lastModifiedTime, entry.isTemFile); + + // Set bookmarks on the just-loaded wrapper + if (!entry.bookmarks.isEmpty()) { + qDebug() << "Setting bookmarks from file config:" << entry.bookmarks; + entry.win->wrapper(entry.openPath)->textEditor()->setBookMarkList(entry.bookmarks); + } else if (m_bookmarkTable.contains(entry.truePath)) { + qDebug() << "Setting bookmarks from global config for:" << entry.truePath; + entry.win->wrapper(entry.openPath)->textEditor()->setBookMarkList(m_bookmarkTable.value(entry.truePath)); + } + } else { + // Non-focus tab: lazy load (tabbar button only) + entry.win->addTabLazy(entry.openPath, entry.tabName, entry.truePath); + } + } + //当前活动页 if (pFocusWindow != nullptr && !focusPath.isNull()) { qDebug() << "Setting focus to window and tab for path:" << focusPath; @@ -598,8 +634,9 @@ void StartManager::openFilesInTab(QStringList files) else { qDebug() << "Opening file in first existing window"; Window *window = m_windows[0]; - window->addTab(canonicalFile); - qDebug() << "Added tab for file:" << canonicalFile << "in existing window"; + // Lazy load: only add tab button, defer EditWrapper creation until tab is activated + window->addTabLazy(canonicalFile, QFileInfo(canonicalFile).fileName(), canonicalFile); + qDebug() << "Added lazy tab for file:" << canonicalFile << "in existing window"; //window->setWindowState(Qt::WindowActive); //通过dbus接口从任务栏激活窗口 if (!Q_LIKELY(Utils::activeWindowFromDock(window->winId()))) { diff --git a/src/widgets/window.cpp b/src/widgets/window.cpp index 458f705d..592ff306 100644 --- a/src/widgets/window.cpp +++ b/src/widgets/window.cpp @@ -837,6 +837,20 @@ bool Window::closeTab() bool Window::closeTab(const QString &filePath) { qDebug() << "Enter closeTab with path:" << filePath; + + if (m_unloadedTabs.contains(filePath)) { + qDebug() << "Closing unloaded tab:" << filePath; + m_unloadedTabs.remove(filePath); + int idx = m_tabbar->indexOf(filePath); + if (idx >= 0) { + m_tabbar->closeTab(idx); + } + if (m_wrappers.isEmpty() && m_unloadedTabs.isEmpty()) { + close(); + } + return true; + } + EditWrapper *wrapper = m_wrappers.value(filePath); if (!wrapper) { qWarning() << "No wrapper found for path:" << filePath; @@ -1144,11 +1158,10 @@ void Window::focusActiveEditor() { qDebug() << "Enter focusActiveEditor"; if (m_tabbar->count() > 0) { - if (currentWrapper() == nullptr) { - qDebug() << "No current wrapper, adding blank tab"; - return; + EditWrapper *wrapper = currentWrapper(); + if (wrapper && wrapper->textEditor()) { + wrapper->textEditor()->setFocus(); } - currentWrapper()->textEditor()->setFocus(); } qDebug() << "Exit focusActiveEditor"; } @@ -1176,7 +1189,7 @@ void Window::removeWrapper(const QString &filePath, bool isDelete) } // Exit window after close all tabs. - if (m_wrappers.isEmpty()) { + if (m_wrappers.isEmpty() && m_unloadedTabs.isEmpty()) { close(); qInfo() << "after close"; } @@ -1304,9 +1317,10 @@ bool Window::saveFile() if (success) { updateSabeAsFileNameTemp(temPath, filePath); - if (currentWrapper()) { + EditWrapper *curWrapper = currentWrapper(); + if (curWrapper) { qDebug() << "Saved successfully, updating save as file name"; - currentWrapper()->hideWarningNotices(); + curWrapper->hideWarningNotices(); } showNotify(tr("Saved successfully")); @@ -1703,8 +1717,8 @@ void Window::popupFindBar() QString tabPath = m_tabbar->currentPath(); EditWrapper *wrapper = currentWrapper(); - if (currentWrapper() == nullptr) { - qDebug() << "No current wrapper, cannot popup find bar"; + if (!wrapper || !wrapper->textEditor()) { + qDebug() << "No valid current wrapper, cannot popup find bar"; return; } @@ -1713,7 +1727,7 @@ void Window::popupFindBar() return; } - currentWrapper()->bottomBar()->updateSize(m_findBar->height() + 8, true); + wrapper->bottomBar()->updateSize(m_findBar->height() + 8, true); if (m_replaceBar->isVisible()) { qDebug() << "Hiding replace bar before showing find bar"; @@ -1742,29 +1756,29 @@ void Window::popupFindBar() void Window::popupReplaceBar() { qDebug() << "Enter popupReplaceBar"; - if (currentWrapper() == nullptr) { - qDebug() << "No current wrapper, cannot popup replace bar"; + EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qDebug() << "No valid current wrapper, cannot popup replace bar"; return; } - if (currentWrapper()->textEditor()->document()->isEmpty()) { + if (wrapper->textEditor()->document()->isEmpty()) { qDebug() << "Current document is empty, cannot popup replace bar"; return; } - if (currentWrapper() && currentWrapper()->getFileLoading()) { + if (wrapper->getFileLoading()) { qDebug() << "File is loading, cannot popup replace bar"; return; } - QTextCursor cursor = currentWrapper()->textEditor()->textCursor(); + QTextCursor cursor = wrapper->textEditor()->textCursor(); m_replaceBar->setsearched(false); - EditWrapper *curWrapper = currentWrapper(); - bool bIsReadOnly = curWrapper->textEditor()->getReadOnlyMode(); + bool bIsReadOnly = wrapper->textEditor()->getReadOnlyMode(); if (cursor.hasSelection()) { - currentWrapper()->textEditor()->setCursorStart(cursor.selectionStart()); + wrapper->textEditor()->setCursorStart(cursor.selectionStart()); qDebug() << "Replace bar: selected"; } @@ -1774,9 +1788,8 @@ void Window::popupReplaceBar() return; } - currentWrapper()->bottomBar()->updateSize(m_replaceBar->height() + 8, true); + wrapper->bottomBar()->updateSize(m_replaceBar->height() + 8, true); - EditWrapper *wrapper = currentWrapper(); if (m_findBar->isVisible()) { m_findBar->hide(); qDebug() << "Hiding find bar before showing replace bar"; @@ -2139,15 +2152,20 @@ void Window::rehighlightPrintDoc(QTextDocument *doc, CSyntaxHighlighter *highlig void Window::updateSizeMode() { qDebug() << "Update size mode"; + EditWrapper *wrapper = currentWrapper(); if (m_findBar && m_findBar->isVisible()) { qDebug() << "Find bar is visible, updating its position"; - currentWrapper()->bottomBar()->updateSize(m_findBar->height() + 8, true); + if (wrapper && wrapper->bottomBar()) { + wrapper->bottomBar()->updateSize(m_findBar->height() + 8, true); + } m_findBar->move(QPoint(4, height() - m_findBar->height() - 4)); } if (m_replaceBar && m_replaceBar->isVisible()) { qDebug() << "Replace bar is visible, updating its position"; - currentWrapper()->bottomBar()->updateSize(m_replaceBar->height() + 8, true); + if (wrapper && wrapper->bottomBar()) { + wrapper->bottomBar()->updateSize(m_replaceBar->height() + 8, true); + } m_replaceBar->move(QPoint(4, height() - m_replaceBar->height() - 4)); } @@ -2157,8 +2175,15 @@ void Window::updateSizeMode() void Window::popupPrintDialog() { qDebug() << "Enter popupPrintDialog"; + + EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "No valid current wrapper, cannot print"; + return; + } + //大文本加载过程不允许打印操作 - if (currentWrapper() && currentWrapper()->getFileLoading()) { + if (wrapper->getFileLoading()) { qDebug() << "File is loading, cannot print"; return; } @@ -2169,7 +2194,7 @@ void Window::popupPrintDialog() return; } - const QString &filePath = currentWrapper()->textEditor()->getFilePath(); + const QString &filePath = wrapper->textEditor()->getFilePath(); const QString &fileDir = QFileInfo(filePath).dir().absolutePath(); qInfo() << qPrintable("Start print doc"); @@ -2179,10 +2204,10 @@ void Window::popupPrintDialog() || (DTK_VERSION_MAJOR == 5 && DTK_VERSION_MINOR > 4) \ || (DTK_VERSION_MAJOR == 5 && DTK_VERSION_MINOR == 4 && DTK_VERSION_PATCH >= 10)) - QTextDocument *doc = currentWrapper()->textEditor()->document(); + QTextDocument *doc = wrapper->textEditor()->document(); m_bLargePrint = false; m_bPrintProcessing = false; - m_printWrapper = currentWrapper(); + m_printWrapper = wrapper; m_multiDocPageCount = 0; if (doc != nullptr && !doc->isEmpty()) { @@ -2190,8 +2215,8 @@ void Window::popupPrintDialog() static const int s_maxDirectReadLen = 1024 * 1024 * 10; static const int s_maxHighlighterDirectReadLen = 1024 * 1024 * 5; // 判断是否需要文本高亮,文本数据量大小,不同数据量使用不同分支。 - bool needHighlighter = currentWrapper()->getSyntaxHighlighter() - && currentWrapper()->getSyntaxHighlighter()->definition().isValid(); + bool needHighlighter = wrapper->getSyntaxHighlighter() + && wrapper->getSyntaxHighlighter()->definition().isValid(); if (needHighlighter && doc->characterCount() > s_maxHighlighterDirectReadLen) { @@ -2204,7 +2229,7 @@ void Window::popupPrintDialog() m_bLargePrint = true; qInfo() << qPrintable("Clone large print document without highlighting"); } else { - currentWrapper()->updateHighlighterAll(); + wrapper->updateHighlighterAll(); m_printDoc = doc->clone(doc); qInfo() << qPrintable("Clone small print document"); } @@ -2213,7 +2238,7 @@ void Window::popupPrintDialog() if (m_bLargePrint) { qInfo() << qPrintable("Clone large print document"); // 克隆大文本数据 - if (!cloneLargeDocument(currentWrapper())) { + if (!cloneLargeDocument(wrapper)) { qWarning() << "Failed to clone large document for printing!"; return; } @@ -2241,7 +2266,7 @@ void Window::popupPrintDialog() m_pPreview->setDocName(docName); } else { qInfo() << qPrintable("Print file: ") << filePath; - QString path = currentWrapper()->textEditor()->getTruePath(); + QString path = wrapper->textEditor()->getTruePath(); QString docName = QFileInfo(path).baseName(); qInfo() << __func__ << "print normal file, docName:" << docName; m_pPreview->setDocName(docName); @@ -2282,10 +2307,10 @@ void Window::popupPrintDialog() } else { printer->setDocName(QString(QFileInfo(filePath).baseName())); } - currentWrapper()->textEditor()->print(printer); + wrapper->textEditor()->print(printer); }); - currentWrapper()->updateHighlighterAll(); + wrapper->updateHighlighterAll(); preview.exec(); #endif @@ -2317,13 +2342,17 @@ void Window::remberPositionSave() { qDebug() << "Enter remberPositionSave"; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "No valid current wrapper, cannot save position"; + return; + } m_remberPositionFilePath = m_tabbar->currentPath(); m_remberPositionRow = wrapper->textEditor()->getCurrentLine(); m_remberPositionColumn = wrapper->textEditor()->getCurrentColumn(); m_remberPositionScrollOffset = wrapper->textEditor()->getScrollOffset(); - currentWrapper()->showNotify(tr("Current location remembered")); + wrapper->showNotify(tr("Current location remembered")); qDebug() << "Exit remberPositionSave"; } @@ -2528,14 +2557,15 @@ void Window::doPrint(DPrinter *printer, const QVector &pageRange) (void)m_printDoc->documentLayout(); // make sure that there is a layout - if (currentWrapper() == nullptr) { - qDebug() << "Current wrapper is null"; + EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qDebug() << "No valid current wrapper"; return; } - QColor background = currentWrapper()->textEditor()->palette().color(QPalette::Base); + QColor background = wrapper->textEditor()->palette().color(QPalette::Base); bool backgroundIsDark = background.value() < 128; //对文本进行分页处理 - for (QTextBlock srcBlock = currentWrapper()->textEditor()->document()->firstBlock(), dstBlock = m_printDoc->firstBlock(); + for (QTextBlock srcBlock = wrapper->textEditor()->document()->firstBlock(), dstBlock = m_printDoc->firstBlock(); srcBlock.isValid() && dstBlock.isValid(); srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) { QVector formatList = srcBlock.layout()->formats(); @@ -2906,6 +2936,30 @@ void Window::backupFile() m_qlistTemFile.replace(tabInfo.tabIndex, byteArray); } + // Record unloaded tabs with minimal JSON entries (path only, no cursor/content) + for (const QString &path : m_unloadedTabs) { + QJsonObject jsonObject; + QString truePath = m_tabbar->truePathAt(m_tabbar->indexOf(path)); + QString effectivePath = truePath.isEmpty() ? path : truePath; + jsonObject.insert("localPath", effectivePath); + if (path == m_tabbar->currentPath()) { + jsonObject.insert("focus", true); + } + // Save bookmarks from global bookmark table for unloaded tabs + QList bookmarkInfo = StartManager::instance()->findBookmark(effectivePath); + if (!bookmarkInfo.isEmpty()) { + QString bookmarkStr; + for (int i = 0; i < bookmarkInfo.size(); i++) { + if (i > 0) bookmarkStr += ","; + bookmarkStr += QString::number(bookmarkInfo[i]); + } + jsonObject.insert("bookMark", bookmarkStr); + } + QJsonDocument document; + document.setObject(jsonObject); + m_qlistTemFile.append(document.toJson(QJsonDocument::Compact)); + } + //将json串列表写入配置文件 m_settings->settings->option("advance.editor.browsing_history_temfile")->setValue(m_qlistTemFile); @@ -2921,6 +2975,18 @@ void Window::backupFile() bool Window::closeAllFiles() { qInfo() << "begin closeAllFiles()"; + + // Close unloaded tabs from back to front to avoid index shifting issues + QStringList unloadedList = m_unloadedTabs.values(); + for (int i = unloadedList.count() - 1; i >= 0; i--) { + const QString &path = unloadedList[i]; + int idx = m_tabbar->indexOf(path); + if (idx >= 0) { + m_tabbar->closeTab(idx); + } + } + m_unloadedTabs.clear(); + QMap wrappers = m_wrappers; // 被删除的窗口索引已变更,需要计算其范围 @@ -2989,6 +3055,63 @@ bool Window::saveAllFloatingFiles() * @param qstrTruePath 最后一次修改时间 * @param bIsTemFile 是否修改 */ +void Window::addTabLazy(const QString &filePath, const QString &tabName, const QString &truePath) +{ + qDebug() << "Enter addTabLazy, filePath:" << filePath; + QString name = tabName.isEmpty() ? QFileInfo(filePath).fileName() : tabName; + m_tabbar->addTab(filePath, name, truePath); + m_unloadedTabs.insert(filePath); + qDebug() << "Exit addTabLazy"; +} + +bool Window::ensureTabLoaded(const QString &filePath) +{ + qDebug() << "Enter ensureTabLoaded, filePath:" << filePath; + if (!m_unloadedTabs.contains(filePath)) { + qDebug() << "File not in unloaded tabs, already loaded or unknown"; + return true; + } + + m_unloadedTabs.remove(filePath); + + QFileInfo fi(filePath); + if (!fi.exists()) { + qWarning() << "File does not exist:" << filePath; + int idx = m_tabbar->indexOf(filePath); + if (idx >= 0) { + m_tabbar->closeTab(idx); + } + return false; + } + + // Handle unsupported MIME type - show warning but keep tab open + if (!Utils::isMimeTypeSupport(fi.absoluteFilePath())) { + qWarning() << "MIME type not supported:" << filePath; + QString strFileName = fi.fileName(); + QString msg = tr("Invalid file: %1").arg(strFileName); + if (m_editorWidget && m_editorWidget->currentWidget()) { + msg = Utils::lineFeed(msg, m_editorWidget->currentWidget()->width() - FLOATTIP_MARGIN, + m_editorWidget->currentWidget()->font(), 2); + DMessageManager::instance()->sendMessage(m_editorWidget->currentWidget(), + QIcon(":/images/warning.svg"), msg); + } + return true; // Return true to indicate handling complete, tab remains open + } + + // Get truePath from tabbar for bookmark lookup + int tabIndex = m_tabbar->indexOf(filePath); + QString truePath = (tabIndex >= 0) ? m_tabbar->truePathAt(tabIndex) : filePath; + + EditWrapper *wrapper = createEditor(); + wrapper->openFile(filePath, truePath); + auto bookmarkInfo = StartManager::instance()->findBookmark(truePath); + wrapper->textEditor()->setBookMarkList(bookmarkInfo); + m_wrappers[filePath] = wrapper; + showNewEditor(wrapper); + qDebug() << "Exit ensureTabLoaded, loaded:" << filePath << "truePath:" << truePath; + return true; +} + void Window::addTemFileTab(const QString &qstrPath, const QString &qstrName, const QString &qstrTruePath, const QString &lastModifiedTime, bool bIsTemFile) { qInfo() << "begin addTemFileTab()"; @@ -3180,14 +3303,27 @@ void Window::handleCurrentChanged(const int &index) wrapper->textEditor()->removeKeywords(); } - if (currentWrapper()) { + EditWrapper *curWrapper = currentWrapper(); + if (curWrapper) { qDebug() << "current wrapper is not null"; - currentWrapper()->checkForReload(); + curWrapper->checkForReload(); checkTabbarForReload(); } const QString &filepath = m_tabbar->fileAt(index); + if (m_unloadedTabs.contains(filepath)) { + if (!ensureTabLoaded(filepath)) { + qWarning() << "Failed to load tab:" << filepath; + // Tab was closed due to file not existing or unsupported MIME type + // Find another valid tab to display + if (m_tabbar->count() > 0) { + m_tabbar->setCurrentIndex(0); + } + return; + } + } + if (m_wrappers.contains(filepath)) { bool bIsContains = false; EditWrapper *wrapper = m_wrappers.value(filepath); @@ -3217,8 +3353,11 @@ void Window::handleCurrentChanged(const int &index) if (currentWrapper() != nullptr) { qDebug() << "current wrapper is not null, show bottom bar"; - currentWrapper()->bottomBar()->show(); - currentWrapper()->bottomBar()->updateSize(BottomBar::defaultHeight(), false); + EditWrapper *curWrapper = currentWrapper(); + if (curWrapper->bottomBar()) { + curWrapper->bottomBar()->show(); + curWrapper->bottomBar()->updateSize(BottomBar::defaultHeight(), false); + } } qDebug() << "handleCurrentChanged end"; } @@ -3226,9 +3365,10 @@ void Window::handleCurrentChanged(const int &index) void Window::handleJumpLineBarExit() { qDebug() << "handleJumpLineBarExit"; - if (currentWrapper() != nullptr) { + EditWrapper *wrapper = currentWrapper(); + if (wrapper && wrapper->textEditor()) { qDebug() << "current wrapper is not null"; - QTimer::singleShot(0, currentWrapper()->textEditor(), SLOT(setFocus())); + QTimer::singleShot(0, wrapper->textEditor(), SLOT(setFocus())); } qDebug() << "handleJumpLineBarExit end"; } @@ -3279,6 +3419,10 @@ void Window::handleFindKeyword(const QString &keyword, bool state) { qDebug() << "handleFindKeyword" << keyword << state; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "handleFindKeyword: no valid current wrapper"; + return; + } m_keywordForSearch = keyword; wrapper->textEditor()->saveMarkStatus(); wrapper->textEditor()->updateCursorKeywordSelection(m_keywordForSearch, state); @@ -3306,6 +3450,10 @@ void Window::slotFindbarClose() { qDebug() << "slotFindbarClose"; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "slotFindbarClose: no valid current wrapper"; + return; + } if (wrapper->bottomBar()->isHidden()) { qDebug() << "bottom bar is hidden, show it"; @@ -3313,8 +3461,8 @@ void Window::slotFindbarClose() } wrapper->bottomBar()->updateSize(BottomBar::defaultHeight(), false); - currentWrapper()->textEditor()->setFocus(); - currentWrapper()->textEditor()->tellFindBarClose(); + wrapper->textEditor()->setFocus(); + wrapper->textEditor()->tellFindBarClose(); qDebug() << "slotFindbarClose end"; } @@ -3322,6 +3470,10 @@ void Window::slotReplacebarClose() { qDebug() << "slotReplacebarClose"; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "slotReplacebarClose: no valid current wrapper"; + return; + } if (wrapper->bottomBar()->isHidden()) { qDebug() << "bottom bar is hidden, show it"; @@ -3329,8 +3481,8 @@ void Window::slotReplacebarClose() } wrapper->bottomBar()->updateSize(BottomBar::defaultHeight(), false); - currentWrapper()->textEditor()->setFocus(); - currentWrapper()->textEditor()->tellFindBarClose(); + wrapper->textEditor()->setFocus(); + wrapper->textEditor()->tellFindBarClose(); qDebug() << "slotReplacebarClose end"; } @@ -3396,6 +3548,10 @@ void Window::handleReplaceAll(const QString &replaceText, const QString &withTex { qDebug() << "handleReplaceAll" << replaceText << withText; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "handleReplaceAll: no valid current wrapper"; + return; + } wrapper->textEditor()->replaceAll(replaceText, withText); qDebug() << "handleReplaceAll end"; } @@ -3407,6 +3563,10 @@ void Window::handleReplaceNext(const QString &file, const QString &replaceText, m_keywordForSearch = replaceText; m_keywordForSearchAll = replaceText; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "handleReplaceNext: no valid current wrapper"; + return; + } wrapper->textEditor()->replaceNext(replaceText, withText); qDebug() << "handleReplaceNext end"; } @@ -3415,6 +3575,10 @@ void Window::handleReplaceRest(const QString &replaceText, const QString &withTe { qDebug() << "handleReplaceRest" << replaceText << withText; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "handleReplaceRest: no valid current wrapper"; + return; + } wrapper->textEditor()->replaceRest(replaceText, withText); qDebug() << "handleReplaceRest end"; } @@ -3423,6 +3587,10 @@ void Window::handleReplaceSkip(QString file, QString keyword) { qDebug() << "handleReplaceSkip" << file << keyword; EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "handleReplaceSkip: no valid current wrapper"; + return; + } handleUpdateSearchKeyword(m_replaceBar, file, keyword, Qt::CaseSensitive); if (QString::compare(m_keywordForSearch, m_keywordForSearchAll, Qt::CaseInsensitive) != 0) { m_keywordForSearchAll.clear(); @@ -3443,9 +3611,10 @@ void Window::handleReplaceSkip(QString file, QString keyword) void Window::handleRemoveSearchKeyword() { qDebug() << "handleRemoveSearchKeyword"; - if (currentWrapper() != nullptr) { + EditWrapper *wrapper = currentWrapper(); + if (wrapper && wrapper->textEditor()) { qDebug() << "remove keywords"; - currentWrapper()->textEditor()->removeKeywords(); + wrapper->textEditor()->removeKeywords(); } qDebug() << "handleRemoveSearchKeyword end"; } @@ -3549,7 +3718,10 @@ void Window::showNotify(const QString &message, bool warning) qDebug() << "current wrapper is null"; this->addBlankTab(); } - currentWrapper()->showNotify(message, warning); + EditWrapper *wrapper = currentWrapper(); + if (wrapper) { + wrapper->showNotify(message, warning); + } qDebug() << "show notify end"; } @@ -3666,14 +3838,22 @@ void Window::slot_saveReadingPath() { qDebug() << "slot save reading path"; m_reading_list.clear(); - m_reading_list.append(currentWrapper()->textEditor()); + EditWrapper *wrapper = currentWrapper(); + if (wrapper && wrapper->textEditor()) { + m_reading_list.append(wrapper->textEditor()); + } qDebug() << "slot save reading path end"; } void Window::slot_beforeReplace(QString _) { qDebug() << "slot before replace"; - currentWrapper()->textEditor()->beforeReplace(_); + EditWrapper *wrapper = currentWrapper(); + if (!wrapper || !wrapper->textEditor()) { + qWarning() << "slot_beforeReplace: no valid current wrapper"; + return; + } + wrapper->textEditor()->beforeReplace(_); } void Window::slot_setTitleFocus() @@ -3704,7 +3884,10 @@ void Window::slot_setTitleFocus() QWidget::setTabOrder(minBtn, quitFullBtn); QWidget::setTabOrder(quitFullBtn, maxBtn); QWidget::setTabOrder(maxBtn, closeBtn); - currentWrapper()->bottomBar()->setChildrenFocus(true, closeBtn); + EditWrapper *wrapper = currentWrapper(); + if (wrapper && wrapper->bottomBar()) { + wrapper->bottomBar()->setChildrenFocus(true, closeBtn); + } qDebug() << "slot set title focus end"; } @@ -3865,12 +4048,13 @@ void Window::slotSigChangeWindowSize(QString mode) void Window::handleFocusWindowChanged(QWindow *w) { qDebug() << "handle focus window changed"; - if (windowHandle() != w || !currentWrapper() || !isActiveWindow()) { + EditWrapper *wrapper = currentWrapper(); + if (windowHandle() != w || !wrapper || !isActiveWindow()) { qDebug() << "handle focus window changed return"; return; } - currentWrapper()->checkForReload(); + wrapper->checkForReload(); checkTabbarForReload(); qDebug() << "handle focus window changed end"; } @@ -3969,6 +4153,7 @@ void Window::resizeEvent(QResizeEvent *e) void Window::closeEvent(QCloseEvent *e) { qDebug() << "close event"; + m_unloadedTabs.clear(); PerformanceMonitor::closeAppStart(); if (StartManager::instance()->isMultiWindow()) { @@ -4050,10 +4235,11 @@ void Window::closeEvent(QCloseEvent *e) void Window::hideEvent(QHideEvent *event) { qDebug() << "hide event"; + EditWrapper *wrapper = currentWrapper(); if (this->isVisible()) { qDebug() << "hide event is visible"; - if (currentWrapper() != nullptr) { - currentWrapper()->textEditor()->setFocus(); + if (wrapper && wrapper->textEditor()) { + wrapper->textEditor()->setFocus(); qDebug() << "hide event set focus"; } } @@ -4061,8 +4247,8 @@ void Window::hideEvent(QHideEvent *event) if (m_findBar->isVisible()) { qDebug() << "hide event hide find bar"; // m_findBar->hide(); - if (currentWrapper() != nullptr) { - currentWrapper()->bottomBar()->show(); + if (wrapper && wrapper->bottomBar()) { + wrapper->bottomBar()->show(); qDebug() << "hide event show bottom bar"; } } @@ -4072,8 +4258,8 @@ void Window::hideEvent(QHideEvent *event) if (m_replaceBar->isVisible()) { qDebug() << "hide event hide replace bar"; //m_replaceBar->hide(); - if (currentWrapper() != nullptr) { - currentWrapper()->m_bottomBar->show(); + if (wrapper) { + wrapper->m_bottomBar->show(); } } #endif @@ -4085,10 +4271,13 @@ void Window::keyPressEvent(QKeyEvent *e) QString key = Utils::getKeyshortcut(e); qDebug() << "key press event" << key; + EditWrapper *wrapper = currentWrapper(); if (key == Utils::getKeyshortcutFromKeymap(m_settings, "window", "decrementfontsize") || key == Utils::getKeyshortcutFromKeymap(m_settings, "window", "incrementfontsize") || key == Utils::getKeyshortcutFromKeymap(m_settings, "window", "togglefullscreen")) { - currentWrapper()->textEditor()->setCodeFoldWidgetHide(true); + if (wrapper && wrapper->textEditor()) { + wrapper->textEditor()->setCodeFoldWidgetHide(true); + } qDebug() << "key press event toggle full screen"; } diff --git a/src/widgets/window.h b/src/widgets/window.h index b3a36d23..69d49702 100644 --- a/src/widgets/window.h +++ b/src/widgets/window.h @@ -68,6 +68,8 @@ class Window : public DMainWindow void addTab(const QString &filepath, bool activeTab = false); void addTabWithWrapper(EditWrapper *wrapper, const QString &filepath, const QString &qstrTruePath, const QString &tabName, int index = -1); + void addTabLazy(const QString &filePath, const QString &tabName, const QString &truePath = ""); + bool ensureTabLoaded(const QString &filePath); bool closeTab(); bool closeTab(const QString &fileName); void restoreTab(); @@ -261,6 +263,7 @@ public Q_SLOTS: Settings *m_settings {nullptr}; QMap m_wrappers; + QSet m_unloadedTabs; DMenu *m_menu {nullptr};