| 8529 | } |
| 8530 | |
| 8531 | void MainWindow::closeEvent(QCloseEvent *event) { |
| 8532 | // ========== CHECK FOR UNSAVED DOCUMENTS ========== |
| 8533 | // Per-tab: silently persist ephemeral view state (edgeless last_position / |
| 8534 | // paged lastAccessedPage) via autosavePositionOnlyChange, then prompt only |
| 8535 | // when doc->modified reflects a real edit. This mirrors tabCloseAttempted, |
| 8536 | // so closing the app feels the same as closing individual tabs. |
| 8537 | // (syncAllDocumentPositions is intentionally NOT called here - it would |
| 8538 | // markModified every edgeless doc and force a prompt for harmless pans. |
| 8539 | // The mobile suspend hook still uses it, where that behavior is needed.) |
| 8540 | if (m_splitViewManager && m_documentManager) { |
| 8541 | auto checkPane = [&](TabManager* tm, TabBar* bar) -> bool { |
| 8542 | if (!tm) return true; |
| 8543 | for (int i = 0; i < tm->tabCount(); ++i) { |
| 8544 | Document* doc = tm->documentAt(i); |
| 8545 | if (!doc) continue; |
| 8546 | |
| 8547 | autosavePositionOnlyChange(doc, tm->viewportAt(i)); |
| 8548 | |
| 8549 | bool needsSavePrompt = false; |
| 8550 | bool isUsingTemp = m_documentManager->isUsingTempBundle(doc); |
| 8551 | |
| 8552 | if (doc->isEdgeless()) { |
| 8553 | bool hasContent = doc->tileCount() > 0 || doc->tileIndexCount() > 0; |
| 8554 | needsSavePrompt = doc->modified || (isUsingTemp && hasContent); |
| 8555 | } else { |
| 8556 | bool hasContent = doc->pageCount() > 0; |
| 8557 | needsSavePrompt = doc->modified || (isUsingTemp && hasContent); |
| 8558 | } |
| 8559 | |
| 8560 | if (needsSavePrompt) { |
| 8561 | if (bar) bar->setCurrentIndex(i); |
| 8562 | |
| 8563 | QString docType = doc->isEdgeless() ? tr("canvas") : tr("document"); |
| 8564 | QMessageBox::StandardButton reply = QMessageBox::question( |
| 8565 | this, |
| 8566 | tr("Save Changes?"), |
| 8567 | tr("The %1 \"%2\" has unsaved changes. Do you want to save before quitting?") |
| 8568 | .arg(docType) |
| 8569 | .arg(doc->displayName()), |
| 8570 | QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, |
| 8571 | QMessageBox::Save |
| 8572 | ); |
| 8573 | |
| 8574 | if (reply == QMessageBox::Cancel) { |
| 8575 | return false; |
| 8576 | } |
| 8577 | |
| 8578 | if (reply == QMessageBox::Save) { |
| 8579 | QString existingPath = m_documentManager->documentPath(doc); |
| 8580 | bool canSaveInPlace = !existingPath.isEmpty() && !isUsingTemp; |
| 8581 | |
| 8582 | if (canSaveInPlace) { |
| 8583 | if (!m_documentManager->saveDocument(doc)) { |
| 8584 | QMessageBox::critical(this, tr("Save Error"), |
| 8585 | tr("Failed to save document to:\n%1\n\nQuit anyway?").arg(existingPath)); |
| 8586 | } |
| 8587 | } else { |
| 8588 | if (!saveNewDocumentWithDialog(doc)) { |
nothing calls this directly
no test coverage detected