diff --git a/src/control/Control.cpp b/src/control/Control.cpp index eb27eff8..52f7f94c 100644 --- a/src/control/Control.cpp +++ b/src/control/Control.cpp @@ -2232,7 +2232,7 @@ bool Control::newFile(string pageTemplate) { XOJ_CHECK_TYPE(Control); - if (!this->close()) + if (!this->close(true)) { return false; } @@ -2292,7 +2292,7 @@ bool Control::openFile(Path filename, int scrollToPage, bool forceOpen) return false; } - if (!this->close()) + if (!this->close(false)) { return false; } @@ -2316,6 +2316,8 @@ bool Control::openFile(Path filename, int scrollToPage, bool forceOpen) } } + this->closeDocument(); + // Read template file if (filename.hasExtension(".xopt")) { @@ -2535,7 +2537,7 @@ bool Control::annotatePdf(Path filename, bool attachPdf, bool attachToDocument) { XOJ_CHECK_TYPE(Control); - if (!this->close()) + if (!this->close(false)) { return false; } @@ -2550,6 +2552,8 @@ bool Control::annotatePdf(Path filename, bool attachPdf, bool attachToDocument) } } + this->closeDocument(); + getCursor()->setCursorBusy(true); this->doc->setFilename(""); @@ -2675,6 +2679,7 @@ bool Control::save(bool synchron) { result = job->save(); unblock(); + this->resetSavedStatus(); } else { @@ -2843,11 +2848,22 @@ bool Control::saveAs() return save(); } +void Control::resetSavedStatus() +{ + this->doc->lock(); + Path filename = this->doc->getFilename(); + this->doc->unlock(); + + this->undoRedo->documentSaved(); + this->recent->addRecentFileFilename(filename); + this->updateWindowTitle(); +} + void Control::quit(bool allowCancel) { XOJ_CHECK_TYPE(Control); - if (!this->close(true, allowCancel)) + if (!this->close(false, allowCancel)) { if (!allowCancel) { @@ -2860,6 +2876,8 @@ void Control::quit(bool allowCancel) return; } + this->closeDocument(); + this->scheduler->lock(); audioController->stopRecording(); @@ -2870,100 +2888,81 @@ void Control::quit(bool allowCancel) gtk_main_quit(); } -bool Control::close(bool destroy, bool allowCancel) +bool Control::close(const bool allowDestroy, const bool allowCancel) { XOJ_CHECK_TYPE(Control); clearSelectionEndText(); metadata->documentChanged(); + bool discard = false; + const bool fileRemoved = !doc->getFilename().isEmpty() && !this->doc->getFilename().exists(); if (undoRedo->isChanged()) { - GtkWidget* dialog = gtk_message_dialog_new(getGtkWindow(), - GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - "%s", - _("This document is not saved yet.")); + const auto message = fileRemoved ? _("Document file was removed.") : _("This document is not saved yet."); + const auto saveLabel = fileRemoved ? _("Save As...") : _("Save"); + GtkWidget* dialog = gtk_message_dialog_new(getGtkWindow(), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, "%s", message); - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Save"), 1); - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Discard"), 2); + gtk_dialog_add_button(GTK_DIALOG(dialog), saveLabel, GTK_RESPONSE_ACCEPT); + gtk_dialog_add_button(GTK_DIALOG(dialog), _("Discard"), GTK_RESPONSE_REJECT); if (allowCancel) { - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), 3); + gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), GTK_RESPONSE_CANCEL); } gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow())); - int resNotSaved = gtk_dialog_run(GTK_DIALOG(dialog)); + const guint dialogResponse = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); - // save - if (resNotSaved == 1) - { - return this->save(true); - } - - // cancel or closed - if (resNotSaved != 2) // 2 = discard - { - return false; - } - else - { - destroy = true; - } - } - - if (!doc->getFilename().isEmpty()) - { - if (!this->doc->getFilename().exists()) + switch (dialogResponse) { - GtkWidget* dialog = gtk_message_dialog_new(getGtkWindow(), - GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - "%s", - _("Document file was removed.")); - - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Save As..."), 1); - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Discard"), 2); - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), 3); - gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow())); - int resDocRemoved = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - if (resDocRemoved == 1) + case GTK_RESPONSE_ACCEPT: + if (fileRemoved) { return this->saveAs(); } - - // cancel or closed - if (resDocRemoved != 2) // 2 = discard - { - return false; - } else { - destroy = true; + return this->save(true); } + break; + case GTK_RESPONSE_REJECT: + discard = true; + break; + default: + return false; + break; } } - if (destroy) + if (allowDestroy && discard) { - undoRedo->clearContents(); - - this->doc->lock(); - this->doc->clearDocument(destroy); - this->doc->unlock(); - - // updateWindowTitle(); - undoRedoChanged(); + this->closeDocument(); } return true; } +bool Control::closeAndDestroy(bool allowCancel) +{ + // We don't want to "double close", so disallow it first. + auto retval = this->close(false, allowCancel); + this->closeDocument(); + return retval; +} + +void Control::closeDocument() +{ + this->undoRedo->clearContents(); + + this->doc->lock(); + this->doc->clearDocument(true); + this->doc->unlock(); + + this->undoRedoChanged(); +} + bool Control::checkExistingFile(Path& folder, Path& filename) { XOJ_CHECK_TYPE(Control); diff --git a/src/control/Control.h b/src/control/Control.h index 91255765..b790d09d 100644 --- a/src/control/Control.h +++ b/src/control/Control.h @@ -75,10 +75,35 @@ public: void exportAsPdf(); void exportAs(); void exportBase(BaseExportJob* job); + void quit(bool allowCancel = true); + + /** + * Save the current document. + * + * @param synchron Whether the save should be run synchronously or asynchronously. + */ bool save(bool synchron = false); bool saveAs(); - void quit(bool allowCancel = true); - bool close(bool destroy = false, bool allowCancel = true); + + /** + * Marks the current document as saved if it is currently marked as unsaved. + */ + void resetSavedStatus(); + + /** + * Close the current document, prompting to save unsaved changes. + * + * @param allowDestroy Whether clicking "Discard" should destroy the current document. + * @param allowCancel Whether the user should be able to cancel closing the document. + * @return true if the user closed the document, otherwise false. + */ + bool close(bool allowDestroy = false, bool allowCancel = true); + + /** + * Calls close, always forcing the document to be destroyed. + * @return The value returned by close + */ + bool closeAndDestroy(bool allowCancel = false); // Asks user to replace an existing file when saving / exporting, since we add the extension // after the OK, we need to check manually @@ -297,6 +322,11 @@ protected: private: XOJ_TYPE_ATTRIB; + /** + * "Closes" the document, preparing the editor for a new document. + */ + void closeDocument(); + RecentManager* recent; UndoRedoHandler* undoRedo; ZoomControl* zoom; diff --git a/src/control/jobs/SaveJob.cpp b/src/control/jobs/SaveJob.cpp index 7b61eab0..62896bf5 100644 --- a/src/control/jobs/SaveJob.cpp +++ b/src/control/jobs/SaveJob.cpp @@ -42,15 +42,7 @@ void SaveJob::afterRun() } else { - Document* doc = this->control->getDocument(); - - doc->lock(); - Path filename = doc->getFilename(); - doc->unlock(); - - control->getUndoRedoHandler()->documentSaved(); - control->getRecentManager()->addRecentFileFilename(filename); - control->updateWindowTitle(); + this->control->resetSavedStatus(); } }