Don't ask to save a non-existant book.

To accomplish that we separate creating a book and creating a session;
gnc_get_session no longer automatically creates a book if one isn't
connected.

We also add an initially_insensitive GtkAction array to
gnc-plugin-basic-commands with a call to make its contents insensitive
at plugin load so that the save button on the toolbar isn't lighted when
there's nothing to save.
This commit is contained in:
John Ralls 2020-05-08 15:47:30 -07:00
parent 320db3270b
commit 4e6c497cd1
7 changed files with 79 additions and 46 deletions

View File

@ -651,7 +651,7 @@ gnc_file_query_save (GtkWindow *parent, gboolean can_cancel)
static gboolean
gnc_post_file_open (GtkWindow *parent, const char * filename, gboolean is_readonly)
{
QofSession *current_session, *new_session;
QofSession *new_session;
QofBook *new_book;
GList *invalid_account_names;
gboolean uh_oh = FALSE;
@ -726,7 +726,7 @@ RESTART:
/* -- this code is almost identical in FileOpen and FileSaveAs -- */
if (gnc_current_session_exist())
{
current_session = gnc_get_current_session();
QofSession *current_session = gnc_get_current_session();
gnc_hook_run(HOOK_BOOK_CLOSED, current_session);
gnc_close_gui_component_by_session (current_session);
gnc_state_save (current_session);
@ -735,7 +735,7 @@ RESTART:
/* load the accounts from the users datafile */
/* but first, check to make sure we've got a session going. */
new_session = qof_session_new (NULL);
new_session = qof_session_new (qof_book_new());
// Begin the new session. If we are in read-only mode, ignore the locks.
qof_session_begin (new_session, newfile, is_readonly, FALSE, FALSE);
@ -1299,6 +1299,9 @@ gnc_file_save (GtkWindow *parent)
QofSession *session;
ENTER (" ");
if (!gnc_current_session_exist ())
return; //No session means nothing to save.
/* hack alert -- Somehow make sure all in-progress edits get committed! */
/* If we don't have a filename/path to save to get one. */
@ -1366,6 +1369,12 @@ gnc_file_save_as (GtkWindow *parent)
ENTER(" ");
if (!gnc_current_session_exist ())
{
LEAVE("No Session.");
return;
}
last = gnc_history_get_last();
if ( last && gnc_uri_targets_local_fs (last))
{

View File

@ -239,6 +239,14 @@ static const gchar *gnc_plugin_important_actions[] =
NULL,
};
/** The following items should be made insensitive at startup time. The
* sensitivity will be changed by some later event. */
static const gchar *gnc_plugin_initially_insensitive_actions[] =
{
"FileSaveAction",
NULL,
};
/** These actions are made not sensitive (i.e.,
* their toolbar and menu items are grayed out and do not send events
* when clicked) when the current book is "Read Only".
@ -309,6 +317,11 @@ gnc_plugin_basic_commands_add_to_window (GncPlugin *plugin,
GncMainWindow *window,
GQuark type)
{
GtkActionGroup *action_group =
gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
gnc_plugin_update_actions(action_group,
gnc_plugin_initially_insensitive_actions,
"sensitive", FALSE);
g_signal_connect(window, "page_changed",
G_CALLBACK(gnc_plugin_basic_commands_main_window_page_changed),
plugin);

View File

@ -64,7 +64,8 @@ test_qofsession_aqb_kvp( void )
if (1)
{
// A file with no content at all, but a valid XML file
QofSession *new_session = qof_session_new (NULL);
QofBook *book = qof_book_new();
QofSession *new_session = qof_session_new (book);
char *newfile = g_strdup_printf("file://%s", file1);
qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);
@ -92,7 +93,8 @@ test_qofsession_aqb_kvp( void )
{
// A file with no content except for the book_template_list kvp
// slot
QofSession *new_session = qof_session_new (NULL);
QofBook *book = qof_book_new();
QofSession *new_session = qof_session_new (book);
char *newfile = g_strdup_printf("file://%s", file2);
qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);

View File

@ -91,7 +91,8 @@ setup (Fixture* fixture, gconstpointer pData)
{
gchar* url = (gchar*)pData;
gnc_module_init_backend_dbi();
fixture->session = qof_session_new (nullptr);
auto book = qof_book_new();
fixture->session = qof_session_new (book);
/* When running distcheck the source directory is read-only, which
* prevents creating the lock file. Force the session to get
* around that.
@ -391,7 +392,8 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
url = fixture->filename;
// Save the session data
auto session_2 = qof_session_new (nullptr);
auto book2{qof_book_new()};
auto session_2 = qof_session_new (book2);
qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
g_assert (session_2 != NULL);
g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
@ -402,7 +404,8 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
// Reload the session data
auto session_3 = qof_session_new (nullptr);
auto book3{qof_book_new()};
auto session_3 = qof_session_new (book3);
g_assert (session_3 != NULL);
qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
g_assert (session_3 != NULL);
@ -442,7 +445,8 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
url = fixture->filename;
// Load the session data
auto session_1 = qof_session_new (nullptr);
auto book1{qof_book_new()};
auto session_1 = qof_session_new (book1);
qof_session_begin (session_1, url, FALSE, TRUE, TRUE);
if (session_1 &&
qof_session_get_error (session_1) != ERR_BACKEND_NO_ERR)
@ -468,7 +472,7 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
}
/* Destroy the session and reload it */
session_2 = qof_session_new (nullptr);
session_2 = qof_session_new (qof_book_new());
qof_session_begin (session_2, url, TRUE, FALSE, FALSE);
if (session_2 &&
qof_session_get_error (session_2) != ERR_BACKEND_NO_ERR)
@ -508,7 +512,7 @@ static void
test_dbi_version_control (Fixture* fixture, gconstpointer pData)
{
auto url = (gchar*)pData;
QofBook* book = nullptr;
QofBook* book{qof_book_new()};
QofBackendError err;
gint ourversion = gnc_prefs_get_long_version ();
GncSqlBackend* sql_be = nullptr;
@ -536,7 +540,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
qof_book_commit_edit (book);
qof_session_end (sess);
qof_session_destroy (sess);
sess = qof_session_new (nullptr);
sess = qof_session_new (qof_book_new());
qof_session_begin (sess, url, TRUE, FALSE, FALSE);
qof_session_load (sess, NULL);
err = qof_session_pop_error (sess);
@ -549,7 +553,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
qof_book_commit_edit (book);
qof_session_end (sess);
qof_session_destroy (sess);
sess = qof_session_new (nullptr);
sess = qof_session_new (qof_book_new());
qof_session_begin (sess, url, TRUE, FALSE, FALSE);
qof_session_load (sess, NULL);
qof_session_ensure_all_data_loaded (sess);
@ -578,14 +582,14 @@ test_dbi_business_store_and_reload (Fixture* fixture, gconstpointer pData)
if (fixture->filename)
url = fixture->filename;
// Save the session data
auto session_2 = qof_session_new (nullptr);
auto session_2 = qof_session_new (qof_book_new());
qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
qof_session_swap_data (fixture->session, session_2);
qof_book_mark_session_dirty (qof_session_get_book (session_2));
qof_session_save (session_2, NULL);
// Reload the session data
auto session_3 = qof_session_new (nullptr);
auto session_3 = qof_session_new (qof_book_new());
qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
qof_session_load (session_3, NULL);

View File

@ -1152,7 +1152,7 @@ gnc_book_get_root_account (QofBook *book)
if (!book) return NULL;
col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
root = gnc_coll_get_root_account (col);
if (root == NULL)
if (root == NULL && !qof_book_shutting_down(book))
root = gnc_account_create_root(book);
return root;
}
@ -5875,6 +5875,8 @@ static void
gnc_account_book_end(QofBook* book)
{
Account *root_account = gnc_book_get_root_account(book);
if (!root_account)
return;
xaccAccountBeginEdit(root_account);
xaccAccountDestroy(root_account);
}

View File

@ -207,47 +207,44 @@ QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
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. */
* id and a lock on the file. */
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.
*/
qof_book_set_backend (newbook, m_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.
*/
qof_book_set_backend (m_book, m_backend);
/* 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.
*/
* and currencies being downloaded, but probably no transactions;
* The GUI will need to do a query for that.
*/
if (m_backend)
{
m_backend->set_percentage(percentage_func);
m_backend->load (newbook, LOAD_TYPE_INITIAL_LOAD);
m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
push_error (m_backend->get_error(), {});
}
auto err = get_error ();
if ((err != ERR_BACKEND_NO_ERR) &&
(err != ERR_FILEIO_FILE_TOO_OLD) &&
(err != ERR_FILEIO_NO_ENCODING) &&
(err != ERR_FILEIO_FILE_UPGRADE) &&
(err != ERR_SQL_DB_TOO_OLD) &&
(err != ERR_SQL_DB_TOO_NEW))
(err != ERR_FILEIO_FILE_TOO_OLD) &&
(err != ERR_FILEIO_NO_ENCODING) &&
(err != ERR_FILEIO_FILE_UPGRADE) &&
(err != ERR_SQL_DB_TOO_OLD) &&
(err != ERR_SQL_DB_TOO_NEW))
{
/* Something broke, put back the old stuff */
delete m_backend;
qof_book_set_backend (newbook, NULL);
qof_book_destroy (newbook);
m_book = oldbook;
m_backend = qof_book_get_backend (m_book);
// Something failed, delete and restore new ones.
destroy_backend();
qof_book_destroy (m_book);
m_book = qof_book_new();
LEAVE ("error from backend %d", get_error ());
return;
}
qof_book_destroy (oldbook);
LEAVE ("sess = %p, book_id=%s", this, m_book_id.c_str ());
}

View File

@ -175,19 +175,25 @@ TEST (QofSessionTest, load)
* and create a new one.
*/
qof_backend_register_provider (get_provider ());
QofSession s;
QofSession s{qof_book_new()};
s.begin ("book1", false, false, false);
auto book = s.get_book ();
char *guidstr1 = guid_to_string(qof_instance_get_guid(s.get_book ()));
s.load (nullptr);
EXPECT_NE (book, s.get_book ());
char *guidstr2 = guid_to_string(qof_instance_get_guid(s.get_book ()));
EXPECT_STRNE (guidstr1, guidstr2);
g_free(guidstr1);
g_free(guidstr2);
/* Now we'll do the load without returning an error from the backend,
* and ensure that it's the new book from the previous test.
*/
load_error = false;
book = s.get_book();
guidstr1 = guid_to_string(qof_instance_get_guid(s.get_book ()));
s.load (nullptr);
EXPECT_EQ (book, s.get_book ());
guidstr2 = guid_to_string(qof_instance_get_guid(s.get_book ()));
EXPECT_STREQ (guidstr1, guidstr2);
g_free(guidstr1);
g_free(guidstr2);
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 ()));