r18801 - gnucash/trunk/src - Some more C++ work. Opening an existing file works, even though nothing is visible so far.

Christian Stimming cstim at code.gnucash.org
Wed Mar 3 15:47:31 EST 2010


Author: cstim
Date: 2010-03-03 15:47:31 -0500 (Wed, 03 Mar 2010)
New Revision: 18801
Trac: http://svn.gnucash.org/trac/changeset/18801

Added:
   gnucash/trunk/src/gnc/Account.hpp
   gnucash/trunk/src/gnc/Book.cpp
   gnucash/trunk/src/gnc/Book.hpp
   gnucash/trunk/src/gnc/ScopedPointer.hpp
   gnucash/trunk/src/gnc/Session.cpp
   gnucash/trunk/src/gnc/Session.hpp
   gnucash/trunk/src/gnc/WeakPointer.hpp
Modified:
   gnucash/trunk/src/CMakeLists.txt
   gnucash/trunk/src/gnc/CMakeLists.txt
   gnucash/trunk/src/gnc/mainwindow.cpp
   gnucash/trunk/src/gnc/mainwindow.hpp
Log:
Some more C++ work. Opening an existing file works, even though nothing is visible so far.

The implementation of a scoped_ptr wrapper around a C object
uses the boost library, though, because writing our own
implementation of a scoped_ptr with custom deletion function
is too non-trivial and I rather re-use the boost::shared_ptr
here instead of making our own mistakes.

Modified: gnucash/trunk/src/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/CMakeLists.txt	2010-03-03 20:47:10 UTC (rev 18800)
+++ gnucash/trunk/src/CMakeLists.txt	2010-03-03 20:47:31 UTC (rev 18801)
@@ -65,6 +65,22 @@
 SET (QT_MIN_VERSION "4.5.0")
 FIND_PACKAGE (Qt4 REQUIRED) # find and setup Qt4 for this project
 
+# ############################################################
+
+# Check for boost
+FIND_PACKAGE (Boost QUIET)
+INCLUDE_DIRECTORIES (${Boost_INCLUDE_DIRS})
+
+# MSVC should not link against boost-regex and boost-date_time.
+IF (MSVC)
+  ADD_DEFINITIONS( -DBOOST_ALL_NO_LIB )
+ENDIF (MSVC)
+IF (WIN32)
+  ADD_DEFINITIONS (-DWIN32_LEAN_AND_MEAN)
+ENDIF (WIN32)
+
+# ############################################################
+
 # Compiler flags
 IF (UNIX)
   SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wdeclaration-after-statement -Wno-pointer-sign -D_FORTIFY_SOURCE=2 -Wall -Wunused -Wmissing-prototypes -Wmissing-declarations  -Wno-unused")

Added: gnucash/trunk/src/gnc/Account.hpp
===================================================================
--- gnucash/trunk/src/gnc/Account.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Account.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,27 @@
+#ifndef GNC_ACCOUNT_HPP
+#define GNC_ACCOUNT_HPP
+
+// gnucash includes
+extern "C"
+{
+#include "qof.h"
+#include "engine/Account.h"
+}
+
+#include "gnc/WeakPointer.hpp"
+
+namespace gnc
+{
+
+class Account : public WeakPointer< ::Account >
+{
+public:
+    typedef WeakPointer< ::Account > base_class;
+    Account(element_type* ptr = 0)
+            : base_class(ptr)
+    { }
+};
+
+} // END namespace gnc
+
+#endif

Added: gnucash/trunk/src/gnc/Book.cpp
===================================================================
--- gnucash/trunk/src/gnc/Book.cpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Book.cpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,12 @@
+#include "config.h"
+#include "gnc/Book.hpp"
+#include "gnc/Account.hpp"
+
+namespace gnc
+{
+Account Book::get_root_account()
+{
+    return Account(gnc_book_get_root_account (get()));
+}
+
+} // END namespace gnc

Added: gnucash/trunk/src/gnc/Book.hpp
===================================================================
--- gnucash/trunk/src/gnc/Book.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Book.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,31 @@
+#ifndef GNC_BOOK_HPP
+#define GNC_BOOK_HPP
+
+// gnucash includes
+extern "C"
+{
+#include "qof.h"
+#include "engine/gnc-hooks.h"
+#include "engine/Account.h"
+}
+
+#include "gnc/WeakPointer.hpp"
+
+namespace gnc
+{
+class Account;
+
+class Book : public WeakPointer< ::QofBook >
+{
+public:
+    typedef WeakPointer< ::QofBook > base_class;
+    Book(element_type* ptr = 0)
+            : base_class(ptr)
+    { }
+
+    Account get_root_account();
+};
+
+} // END namespace gnc
+
+#endif

Modified: gnucash/trunk/src/gnc/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/gnc/CMakeLists.txt	2010-03-03 20:47:10 UTC (rev 18800)
+++ gnucash/trunk/src/gnc/CMakeLists.txt	2010-03-03 20:47:31 UTC (rev 18801)
@@ -10,6 +10,8 @@
 )
 
 SET (gnc_SOURCES
+  Book.cpp
+  Session.cpp
   main.cpp
   mainwindow.cpp
 )
@@ -18,6 +20,11 @@
   mainwindow.hpp
 )
 SET (gnc_HEADERS ${gnc_QOBJECT_HEADERS}
+  Account.hpp
+  Book.hpp
+  ScopedPointer.hpp
+  Session.hpp
+  WeakPointer.hpp
 )
 
 SET (gnc_FORMS

Added: gnucash/trunk/src/gnc/ScopedPointer.hpp
===================================================================
--- gnucash/trunk/src/gnc/ScopedPointer.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/ScopedPointer.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,83 @@
+#ifndef GNC_SCOPEDPOINTER_HPP
+#define GNC_SCOPEDPOINTER_HPP
+
+#include <boost/shared_ptr.hpp>
+
+namespace gnc
+{
+
+/** A sole ownership of a single C object.
+ *
+ * This copies the interface of the boost::scoped_ptr, but with the
+ * boost::shared_ptr possiblity of a custom deleter function because
+ * we need that.
+ */
+template<class T>
+class ScopedPointer // noncopyable
+{
+    // Private copy constructor so that this is noncopyable
+    ScopedPointer(ScopedPointer const &);
+    ScopedPointer& operator=(ScopedPointer const&);
+    void operator==(ScopedPointer const&) const;
+    void operator!=(ScopedPointer const&) const;
+    boost::shared_ptr<T> m_ptr;
+    typedef ScopedPointer<T> this_type;
+public:
+    typedef T element_type;
+
+    ScopedPointer()
+            : m_ptr()
+    { }
+
+    template<class Y, class D> ScopedPointer(Y * ptr, D deleter)
+            : m_ptr(ptr, deleter)
+    { }
+
+    void reset() // never throws in 1.30+
+    {
+        this_type().swap(*this);
+    }
+
+    template<class Y, class D> void reset( Y * p, D d )
+    {
+        this_type( p, d ).swap( *this );
+    }
+
+    T & operator*() const // never throws
+    {
+        assert(m_ptr != 0);
+        return *m_ptr.get();
+    }
+
+    T * operator->() const // never throws
+    {
+        assert(m_ptr != 0);
+        return m_ptr.get();
+    }
+
+    T * get() const // never throws
+    {
+        return m_ptr.get();
+    }
+
+    // implicit conversion to "bool"
+    typedef T * (this_type::*unspecified_bool_type)() const;
+    operator unspecified_bool_type() const // never throws
+    {
+        return m_ptr == 0? 0: &this_type::get;
+    }
+
+    bool operator! () const // never throws
+    {
+        return m_ptr == 0;
+    }
+
+    void swap(ScopedPointer & other) // never throws
+    {
+        m_ptr.swap(other.m_ptr);
+    }
+};
+
+} // END namespace gnc
+
+#endif

Added: gnucash/trunk/src/gnc/Session.cpp
===================================================================
--- gnucash/trunk/src/gnc/Session.cpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Session.cpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,83 @@
+#include "config.h"
+#include "gnc/Session.hpp"
+#include "gnc/Book.hpp"
+
+// Explicit instantiation to check for compiler errors in the template
+template class gnc::ScopedPointer< QofSession >;
+template class gnc::WeakPointer< QofSession >;
+
+
+namespace gnc
+{
+
+Book Session::get_book () const
+{
+    return Book(qof_session_get_book(get()));
+}
+
+
+#define TYPE_TO_STR(tstr, desc) tstr : return std::make_pair<std::string,std::string>(#tstr, desc)
+
+std::pair<std::string, std::string> errorToStringPair(QofBackendError err)
+{
+    switch (err)
+    {
+    case TYPE_TO_STR(ERR_BACKEND_NO_ERR, "No Error");
+    case TYPE_TO_STR(ERR_BACKEND_NO_HANDLER, "no backend handler found for this access method (ENOSYS)");
+    case TYPE_TO_STR(ERR_BACKEND_NO_BACKEND, "Backend * pointer was unexpectedly null");
+    case TYPE_TO_STR(ERR_BACKEND_BAD_URL, "Can't parse url");
+    case TYPE_TO_STR(ERR_BACKEND_NO_SUCH_DB, "the named database doesn't exist");
+    case TYPE_TO_STR(ERR_BACKEND_CANT_CONNECT, "bad dbname/login/passwd or network failure");
+    case TYPE_TO_STR(ERR_BACKEND_CONN_LOST, "Lost connection to server");
+    case TYPE_TO_STR(ERR_BACKEND_LOCKED, "in use by another user (ETXTBSY)");
+    case TYPE_TO_STR(ERR_BACKEND_READONLY, "cannot write to file/directory");
+    case TYPE_TO_STR(ERR_BACKEND_TOO_NEW, "file/db version newer than what we can read");
+    case TYPE_TO_STR(ERR_BACKEND_DATA_CORRUPT, "data in db is corrupt");
+    case TYPE_TO_STR(ERR_BACKEND_SERVER_ERR, "error in response from server");
+    case TYPE_TO_STR(ERR_BACKEND_ALLOC, "internal memory allocation failure");
+    case TYPE_TO_STR(ERR_BACKEND_PERM, "user login successful, but no permissions to access the desired object");
+    case TYPE_TO_STR(ERR_BACKEND_MODIFIED, "commit of object update failed because another user has modified the object");
+    case TYPE_TO_STR(ERR_BACKEND_MOD_DESTROY, "commit of object update failed because another user has deleted the object");
+    case TYPE_TO_STR(ERR_BACKEND_MISC, "undetermined error");
+    case TYPE_TO_STR(ERR_QSF_INVALID_OBJ, "The QSF object failed to validate against the QSF object schema");
+    case TYPE_TO_STR(ERR_QSF_INVALID_MAP, "The QSF map failed to validate against the QSF map schema");
+    case TYPE_TO_STR(ERR_QSF_BAD_OBJ_GUID, "The QSF object contains one or more invalid GUIDs.");
+    case TYPE_TO_STR(ERR_QSF_BAD_QOF_VERSION, "QSF map or object doesn't match the current QOF_OBJECT_VERSION.");
+    case TYPE_TO_STR(ERR_QSF_BAD_MAP, "The selected map validates but is unusable.");
+    case TYPE_TO_STR(ERR_QSF_NO_MAP, "The QSF object file was loaded without a map");
+    case TYPE_TO_STR(ERR_QSF_WRONG_MAP, "The selected map validates but is for different objects.");
+    case TYPE_TO_STR(ERR_QSF_MAP_NOT_OBJ, "Selected file is a QSF map and cannot be opened as a QSF object");
+    case TYPE_TO_STR(ERR_QSF_OVERFLOW, "EOVERFLOW - generated by strtol or strtoll.");
+    case TYPE_TO_STR(ERR_QSF_OPEN_NOT_MERGE, "QSF files cannot be opened alone. The data must be merged.");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_BAD_READ, "read failed or file prematurely truncated");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_EMPTY, "file exists, is readable, but is empty");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_LOCKERR, "mangled locks (unspecified error)");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_NOT_FOUND, "not found / no such file");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_TOO_OLD, "file version so old we can't read it");
+    case TYPE_TO_STR(ERR_FILEIO_UNKNOWN_FILE_TYPE, "didn't recognize the file type");
+    case TYPE_TO_STR(ERR_FILEIO_PARSE_ERROR, "couldn't parse the data in the file");
+    case TYPE_TO_STR(ERR_FILEIO_BACKUP_ERROR, "couldn't make a backup of the file");
+    case TYPE_TO_STR(ERR_FILEIO_WRITE_ERROR, "couldn't write to the file");
+    case TYPE_TO_STR(ERR_FILEIO_READ_ERROR, "Could not open the file for reading.");
+    case TYPE_TO_STR(ERR_FILEIO_NO_ENCODING, "file does not specify encoding");
+    case TYPE_TO_STR(ERR_FILEIO_FILE_EACCES, "No read access permission for the given file");
+    case TYPE_TO_STR(ERR_NETIO_SHORT_READ, "not enough bytes received");
+    case TYPE_TO_STR(ERR_NETIO_WRONG_CONTENT_TYPE, "wrong kind of server, wrong data served");
+    case TYPE_TO_STR(ERR_NETIO_NOT_GNCXML, "whatever it is, we can't parse it.");
+    case TYPE_TO_STR(ERR_SQL_MISSING_DATA, "database doesn't contain expected data");
+    case TYPE_TO_STR(ERR_SQL_DB_TOO_OLD, "database is old and needs upgrading");
+    case TYPE_TO_STR(ERR_SQL_DB_BUSY, "database is busy, cannot upgrade version");
+    case TYPE_TO_STR(ERR_RPC_HOST_UNK, "Host unknown");
+    case TYPE_TO_STR(ERR_RPC_CANT_BIND, "can't bind to address");
+    case TYPE_TO_STR(ERR_RPC_CANT_ACCEPT, "can't accept connection");
+    case TYPE_TO_STR(ERR_RPC_NO_CONNECTION, "no connection to server");
+    case TYPE_TO_STR(ERR_RPC_BAD_VERSION, "RPC Version Mismatch");
+    case TYPE_TO_STR(ERR_RPC_FAILED, "Operation failed");
+    case TYPE_TO_STR(ERR_RPC_NOT_ADDED, "object not added");
+    default:
+        assert(0); // must not be reached
+        return std::make_pair("Unknown", "Unknown");
+    }
+}
+
+} // END namespace gnc

Added: gnucash/trunk/src/gnc/Session.hpp
===================================================================
--- gnucash/trunk/src/gnc/Session.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Session.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,107 @@
+#ifndef GNC_SESSION_HPP
+#define GNC_SESSION_HPP
+
+// gnucash includes
+#include "config.h" // required by qof/qofutil.h
+extern "C"
+{
+#include <glib/gi18n.h>
+#include "qof.h"
+#include "engine/gnc-hooks.h"
+}
+
+#include "gnc/ScopedPointer.hpp"
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace gnc
+{
+
+class Book;
+
+/** ScopedPointer object around a QofSession object, which also owns the
+ * QofSession object.
+ */
+class Session : public ScopedPointer< ::QofSession >
+            , boost::noncopyable
+{
+public:
+    typedef ScopedPointer< ::QofSession > base_class;
+
+    Session()
+            : base_class()
+    {}
+    Session(element_type *ptr)
+            : base_class(ptr, qof_session_destroy)
+    {}
+    void reset(element_type *ptr)
+    {
+        base_class::reset(ptr, qof_session_destroy);
+    }
+    using base_class::reset;
+    static element_type* newInstance()
+    {
+        return qof_session_new();
+    }
+
+    // Now the actual functions on the object
+
+    void begin(const std::string& book_id, bool ignore_lock, bool create_if_nonexistent)
+    {
+        qof_session_begin(get(), book_id.c_str(), ignore_lock, create_if_nonexistent);
+    }
+    void load (QofPercentageFunc percentage_func)
+    {
+        qof_session_load(get(), percentage_func);
+    }
+    QofBackendError get_error ()
+    {
+        return qof_session_get_error(get());
+    }
+    QofBackendError pop_error ()
+    {
+        return qof_session_pop_error(get());
+    }
+    std::string get_error_message() const
+    {
+        return qof_session_get_error_message(get());
+    }
+    Book get_book () const;
+
+    std::string get_file_path () const
+    {
+        return qof_session_get_file_path(get());
+    }
+
+    std::string get_url() const
+    {
+        return qof_session_get_url(get());
+    }
+
+    bool save_in_progress() const
+    {
+        return qof_session_save_in_progress(get());
+    }
+    bool save_may_clobber_data () const
+    {
+        return qof_session_save_may_clobber_data(get());
+    }
+    void save (QofPercentageFunc percentage_func)
+    {
+        qof_session_save(get(), percentage_func);
+    }
+
+
+    void call_close_hooks ()
+    {
+        qof_session_call_close_hooks (get());
+    }
+
+
+};
+
+std::pair<std::string, std::string> errorToStringPair(QofBackendError err);
+
+} // END namespace gnc
+
+#endif

Added: gnucash/trunk/src/gnc/WeakPointer.hpp
===================================================================
--- gnucash/trunk/src/gnc/WeakPointer.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/WeakPointer.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -0,0 +1,65 @@
+#ifndef GNC_WEAKPOINTER_HPP
+#define GNC_WEAKPOINTER_HPP
+
+namespace gnc
+{
+
+/** A thin wrapper for a C object which is owned by someone else.
+ *
+ * This copies the interface of the boost::scoped_ptr, but with the
+ * boost::shared_ptr possiblity of a custom deleter function because
+ * we need that.
+ */
+template<class T>
+class WeakPointer
+{
+public:
+    typedef T element_type;
+private:
+    element_type *m_ptr;
+    typedef WeakPointer<T> this_type;
+public:
+
+    WeakPointer(element_type* ptr = 0)
+            : m_ptr(ptr)
+    { }
+
+    void reset(element_type* ptr = 0)
+    {
+        m_ptr = ptr;
+    }
+
+    T & operator*() const // never throws
+    {
+        assert(m_ptr != 0);
+        return *m_ptr;
+    }
+
+    T * operator->() const // never throws
+    {
+        assert(m_ptr != 0);
+        return m_ptr;
+    }
+
+    T * get() const // never throws
+    {
+        return m_ptr;
+    }
+
+    // implicit conversion to "bool"
+    typedef T * this_type::*unspecified_bool_type;
+    operator unspecified_bool_type() const // never throws
+    {
+        return m_ptr == 0? 0: &this_type::m_ptr;
+    }
+
+    bool operator! () const // never throws
+    {
+        return m_ptr == 0;
+    }
+
+};
+
+} // END namespace gnc
+
+#endif

Modified: gnucash/trunk/src/gnc/mainwindow.cpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.cpp	2010-03-03 20:47:10 UTC (rev 18800)
+++ gnucash/trunk/src/gnc/mainwindow.cpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -1,23 +1,38 @@
-#include <QtGui>
+#include <QtGui/QToolBar>
+#include <QtGui/QMessageBox>
+#include <QtGui/QFileDialog>
+#include <QtCore/QSettings>
 
+#include "config.h"
 #include "mainwindow.hpp"
 #include "ui_mainwindow.h"
 
 // gnucash includes
-#include "config.h"
-extern "C" {
+extern "C"
+{
 #include <glib/gi18n.h>
 #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"
 }
 
+#include "gnc/Account.hpp"
+#include "gnc/Book.hpp"
+
 namespace gnc
 {
 
+inline QString errorToString(QofBackendError err)
+{
+    return QString::fromStdString(errorToStringPair(err).first);
+}
+inline QString errorToDescription(QofBackendError err)
+{
+    return QString::fromStdString(errorToStringPair(err).second);
+}
+
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = GNC_MOD_GUI;
 
@@ -37,7 +52,7 @@
 
     setWindowIcon(QIcon(":/pixmaps/gnucash-icon-32x32.png"));
 
-    setCurrentFile("");
+    newFile();
     setUnifiedTitleAndToolBarOnMac(true);
 }
 
@@ -45,33 +60,6 @@
 {
 }
 
-void MainWindow::closeEvent(QCloseEvent *event)
-{
-    if (maybeSave())
-    {
-        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
-    {
-        event->ignore();
-    }
-}
-
 void MainWindow::open()
 {
     if (maybeSave())
@@ -196,12 +184,56 @@
     return true;
 }
 
+void MainWindow::setCurrentFile(const QString &fileName)
+{
+    curFile = fileName;
+    ui->textEdit->document()->setModified(false);
+    setWindowModified(false);
+
+    QString shownName;
+    if (curFile.isEmpty())
+        shownName = "untitled.txt";
+    else
+        shownName = strippedName(curFile);
+
+    setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Application")));
+}
+
+QString MainWindow::strippedName(const QString &fullFileName)
+{
+    return QFileInfo(fullFileName).fileName();
+}
+
 // ////////////////////////////////////////////////////////////
 
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+    if (maybeSave())
+    {
+        writeSettings();
+        event->accept();
+
+        /* disable events; otherwise the mass deletion of accounts and
+         * transactions during shutdown would cause massive redraws */
+        qof_event_suspend ();
+
+        qof_session_call_close_hooks(m_session.get());
+        gnc_hook_run(HOOK_BOOK_CLOSED, m_session.get());
+
+        m_session.reset();
+
+        qof_event_resume ();
+    }
+    else
+    {
+        event->ignore();
+    }
+}
+
 static void
-gnc_book_opened (void)
+gnc_book_opened (Session& sess)
 {
-    gnc_hook_run(HOOK_BOOK_OPENED, gnc_get_current_session());
+    gnc_hook_run(HOOK_BOOK_OPENED, sess.get());
 }
 
 void MainWindow::newFile()
@@ -209,30 +241,29 @@
     if (maybeSave())
     {
 
-	if (gnc_current_session_exist()) {
-	    QofSession *session = gnc_get_current_session ();
+        if (m_session.get())
+        {
+            /* close any ongoing file sessions, and free the accounts.
+             * disable events so we don't get spammed by redraws. */
+            qof_event_suspend ();
 
-	    /* close any ongoing file sessions, and free the accounts.
-	     * disable events so we don't get spammed by redraws. */
-	    qof_event_suspend ();
+            m_session.call_close_hooks();
+            gnc_hook_run(HOOK_BOOK_CLOSED, m_session.get());
 
-	    qof_session_call_close_hooks(session);
-	    gnc_hook_run(HOOK_BOOK_CLOSED, session);
+            m_session.reset();
+            qof_event_resume ();
+        }
 
-	    gnc_clear_current_session();
-	    qof_event_resume ();
-	}
+        /* start a new book */
+        m_session.reset(Session::newInstance());
 
-	/* start a new book */
-	gnc_get_current_session ();
+        gnc_hook_run(HOOK_NEW_BOOK, NULL);
 
-	gnc_hook_run(HOOK_NEW_BOOK, NULL);
+        //gnc_gui_refresh_all ();
 
-	//gnc_gui_refresh_all ();
+        /* Call this after re-enabling events. */
+        gnc_book_opened (m_session);
 
-	/* Call this after re-enabling events. */
-	gnc_book_opened ();
-
         setCurrentFile("");
     }
 }
@@ -240,7 +271,7 @@
 void MainWindow::loadFile(const QString &fileName)
 {
     if (fileName.isEmpty())
-	return;
+        return;
 
     // copied from gnc_post_file_open, gnome-utils/gnc-file.c
 
@@ -254,58 +285,57 @@
 
     /* -------------- 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();
+    m_session.call_close_hooks();
+    gnc_hook_run(HOOK_BOOK_CLOSED, m_session.get());
+    m_session.reset();
 
     /* 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;
+    bool we_are_in_error = 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)
     {
-	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"));
+        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();
-	}
+                == 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))
+             (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);
-	}
+                                  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);
+        }
     }
 
     QApplication::setOverrideCursor(Qt::WaitCursor);
@@ -314,52 +344,63 @@
      * 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))
+            (ERR_BACKEND_READONLY == io_err) ||
+            (ERR_BACKEND_NO_SUCH_DB == io_err) ||
+            (ERR_SQL_DB_TOO_OLD == io_err))
     {
-	uh_oh = true;
+        we_are_in_error = 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 (io_err != ERR_BACKEND_NO_ERR)
+        {
+            we_are_in_error = !(QMessageBox::question(this, tr("Open anyway?"),
+                                tr("The file %1 has some errors: %2: %3. Open anyway?")
+                                .arg(fileName)
+                                .arg(errorToString(io_err))
+                                .arg(errorToDescription(io_err)))
+                                == QMessageBox::Ok);
+        }
     }
 
-    if (!uh_oh)
+    if (!we_are_in_error)
     {
-	::Account *new_root;
+        char * logpath = xaccResolveFilePath(newfile);
+        PINFO ("logpath=%s", logpath ? logpath : "(null)");
+        xaccLogSetBaseName (logpath);
+        xaccLogDisable();
 
-	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();
 
-	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);
 
-	/* 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 (io_err != ERR_BACKEND_NO_ERR)
+        {
+            we_are_in_error = !(QMessageBox::question(this, tr("Error on Open"),
+                                tr("There was an error opening the file %1: %2: %3. FIXME")
+                                .arg(fileName)
+                                .arg(errorToString(io_err))
+                                .arg(errorToDescription(io_err)))
+                                == QMessageBox::Ok);
+        }
     }
 
 
     /* 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);
+    m_session.reset(new_session);
 
+    ::Account * new_root = m_session.get_book().get_root_account().get();
+    if (we_are_in_error)
+        new_root = NULL;
+
     qof_event_resume ();
 
     /* Call this after re-enabling events. */
-    gnc_book_opened ();
+    gnc_book_opened (m_session);
 
     QApplication::restoreOverrideCursor();
 
@@ -381,7 +422,7 @@
     file.close();
     QApplication::setOverrideCursor(Qt::WaitCursor);
 
-    QofSession *session = gnc_get_current_session ();
+    QofSession *session = m_session.get();
     /* Make sure all of the data from the old file is loaded */
     qof_session_ensure_all_data_loaded(session);
 
@@ -398,25 +439,25 @@
     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);
-	}
+                                  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))
+             (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);
-	}
+        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
@@ -426,12 +467,15 @@
     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;
+        QMessageBox::critical(this, tr("Still in Error"),
+                              tr("The file %1 still cannot be written: %2: %3. FIXME")
+                              .arg(fileName)
+                              .arg(errorToString(io_err))
+                              .arg(errorToDescription(io_err)));
+        xaccLogDisable();
+        qof_session_destroy (new_session);
+        xaccLogEnable();
+        return false;
     }
 
     /* Prevent race condition between swapping the contents of the two
@@ -443,14 +487,14 @@
     /* 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();
+    m_session.reset();
     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);
+    m_session.reset(new_session);
 
     qof_event_resume();
 
@@ -464,24 +508,4 @@
     return true;
 }
 
-void MainWindow::setCurrentFile(const QString &fileName)
-{
-    curFile = fileName;
-    ui->textEdit->document()->setModified(false);
-    setWindowModified(false);
-
-    QString shownName;
-    if (curFile.isEmpty())
-        shownName = "untitled.txt";
-    else
-        shownName = strippedName(curFile);
-
-    setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Application")));
-}
-
-QString MainWindow::strippedName(const QString &fullFileName)
-{
-    return QFileInfo(fullFileName).fileName();
-}
-
 } // END namespace gnc

Modified: gnucash/trunk/src/gnc/mainwindow.hpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.hpp	2010-03-03 20:47:10 UTC (rev 18800)
+++ gnucash/trunk/src/gnc/mainwindow.hpp	2010-03-03 20:47:31 UTC (rev 18801)
@@ -3,6 +3,7 @@
 
 #include <QMainWindow>
 #include <QSharedPointer>
+#include "gnc/Session.hpp"
 
 class QAction;
 class QMenu;
@@ -55,6 +56,8 @@
 
     QToolBar *fileToolBar;
     QToolBar *editToolBar;
+
+    Session m_session;
 };
 
 } // END namespace gnc



More information about the gnucash-changes mailing list