Don't create 2 new books for every new session.

And don't ask to save a not-dirty or empty book, fixing
Bug 794870 - If no book is opened, gnucash still asks if the user wants
to save changes when opening a file
This commit is contained in:
John Ralls 2018-09-23 16:30:30 -07:00
parent 1c5eb86d90
commit 26a179872d
7 changed files with 44 additions and 39 deletions

View File

@ -1238,6 +1238,8 @@ gnc_main_window_prompt_for_save (GtkWidget *window)
return FALSE;
session = gnc_get_current_session();
book = qof_session_get_book(session);
if (!qof_book_session_not_saved(book))
return FALSE;
filename = qof_session_get_url(session);
if (!strlen (filename))
filename = _("<unknown>");

View File

@ -298,6 +298,7 @@ test_gnc_sql_commit_edit (void)
qof_instance_init_data (inst, QOF_ID_NULL, book);
qof_book_set_dirty_cb (book, test_dirty_cb, &dirty_called);
qof_instance_set_dirty_flag (inst, TRUE);
gnc_account_create_root (book);
qof_book_mark_session_dirty (book);
g_assert (qof_instance_get_dirty_flag (inst));

View File

@ -58,6 +58,8 @@ extern "C"
#include "qofobject-p.h"
#include "qofbookslots.h"
#include "kvp-frame.hpp"
// For GNC_ID_ROOT_ACCOUNT:
#include "AccountP.h"
static QofLogModule log_module = QOF_MOD_ENGINE;
#define AB_KEY "hbci"
@ -456,7 +458,7 @@ gboolean
qof_book_session_not_saved (const QofBook *book)
{
if (!book) return FALSE;
return book->session_dirty;
return !qof_book_empty(book) && book->session_dirty;
}
@ -585,6 +587,15 @@ qof_book_mark_readonly(QofBook *book)
g_return_if_fail( book != NULL );
book->read_only = TRUE;
}
gboolean
qof_book_empty(const QofBook *book)
{
if (!book) return TRUE;
auto root_acct_col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
return qof_collection_get_data(root_acct_col) == nullptr;
}
/* ====================================================================== */
QofCollection *

View File

@ -258,6 +258,9 @@ gboolean qof_book_is_readonly(const QofBook *book);
/** Mark the book as read only. */
void qof_book_mark_readonly(QofBook *book);
/** Check if the book has had anything loaded into it. */
gboolean qof_book_empty(const QofBook *book);
#endif /* SWIG */
/** Returns flag indicating whether this book uses trading accounts */

View File

@ -125,7 +125,6 @@ QofSessionImpl::QofSessionImpl () noexcept
m_last_err {},
m_error_message {}
{
clear_error ();
}
QofSessionImpl::~QofSessionImpl () noexcept
@ -201,44 +200,23 @@ QofSessionImpl::load_backend (std::string access_method) noexcept
void
QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
{
/* We must have an empty book to load into or bad things will happen. */
g_return_if_fail(m_book && qof_book_empty(m_book));
if (!m_book_id.size ()) return;
ENTER ("sess=%p book_id=%s", this, m_book_id.c_str ());
/* At this point, we should are supposed to have a valid book
* id and a lock on the file. */
QofBook * oldbook {m_book};
QofBook * newbook {qof_book_new ()};
m_book = newbook;
PINFO ("new book=%p", newbook);
clear_error ();
/* This code should be sufficient to initialize *any* backend,
* whether http, postgres, or anything else that might come along.
* Basically, the idea is that by now, a backend has already been
* created & set up. At this point, we only need to get the
* top-level account group out of the backend, and that is a
* generic, backend-independent operation.
*/
auto be (qof_book_get_backend (oldbook));
qof_book_set_backend (newbook, be);
/* Starting the session should result in a bunch of accounts
* and currencies being downloaded, but probably no transactions;
* The GUI will need to do a query for that.
*/
auto be (qof_book_get_backend(m_book));
if (be)
{
be->set_percentage(percentage_func);
be->load (newbook, LOAD_TYPE_INITIAL_LOAD);
be->load (m_book, LOAD_TYPE_INITIAL_LOAD);
push_error (be->get_error(), {});
}
/* XXX if the load fails, then we try to restore the old set of books;
* however, we don't undo the session id (the URL). Thus if the
* user attempts to save after a failed load, they weill be trying to
* save to some bogus URL. This is wrong. XXX FIXME.
*/
auto err = get_error ();
if ((err != ERR_BACKEND_NO_ERR) &&
(err != ERR_FILEIO_FILE_TOO_OLD) &&
@ -247,16 +225,11 @@ QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
(err != ERR_SQL_DB_TOO_OLD) &&
(err != ERR_SQL_DB_TOO_NEW))
{
/* Something broke, put back the old stuff */
qof_book_set_backend (newbook, NULL);
qof_book_destroy (newbook);
m_book = oldbook;
qof_book_destroy(m_book);
m_book = qof_book_new();
LEAVE ("error from backend %d", get_error ());
return;
}
qof_book_set_backend (oldbook, NULL);
qof_book_destroy (oldbook);
LEAVE ("sess = %p, book_id=%s", this, m_book_id.c_str ());
}

View File

@ -36,6 +36,8 @@ extern "C"
#include "../qof.h"
#include "../qofbook-p.h"
#include "../qofbookslots.h"
/* For gnc_account_create_root() */
#include "../Account.h"
static const gchar *suitename = "/qof/qofbook";
void test_suite_qofbook ( void );
@ -285,6 +287,7 @@ test_book_session_not_saved( Fixture *fixture, gconstpointer pData )
g_assert( !qof_book_session_not_saved( fixture->book ) );
qof_book_mark_session_saved( fixture->book );
g_assert( !qof_book_session_not_saved( fixture->book ) );
gnc_account_create_root (fixture->book);
qof_book_mark_session_dirty( fixture-> book );
g_assert( qof_book_session_not_saved( fixture->book ) );
}
@ -294,6 +297,7 @@ test_book_mark_session_saved( Fixture *fixture, gconstpointer pData )
{
time64 dirty_time, clean_time;
gnc_account_create_root (fixture->book);
qof_book_mark_session_dirty( fixture-> book );
g_assert( qof_book_session_not_saved( fixture->book ) );
dirty_time = qof_book_get_session_dirty_time( fixture->book );
@ -626,6 +630,7 @@ test_book_mark_session_dirty( Fixture *fixture, gconstpointer pData )
g_assert( fixture->book->dirty_cb == NULL );
g_assert( qof_book_session_not_saved( fixture->book ) == FALSE );
before = gnc_time (NULL);
gnc_account_create_root (fixture->book);
qof_book_mark_session_dirty( fixture->book );
after = gnc_time (NULL);
g_assert_cmpint( qof_book_get_session_dirty_time( fixture->book ), >= , before);

View File

@ -28,6 +28,7 @@
#include <qof-backend.hpp>
#include <cstdlib>
#include "../gnc-backend-prov.hpp"
#include "../Account.h"
static QofBook * exported_book {nullptr};
static bool safe_sync_called {false};
@ -57,9 +58,12 @@ example_hook (QofSession & session)
hook_called = true;
}
void QofSessionMockBackend::load (QofBook *, QofBackendLoadType)
void QofSessionMockBackend::load (QofBook *book, QofBackendLoadType)
{
if (load_error) set_error(ERR_BACKEND_NO_BACKEND);
if (load_error)
set_error(ERR_BACKEND_NO_BACKEND);
else
auto root = gnc_account_create_root (book);
data_loaded = true;
}
@ -178,10 +182,13 @@ TEST (QofSessionTest, load)
EXPECT_EQ (book, s.get_book ());
// Now we'll do the load without returning an error from the backend,
// and ensure that the book changed to a new book.
// and ensure that it's the original book and that it's not empty.
load_error = false;
s.load (nullptr);
EXPECT_NE (book, s.get_book ());
EXPECT_EQ (book, s.get_book ());
EXPECT_EQ (s.get_error(), ERR_BACKEND_NO_ERR);
//But it's still empty, to the book shouldn't need saving
EXPECT_FALSE(qof_book_session_not_saved (s.get_book ()));
// I'll put load_error back just to be tidy.
load_error = true;
qof_backend_unregister_all_providers ();
@ -192,11 +199,14 @@ TEST (QofSessionTest, save)
qof_backend_register_provider (get_provider ());
QofSession s;
s.begin ("book1", false, false, false);
load_error = false;
s.load (nullptr);
qof_book_mark_session_dirty (s.get_book ());
s.save (nullptr);
EXPECT_EQ (sync_called, true);
qof_backend_unregister_all_providers ();
sync_called = false;
load_error = true;
}
TEST (QofSessionTest, safe_save)