From 68b8878ab5c01c41519bdfd941b1afbc12fd80e0 Mon Sep 17 00:00:00 2001 From: Christian Stimming Date: Tue, 2 Mar 2010 20:22:23 +0000 Subject: [PATCH] More C++/Qt4 frontend work. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18782 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/gnc/main.cpp | 9 +- src/gnc/mainwindow.cpp | 289 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 275 insertions(+), 23 deletions(-) diff --git a/src/gnc/main.cpp b/src/gnc/main.cpp index b49cd22174..81a0c054ce 100644 --- a/src/gnc/main.cpp +++ b/src/gnc/main.cpp @@ -41,6 +41,7 @@ extern "C" #include "core-utils/gnc-main.h" #include "engine/gnc-session.h" #include "engine/engine-helpers.h" +#include "engine/cashobjects.h" #include "swig-runtime.h" #include "gnc-backend-xml.h" @@ -169,14 +170,20 @@ main(int argc, char ** argv) gnc::gnc_log_init(); + qof_init(); gnc_module_system_init(); + cashobjects_register(); + // For the XML file backend qof_backend_module_init(); // From here on the new C++ code QApplication app(argc, argv); gnc::MainWindow mainWin; mainWin.show(); - return app.exec(); + + int r = app.exec(); + qof_close(); + return r; } diff --git a/src/gnc/mainwindow.cpp b/src/gnc/mainwindow.cpp index 8297cd078f..e82af30ee1 100644 --- a/src/gnc/mainwindow.cpp +++ b/src/gnc/mainwindow.cpp @@ -3,9 +3,24 @@ #include "mainwindow.hpp" #include "ui_mainwindow.h" +// gnucash includes +#include "config.h" +extern "C" { +#include +#include "qof.h" +#include "engine/gnc-session.h" +#include "engine/gnc-hooks.h" +#include "engine/gnc-filepath-utils.h" +#include "engine/Account.h" +#include "engine/TransLog.h" +} + namespace gnc { +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = GNC_MOD_GUI; + MainWindow::MainWindow() : ui(new Ui::MainWindow) { @@ -36,6 +51,20 @@ void MainWindow::closeEvent(QCloseEvent *event) { writeSettings(); event->accept(); + + QofSession *session = gnc_get_current_session (); + + /* disable events; otherwise the mass deletion of accounts and + * transactions during shutdown would cause massive redraws */ + qof_event_suspend (); + + qof_session_call_close_hooks(session); + gnc_hook_run(HOOK_BOOK_CLOSED, session); + gnc_clear_current_session(); + + gnc_get_current_session (); + + qof_event_resume (); } else { @@ -43,15 +72,6 @@ void MainWindow::closeEvent(QCloseEvent *event) } } -void MainWindow::newFile() -{ - if (maybeSave()) - { - ui->textEdit->clear(); - setCurrentFile(""); - } -} - void MainWindow::open() { if (maybeSave()) @@ -176,21 +196,171 @@ bool MainWindow::maybeSave() return true; } +// //////////////////////////////////////////////////////////// + +static void +gnc_book_opened (void) +{ + gnc_hook_run(HOOK_BOOK_OPENED, gnc_get_current_session()); +} + +void MainWindow::newFile() +{ + if (maybeSave()) + { + + if (gnc_current_session_exist()) { + QofSession *session = gnc_get_current_session (); + + /* close any ongoing file sessions, and free the accounts. + * disable events so we don't get spammed by redraws. */ + qof_event_suspend (); + + qof_session_call_close_hooks(session); + gnc_hook_run(HOOK_BOOK_CLOSED, session); + + gnc_clear_current_session(); + qof_event_resume (); + } + + /* start a new book */ + gnc_get_current_session (); + + gnc_hook_run(HOOK_NEW_BOOK, NULL); + + //gnc_gui_refresh_all (); + + /* Call this after re-enabling events. */ + gnc_book_opened (); + + setCurrentFile(""); + } +} + void MainWindow::loadFile(const QString &fileName) { - QFile file(fileName); - if (!file.open(QFile::ReadOnly | QFile::Text)) + if (fileName.isEmpty()) + return; + + // copied from gnc_post_file_open, gnome-utils/gnc-file.c + + /* disable events while moving over to the new set of accounts; + * the mass deletion of accounts and transactions during + * switchover would otherwise cause excessive redraws. */ + qof_event_suspend (); + + /* Change the mouse to a busy cursor */ + //gnc_set_busy_cursor (NULL, TRUE); + + /* -------------- BEGIN CORE SESSION CODE ------------- */ + /* -- this code is almost identical in FileOpen and FileSaveAs -- */ + QofSession *current_session = gnc_get_current_session(); + qof_session_call_close_hooks(current_session); + gnc_hook_run(HOOK_BOOK_CLOSED, current_session); + gnc_clear_current_session(); + + /* load the accounts from the users datafile */ + /* but first, check to make sure we've got a session going. */ + QofSession *new_session = qof_session_new (); + + bool uh_oh = false; + QByteArray newfile = fileName.toUtf8(); + qof_session_begin (new_session, newfile, FALSE, FALSE); + QofBackendError io_err = qof_session_get_error (new_session); + /* if file appears to be locked, ask the user ... */ + if (ERR_BACKEND_LOCKED == io_err || ERR_BACKEND_READONLY == io_err) { - QMessageBox::warning(this, tr("Application"), - tr("Cannot read file %1:\n%2.") - .arg(fileName) - .arg(file.errorString())); - return; + QString fmt1 = tr("GnuCash could not obtain the lock for %1.").arg(fileName); + QString fmt2 = + ((ERR_BACKEND_LOCKED == io_err) + ? tr("That database may be in use by another user, " + "in which case you should not open the database. " + "What would you like to do? Open anyway? FIXME") + : tr("That database may be on a read-only file system, " + "or you may not have write permission for the directory. " + "If you proceed you may not be able to save any changes. " + "What would you like to do? Open anyway? FIXME")); + if (QMessageBox::question(this, fmt1, fmt2) + == QMessageBox::Ok) + { + /* user told us to ignore locks. So ignore them. */ + qof_session_begin (new_session, newfile, TRUE, FALSE); + } + else + { + /* Can't use the given file, so just create a new + * database so that the user will get a window that + * they can click "Exit" on. + */ + newFile(); + } + } + /* if the database doesn't exist, ask the user ... */ + else if ((ERR_BACKEND_NO_SUCH_DB == io_err) || + (ERR_SQL_DB_TOO_OLD == io_err)) + { + if (QMessageBox::question(this, tr("Create New File?"), + tr("The file %1 does not exist. Do you want to create it?").arg(fileName)) + == QMessageBox::Ok) + { + /* user told us to create a new database. Do it. */ + qof_session_begin (new_session, newfile, FALSE, TRUE); + } } - QTextStream in(&file); QApplication::setOverrideCursor(Qt::WaitCursor); - ui->textEdit->setPlainText(in.readAll()); + /* Check for errors again, since above may have cleared the lock. + * If its still locked, still, doesn't exist, still too old, then + * don't bother with the message, just die. */ + io_err = qof_session_get_error (new_session); + if ((ERR_BACKEND_LOCKED == io_err) || + (ERR_BACKEND_READONLY == io_err) || + (ERR_BACKEND_NO_SUCH_DB == io_err) || + (ERR_SQL_DB_TOO_OLD == io_err)) + { + uh_oh = true; + } + else + { + uh_oh = !(QMessageBox::question(this, tr("Open anyway?"), + tr("The file %1 has some errors (FIXME). Open anyway?").arg(fileName)) + == QMessageBox::Ok); + } + + if (!uh_oh) + { + ::Account *new_root; + + char * logpath = xaccResolveFilePath(newfile); + PINFO ("logpath=%s", logpath ? logpath : "(null)"); + xaccLogSetBaseName (logpath); + xaccLogDisable(); + + statusBar()->showMessage(tr("Loading user data..."), 2000); + qof_session_load (new_session, NULL); + xaccLogEnable(); + + /* check for i/o error, put up appropriate error dialog */ + io_err = qof_session_get_error (new_session); + + uh_oh = !(QMessageBox::question(this, tr("Error on Open"), + tr("There was an error opening the file %1. FIXME").arg(fileName)) + == QMessageBox::Ok); + + new_root = gnc_book_get_root_account (qof_session_get_book (new_session)); + if (uh_oh) new_root = NULL; + } + + + /* if we got to here, then we've successfully gotten a new session */ + /* close up the old file session (if any) */ + gnc_set_current_session(new_session); + + qof_event_resume (); + + /* Call this after re-enabling events. */ + gnc_book_opened (); + QApplication::restoreOverrideCursor(); setCurrentFile(fileName); @@ -200,7 +370,7 @@ void MainWindow::loadFile(const QString &fileName) bool MainWindow::saveFile(const QString &fileName) { QFile file(fileName); - if (!file.open(QFile::WriteOnly | QFile::Text)) + if (!file.open(QFile::WriteOnly)) { QMessageBox::warning(this, tr("Application"), tr("Cannot write file %1:\n%2.") @@ -208,10 +378,85 @@ bool MainWindow::saveFile(const QString &fileName) .arg(file.errorString())); return false; } - - QTextStream out(&file); + file.close(); QApplication::setOverrideCursor(Qt::WaitCursor); - out << ui->textEdit->toPlainText(); + + QofSession *session = gnc_get_current_session (); + /* Make sure all of the data from the old file is loaded */ + qof_session_ensure_all_data_loaded(session); + + /* -- this session code is NOT identical in FileOpen and FileSaveAs -- */ + + QByteArray newfile = fileName.toUtf8(); + xaccLogSetBaseName(newfile); //FIXME: This is premature. + QofSession *new_session = qof_session_new (); + qof_session_begin (new_session, newfile, FALSE, FALSE); + + QofBackendError io_err = qof_session_get_error (new_session); + + /* if file appears to be locked, ask the user ... */ + if (ERR_BACKEND_LOCKED == io_err || ERR_BACKEND_READONLY == io_err) + { + if (QMessageBox::question(this, tr("Ignore Lock?"), + tr("The file %1 is locked. Should we ignore the lock?").arg(fileName)) + == QMessageBox::Ok) + { + /* user told us to ignore locks. So ignore them. */ + qof_session_begin (new_session, newfile, TRUE, FALSE); + } + } + + /* if the database doesn't exist, ask the user ... */ + else if ((ERR_FILEIO_FILE_NOT_FOUND == io_err) || + (ERR_BACKEND_NO_SUCH_DB == io_err) || + (ERR_SQL_DB_TOO_OLD == io_err)) + { + if (QMessageBox::question(this, tr("Create New File?"), + tr("The file %1 does not exist. Should it be created?").arg(fileName))) + { + /* user told us to create a new database. Do it. */ + qof_session_begin (new_session, newfile, FALSE, TRUE); + } + } + + /* check again for session errors (since above dialog may have + * cleared a file lock & moved things forward some more) + * This time, errors will be fatal. + */ + io_err = qof_session_get_error (new_session); + if (ERR_BACKEND_NO_ERR != io_err) + { + QMessageBox::critical(this, tr("Still in Error"), + tr("The file %1 still cannot be written. FIXME").arg(fileName)); + xaccLogDisable(); + qof_session_destroy (new_session); + xaccLogEnable(); + return false; + } + + /* Prevent race condition between swapping the contents of the two + * sessions, and actually installing the new session as the current + * one. Any event callbacks that occur in this interval will have + * problems if they check for the current book. */ + qof_event_suspend(); + + /* if we got to here, then we've successfully gotten a new session */ + /* close up the old file session (if any) */ + qof_session_swap_data (session, new_session); + gnc_clear_current_session(); + session = NULL; + + /* XXX At this point, we should really mark the data in the new session + * as being 'dirty', since we haven't saved it at all under the new + * session. But I'm lazy... + */ + gnc_set_current_session(new_session); + + qof_event_resume(); + + /* --------------- END CORE SESSION CODE -------------- */ + + QApplication::restoreOverrideCursor(); setCurrentFile(fileName);