r18926 - gnucash/trunk/src - Cutecash: Fix file loading, saving, and save-as. Works fine now.
Christian Stimming
cstim at code.gnucash.org
Wed Mar 17 15:24:01 EDT 2010
Author: cstim
Date: 2010-03-17 15:24:01 -0400 (Wed, 17 Mar 2010)
New Revision: 18926
Trac: http://svn.gnucash.org/trac/changeset/18926
Added:
gnucash/trunk/src/gnc/mainwindow-file.cpp
Modified:
gnucash/trunk/src/CMakeLists.txt
gnucash/trunk/src/core-utils/CMakeLists.txt
gnucash/trunk/src/gnc/CMakeLists.txt
gnucash/trunk/src/gnc/Cmd.cpp
gnucash/trunk/src/gnc/Numeric.hpp
gnucash/trunk/src/gnc/SplitListModel.cpp
gnucash/trunk/src/gnc/Transaction.hpp
gnucash/trunk/src/gnc/mainwindow.cpp
gnucash/trunk/src/gnc/mainwindow.hpp
gnucash/trunk/src/libqof/CMakeLists.txt
Log:
Cutecash: Fix file loading, saving, and save-as. Works fine now.
Also, use the new GDate setter/getter for the transaction time.
Modified: gnucash/trunk/src/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/CMakeLists.txt 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/CMakeLists.txt 2010-03-17 19:24:01 UTC (rev 18926)
@@ -126,9 +126,6 @@
")
ENDIF (UNIX)
-# Let cmake copy the created file only on changes.
-#CONFIGURE_FILE (${CONFIG_H} ${CMAKE_CURRENT_BINARY_DIR}/config.h COPYONLY)
-
# ############################################################
# The subdirectories
Modified: gnucash/trunk/src/core-utils/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/core-utils/CMakeLists.txt 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/core-utils/CMakeLists.txt 2010-03-17 19:24:01 UTC (rev 18926)
@@ -35,15 +35,13 @@
SET_SOURCE_FILES_PROPERTIES (${libgnc_core_utils_SOURCES} PROPERTIES OBJECT_DEPENDS ${CONFIG_H})
# Workaround to create a very simple gncla-dir.h file
-FILE (WRITE ${CMAKE_CURRENT_BINARY_DIR}/gncla-dir.h.tmp "
+FILE (WRITE ${CMAKE_CURRENT_BINARY_DIR}/gncla-dir.h "
#define PREFIX \"${CMAKE_INSTALL_PREFIX}\"
#define DATADIR \"${CMAKE_INSTALL_PREFIX}/share\"
#define SYSCONFDIR \"${CMAKE_INSTALL_PREFIX}/etc\"
#define LIBDIR \"${CMAKE_INSTALL_PREFIX}/lib\"
#define LOCALE_DATADIRNAME \"share\"
")
-# Let cmake copy the created file only on changes.
-CONFIGURE_FILE (${CMAKE_CURRENT_BINARY_DIR}/gncla-dir.h.tmp ${CMAKE_CURRENT_BINARY_DIR}/gncla-dir.h COPYONLY)
SET (libgnc_core_utils_HEADERS
binreloc.h
Modified: gnucash/trunk/src/gnc/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/gnc/CMakeLists.txt 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/CMakeLists.txt 2010-03-17 19:24:01 UTC (rev 18926)
@@ -21,6 +21,7 @@
SplitListModel.cpp
main.cpp
mainwindow.cpp
+ mainwindow-file.cpp
)
SET (gnc_QOBJECT_HEADERS
Modified: gnucash/trunk/src/gnc/Cmd.cpp
===================================================================
--- gnucash/trunk/src/gnc/Cmd.cpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/Cmd.cpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -175,7 +175,7 @@
{
return new Cmd<Transaction, QDate>(QObject::tr("Edit Transaction Date"),
t, &Transaction::setDatePosted,
- t.getDatePosted().date(), newValue);
+ t.getDatePosted(), newValue);
}
Modified: gnucash/trunk/src/gnc/Numeric.hpp
===================================================================
--- gnucash/trunk/src/gnc/Numeric.hpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/Numeric.hpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -63,6 +63,13 @@
result.setTimeSpec(Qt::UTC);
return result;
}
+inline QDate toQDate(const ::GDate& d)
+{
+ if (g_date_valid(&d))
+ return QDate(g_date_year(&d), g_date_month(&d), g_date_day(&d));
+ else
+ return QDate();
+}
inline ::Timespec toTimespec(const QDateTime& qdt)
{
::Timespec result;
Modified: gnucash/trunk/src/gnc/SplitListModel.cpp
===================================================================
--- gnucash/trunk/src/gnc/SplitListModel.cpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/SplitListModel.cpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -122,7 +122,7 @@
{
case Qt::DisplayRole:
case Qt::EditRole:
- return trans.getDatePosted().date();
+ return trans.getDatePosted();
default:
return QVariant();
}
@@ -307,7 +307,7 @@
Transaction trans = split.getParent();
Split other = split.getOtherSplit();
Q_ASSERT(other);
- Commodity originCommodity =split.getAccount().getCommodity();
+ Commodity originCommodity = split.getAccount().getCommodity();
Commodity transCommodity = trans.getCurrency();
Commodity otherCommodity = other.getAccount().getCommodity();
if (originCommodity != transCommodity
Modified: gnucash/trunk/src/gnc/Transaction.hpp
===================================================================
--- gnucash/trunk/src/gnc/Transaction.hpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/Transaction.hpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -87,10 +87,9 @@
bool isBalanced() const { return xaccTransIsBalanced(get()); }
Numeric getAccountConvRate(const Account& acc) const { return xaccTransGetAccountConvRate(get(), acc.get()); }
- void setDatePosted(const QDate& t) { xaccTransSetDatePostedSecs(get(), QDateTime(t, QTime(12,0,0)).toTime_t()); }
- void setDatePosted(const QDateTime& t) { xaccTransSetDatePostedSecs(get(), t.toTime_t()); }
+ void setDatePosted(const QDate& d) { xaccTransSetDate(get(), d.day(), d.month(), d.year()); }
void setDateEntered(const QDateTime& t) { xaccTransSetDateEnteredSecs(get(), t.toTime_t()); }
- QDateTime getDatePosted() const { return toQDateTime(xaccTransRetDatePostedTS(get())); }
+ QDate getDatePosted() const { return toQDate(xaccTransGetDatePostedGDate(get())); }
QDateTime getDateEntered() const { return toQDateTime(xaccTransRetDateEnteredTS(get())); }
};
Added: gnucash/trunk/src/gnc/mainwindow-file.cpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow-file.cpp (rev 0)
+++ gnucash/trunk/src/gnc/mainwindow-file.cpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -0,0 +1,774 @@
+/*
+ * mainwindow-file.cpp
+ * Copyright (C) 2010 Christian Stimming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation Voice: +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+ * Boston, MA 02110-1301, USA gnu at gnu.org
+ */
+
+#include <QtCore/QSettings>
+#include <QtGui/QCloseEvent>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtGui/QProgressBar>
+#include <QtGui/QPushButton>
+#include <QtGui/QToolBar>
+#include <QtGui/QUndoStack>
+#include <QDebug>
+
+#include "config.h"
+#include "mainwindow.hpp"
+#include "ui_mainwindow.h"
+
+// gnucash includes
+#include <glib/gi18n.h>
+extern "C"
+{
+#include "qof.h"
+#include "engine/gnc-hooks.h"
+#include "core-utils/gnc-uri-utils.h"
+#include "engine/Account.h"
+#include "engine/TransLog.h"
+}
+
+#include "gnc/Account.hpp"
+#include "gnc/AccountItemModel.hpp"
+#include "gnc/Book.hpp"
+#include "gnc/Numeric.hpp"
+#include "gnc/Split.hpp"
+#include "gnc/SplitListModel.hpp"
+#include "gnc/RecentFileMenu.hpp"
+
+#include "gnc/Cmd.hpp"
+
+namespace gnc
+{
+
+inline QString errorToString(QofBackendError err)
+{
+ return errorToStringPair(err).first;
+}
+inline QString errorToDescription(QofBackendError err)
+{
+ return errorToStringPair(err).second;
+}
+
+/* This static indicates the debugging module that this .o belongs to. */
+static QofLogModule log_module = GNC_MOD_GUI;
+static const char* PROPERTY_TAB_PREVIOUSPOS = "tab_previouspos";
+static gint save_in_progress = 0;
+
+// ////////////////////////////////////////////////////////////
+
+bool MainWindow::show_session_error (QWidget *parent,
+ ::QofBackendError io_error,
+ const QString& filename,
+ GNCFileDialogType type)
+{
+ bool should_abort = true;
+ QString fmt;
+
+ switch (io_error)
+ {
+ case ERR_BACKEND_NO_ERR:
+ should_abort = FALSE;
+ break;
+
+ case ERR_BACKEND_NO_HANDLER:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("No suitable backend was found for %1.").arg(filename));
+ break;
+
+ case ERR_BACKEND_NO_BACKEND:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The URL %1 is not supported by this version of GnuCash.").arg(filename));
+ break;
+
+ case ERR_BACKEND_BAD_URL:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("Can't parse the URL %1.").arg(filename));
+ break;
+
+ case ERR_BACKEND_CANT_CONNECT:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("Can't connect to %1. "
+ "The host, username or password were incorrect.").arg(filename));
+ break;
+
+ case ERR_BACKEND_CONN_LOST:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("Can't connect to %1. "
+ "Connection was lost, unable to send data.").arg(filename));
+ break;
+
+ case ERR_BACKEND_TOO_NEW:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("This file/URL appears to be from a newer version "
+ "of GnuCash. You must upgrade your version of GnuCash "
+ "to work with this data."));
+ break;
+
+ case ERR_BACKEND_NO_SUCH_DB:
+ if (QMessageBox::question(parent, tr("Create New File?"),
+ tr("The database %1 doesn't seem to exist. "
+ "Do you want to create it?").arg(filename),
+ QMessageBox::Ok | QMessageBox::Cancel)
+ == QMessageBox::Ok)
+ {
+ should_abort = false;
+ }
+ break;
+
+ case ERR_BACKEND_LOCKED:
+ switch (type)
+ {
+ case GNC_FILE_DIALOG_OPEN:
+ default:
+ fmt = tr("GnuCash could not obtain the lock for %1. "
+ "That database may be in use by another user, "
+ "in which case you should not open the database. "
+ "Do you want to proceed with opening the database?");
+ break;
+
+ case GNC_FILE_DIALOG_IMPORT:
+ fmt = tr("GnuCash could not obtain the lock for %1. "
+ "That database may be in use by another user, "
+ "in which case you should not import the database. "
+ "Do you want to proceed with importing the database?");
+ break;
+
+ case GNC_FILE_DIALOG_SAVE:
+ fmt = tr("GnuCash could not obtain the lock for %1. "
+ "That database may be in use by another user, "
+ "in which case you should not save the database. "
+ "Do you want to proceed with saving the database?");
+ break;
+
+ case GNC_FILE_DIALOG_EXPORT:
+ fmt = tr("GnuCash could not obtain the lock for %1. "
+ "That database may be in use by another user, "
+ "in which case you should not export the database. "
+ "Do you want to proceed with exporting the database?");
+ break;
+ }
+
+ if (QMessageBox::question(parent, tr("Create New File?"),
+ tr("The database %1 doesn't seem to exist. "
+ "Do you want to create it?").arg(filename),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
+ == QMessageBox::Yes)
+ {
+ should_abort = false;
+ }
+ break;
+
+ case ERR_BACKEND_READONLY:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("GnuCash could not write to %1. "
+ "That database may be on a read-only file system, "
+ "or you may not have write permission for the directory.").arg(filename));
+ break;
+
+ case ERR_BACKEND_DATA_CORRUPT:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The file/URL %1 "
+ "does not contain GnuCash data or the data is corrupt.").arg(filename));
+ break;
+
+ case ERR_BACKEND_SERVER_ERR:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The server at URL %1 "
+ "experienced an error or encountered bad or corrupt data.").arg(filename));
+ break;
+
+ case ERR_BACKEND_PERM:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("You do not have permission to access %1.").arg(filename));
+ break;
+
+ case ERR_BACKEND_MISC:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("An error occurred while processing %1.").arg(filename));
+ break;
+
+
+ case ERR_FILEIO_FILE_BAD_READ:
+ if (QMessageBox::question(parent, tr("Continue?"),
+ tr("There was an error reading the file. "
+ "Do you want to continue?"),
+ QMessageBox::Ok | QMessageBox::Cancel)
+ == QMessageBox::Ok)
+ {
+ should_abort = false;
+ }
+ break;
+
+ case ERR_FILEIO_PARSE_ERROR:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("There was an error parsing the file %1.").arg(filename));
+ break;
+
+ case ERR_FILEIO_FILE_EMPTY:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The file %1 is empty.").arg(filename));
+ break;
+
+ case ERR_FILEIO_FILE_NOT_FOUND:
+ if (type == GNC_FILE_DIALOG_SAVE)
+ {
+ should_abort = false;
+ }
+ else
+ {
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The file %1 could not be found.").arg(filename));
+ }
+ break;
+
+ case ERR_FILEIO_FILE_TOO_OLD:
+ if (QMessageBox::question(parent, tr("Continue?"),
+ tr("This file is from an older version of GnuCash. "
+ "Do you want to continue?"),
+ QMessageBox::Ok | QMessageBox::Cancel)
+ == QMessageBox::Ok)
+ {
+ should_abort = false;
+ }
+ break;
+
+ case ERR_FILEIO_UNKNOWN_FILE_TYPE:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The file type of file %1 is unknown.").arg(filename));
+ break;
+
+ case ERR_FILEIO_BACKUP_ERROR:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("Could not make a backup of the file %1").arg(filename));
+ break;
+
+ case ERR_FILEIO_WRITE_ERROR:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("Could not write to file %1. Check that you have "
+ "permission to write to this file and that "
+ "there is sufficient space to create it.").arg(filename));
+ break;
+
+ case ERR_FILEIO_FILE_EACCES:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("No read permission to read from file %1.").arg(filename));
+ break;
+
+ case ERR_SQL_DB_TOO_OLD:
+ if (QMessageBox::question(parent, tr("Upgrade Database?"),
+ tr("This database is from an older version of GnuCash. "
+ "Do you want to want to upgrade the database "
+ "to the current version?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
+ == QMessageBox::Yes)
+ {
+ should_abort = false;
+ }
+ break;
+
+ case ERR_SQL_DB_BUSY:
+ QMessageBox::critical(parent, tr("Error"),
+ tr("The SQL database is in use by other users, "
+ "and the upgrade cannot be performed until they logoff. "
+ "If there are currently no other users, consult the "
+ "documentation to learn how to clear out dangling login "
+ "sessions."));
+ break;
+
+ default:
+ PERR("FIXME: Unhandled error %d", io_error);
+ QMessageBox::critical(parent, tr("Error"),
+ tr("An unknown I/O error (%1) occurred.").arg(int(io_error)));
+ break;
+ }
+
+ return should_abort;
+}
+
+// ////////////////////////////////////////////////////////////
+
+
+static void
+gnc_book_opened (Session& sess)
+{
+ gnc_hook_run(HOOK_BOOK_OPENED, sess.get());
+}
+
+
+namespace
+{
+/** This is a workaround function object so that we can obtain a
+ * QofPercentageFunc without extra boost::bind usage; obviously due to
+ * the static member variable it will not work if multiple instances
+ * are in use simultaneously */
+class progress_functor
+{
+public:
+ progress_functor(QProgressBar *progressBar)
+ {
+ m_progressBar = progressBar;
+ }
+ ~progress_functor()
+ {
+ m_progressBar = NULL;
+ }
+ static void static_func(const char *message, double percent)
+ {
+ assert(m_progressBar);
+ m_progressBar->setValue(int(percent));
+ // Give the Qt event loop some time
+ qApp->processEvents();
+ }
+private:
+ static QProgressBar *m_progressBar;
+};
+QProgressBar *progress_functor::m_progressBar = NULL;
+
+} // END namespace anonymous
+
+
+void MainWindow::loadFile(const QString &fileName)
+{
+ if (fileName.isEmpty())
+ return;
+
+ // copied from gnc_post_file_open, gnome-utils/gnc-file.c
+
+ QString newfile_qstring =
+ gchar_to_QString(gnc_uri_normalize_uri(fileName.toUtf8(), TRUE));
+ if (newfile_qstring.isEmpty())
+ {
+ show_session_error (this, ERR_FILEIO_FILE_NOT_FOUND, fileName,
+ GNC_FILE_DIALOG_OPEN);
+ return;
+ }
+ QByteArray newfile = newfile_qstring.toUtf8();
+
+ /* 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 cusor
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ /* -------------- BEGIN CORE SESSION CODE ------------- */
+ /* -- this code is almost identical in FileOpen and FileSaveAs -- */
+ m_session.call_close_hooks();
+ gnc_hook_run(HOOK_BOOK_CLOSED, m_session.get());
+ qof_session_destroy(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 we_are_in_error = false;
+ 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?")
+ : 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?"));
+ QMessageBox msgBox;
+ QPushButton *openAnyway = msgBox.addButton(tr("_Open Anyway"), QMessageBox::ActionRole);
+ QPushButton *createNewFile = msgBox.addButton(tr("_Create New File"), QMessageBox::ActionRole);
+ QPushButton *close = msgBox.addButton(QMessageBox::Close);
+ msgBox.exec();
+ if (msgBox.clickedButton() == openAnyway)
+ {
+ /* user told us to ignore locks. So ignore them. */
+ qof_session_begin (new_session, newfile, TRUE, FALSE);
+ }
+ else if (msgBox.clickedButton() == createNewFile)
+ {
+ /* 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();
+ return;
+ }
+ else
+ {
+ qApp->quit();
+ return;
+ }
+ }
+
+ if (ERR_QSF_OPEN_NOT_MERGE == io_err)
+ {
+ we_are_in_error = true;
+ }
+ /* 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 (false == show_session_error (this, io_err, newfile, GNC_FILE_DIALOG_OPEN))
+ {
+ /* user told us to create a new database. Do it. */
+ qof_session_begin (new_session, newfile, FALSE, TRUE);
+ }
+ }
+
+ /* 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))
+ {
+ we_are_in_error = true;
+ }
+ else
+ {
+ we_are_in_error = show_session_error (this, io_err, newfile, GNC_FILE_DIALOG_OPEN);
+ }
+
+ if (!we_are_in_error)
+ {
+ gchar *logpath = NULL;
+ if ( gnc_uri_is_file_uri ( newfile ) )
+ logpath = gnc_uri_get_path(newfile);
+ PINFO ("logpath=%s", logpath ? logpath : "(null)");
+ xaccLogSetBaseName (logpath);
+ g_free ( logpath );
+
+ xaccLogDisable();
+
+ {
+ // Set up a progress bar in the statusBar()
+ QProgressBar progressBar;
+ progressBar.setMinimum(0);
+ progressBar.setMaximum(100);
+ statusBar()->showMessage(tr("Loading user data..."));
+ statusBar()->addPermanentWidget(&progressBar);
+ progressBar.show();
+ // This local progress_functor is a workaround on how to
+ // pass the suitable function pointer to session_load -
+ // not very nice because of its static member, but it does
+ // the trick for now.
+ progress_functor functor(&progressBar);
+
+ // Do the loading.
+ qof_session_load (new_session, &progress_functor::static_func);
+
+ // Remove the progress bar again from the status bar.
+ statusBar()->removeWidget(&progressBar);
+ }
+ xaccLogEnable();
+
+ /* check for i/o error, put up appropriate error dialog */
+ io_err = qof_session_get_error (new_session);
+
+ we_are_in_error = show_session_error(this, io_err, newfile, GNC_FILE_DIALOG_OPEN);
+
+ ::Account* new_root_account = gnc_book_get_root_account (qof_session_get_book (new_session));
+ if (we_are_in_error) new_root_account = NULL;
+
+ /* Umm, came up empty-handed, but no error:
+ * The backend forgot to set an error. So make one up. */
+ if (!we_are_in_error && !new_root_account)
+ {
+ we_are_in_error = show_session_error (this, ERR_BACKEND_MISC, newfile,
+ GNC_FILE_DIALOG_OPEN);
+ }
+ }
+
+ QApplication::restoreOverrideCursor();
+
+ /* going down -- abandon ship */
+ if (we_are_in_error)
+ {
+ xaccLogDisable();
+ qof_session_destroy (new_session);
+ xaccLogEnable();
+
+ /* well, no matter what, I think it's a good idea to have a root
+ * account around. For example, early in the gnucash startup
+ * sequence, the user opens a file; if this open fails for any
+ * reason, we don't want to leave them high & dry without a root
+ * account, because if the user continues, then bad things will
+ * happen. */
+ new_session = qof_session_new ();
+ m_session.reset(new_session);
+
+ qof_event_resume ();
+ return;
+ }
+
+ /* if we got to here, then we've successfully gotten a new session */
+ /* close up the old file session (if any) */
+ m_session.reset(new_session);
+
+ qof_event_resume ();
+
+ /* Call this after re-enabling events. */
+ gnc_book_opened (m_session);
+
+ // ////////////////////////////////////////////////////////////
+ // Some display about this file
+
+ Account root (m_session.get_book().get_root_account());
+ if (root)
+ {
+ m_accountListModel = new AccountListModel(root, this);
+ ui->tableView->setModel(m_accountListModel);
+
+ m_accountTreeModel = new AccountTreeModel(root, this);
+ ui->treeView->setModel(m_accountTreeModel);
+
+ ui->treeViewTab->setProperty(PROPERTY_TAB_PREVIOUSPOS, ui->tabWidget->currentIndex());
+ ui->tabWidget->setCurrentWidget(ui->treeViewTab);
+ }
+ else
+ {
+ //ui->labelMain->setText(tr("No root account"));
+ }
+
+ // ////////////////////////////////////////////////////////////
+
+ setCurrentFile(fileName);
+ statusBar()->showMessage(tr("File loaded"), 5000);
+}
+
+
+// ////////////////////////////////////////////////////////////
+
+bool MainWindow::saveFileAs(const QString &fileName)
+{
+ if (gnc_uri_is_file_uri(fileName.toUtf8()))
+ {
+ QFile file(gchar_to_QString(gnc_uri_get_path(fileName.toUtf8())));
+ if (!file.open(QFile::WriteOnly))
+ {
+ QMessageBox::warning(this, tr("Application"),
+ tr("Cannot write file %1:\n%2.")
+ .arg(fileName)
+ .arg(file.errorString()));
+ return false;
+ }
+ file.close();
+ }
+
+ /* Check to see if the user specified the same file as the current
+ * file. If so, then just do a simple save, instead of a full save as */
+ /* FIXME Check if it is ok to have a password in the uri here */
+ QString newfile_qstring =
+ gchar_to_QString(gnc_uri_normalize_uri ( fileName.toUtf8(), TRUE ));
+ if (newfile_qstring.isEmpty())
+ {
+ show_session_error (this, ERR_FILEIO_FILE_NOT_FOUND, fileName,
+ GNC_FILE_DIALOG_SAVE);
+ return false;
+ }
+ QByteArray newfile = newfile_qstring.toUtf8();
+
+ QofSession *session = m_session.get();
+ if (m_session.get_url() == fileName)
+ {
+ return saveFile();
+ }
+
+ /* 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 -- */
+
+ save_in_progress++;
+ 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 (false == show_session_error (this, io_err, newfile, GNC_FILE_DIALOG_SAVE))
+ {
+ /* 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 (false == show_session_error (this, io_err, newfile, GNC_FILE_DIALOG_SAVE))
+ {
+ /* 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)
+ {
+ show_session_error (this, io_err, newfile, GNC_FILE_DIALOG_SAVE);
+ xaccLogDisable();
+ qof_session_destroy (new_session);
+ xaccLogEnable();
+ save_in_progress--;
+ return false;
+ }
+
+ /* oops ... file already exists ... ask user what to do... */
+ if (qof_session_save_may_clobber_data (new_session))
+ {
+ if (QMessageBox::question(this, tr("File Exists"),
+ tr("The file %1 already exists. "
+ "Are you sure you want to overwrite it?").arg(fileName),
+ QMessageBox::Yes | QMessageBox::No)
+ != QMessageBox::Yes)
+ {
+ /* if user says cancel, we should break out */
+ xaccLogDisable();
+ qof_session_destroy (new_session);
+ xaccLogEnable();
+ save_in_progress--;
+ return false;
+ }
+
+ /* Whoa-ok. Blow away the previous file. */
+ }
+
+ /* XXX Would logging make sense for databases as well (mysql/postgres) ?
+ * Currently the logpath is relative to the data file path.
+ * Databases don't have a file path, so no logging will be
+ * done for them in the current setup.
+ */
+ gchar *logpath = NULL;
+ if ( gnc_uri_is_file_uri ( newfile ) )
+ logpath = gnc_uri_get_path(newfile);
+ PINFO ("logpath=%s", logpath ? logpath : "(null)");
+ xaccLogSetBaseName (logpath);
+ g_free ( logpath );
+
+
+ /* 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);
+ qof_session_destroy(m_session.get());
+ 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...
+ */
+ m_session.reset(new_session);
+
+ qof_event_resume();
+
+ /* --------------- END CORE SESSION CODE -------------- */
+
+ bool r = saveFile();
+
+ save_in_progress--;
+ setCurrentFile(fileName);
+ return r;
+}
+
+static bool been_here_before = false;
+
+bool MainWindow::saveFile()
+{
+ /* hack alert -- Somehow make sure all in-progress edits get committed! */
+
+ /* If we don't have a filename/path to save to get one. */
+ if (m_session.get_url().isEmpty())
+ return on_actionSave_as_triggered();
+
+ /* use the current session to save to file */
+ save_in_progress++;
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ {
+ // Set up a progress bar in the statusBar()
+ QProgressBar progressBar;
+ progressBar.setMinimum(0);
+ progressBar.setMaximum(100);
+ statusBar()->showMessage(tr("Saving user data..."));
+ statusBar()->addPermanentWidget(&progressBar);
+ progressBar.show();
+ // A local progress_functor to pass the suitable function
+ // pointer to session_load
+ progress_functor functor(&progressBar);
+
+ // The actual saving
+ qof_session_save (m_session.get(), &progress_functor::static_func);
+
+ // Remove the progress bar again from the status bar.
+ statusBar()->removeWidget(&progressBar);
+ }
+
+ // And saving is finished
+ QApplication::restoreOverrideCursor();
+ save_in_progress--;
+
+
+ /* Make sure everything's OK - disk could be full, file could have
+ become read-only etc. */
+ QofBackendError io_err = m_session.get_error ();
+ if (ERR_BACKEND_NO_ERR != io_err)
+ {
+ show_session_error (this, io_err, m_session.get_url(), GNC_FILE_DIALOG_SAVE);
+
+ if (been_here_before)
+ return true;
+ been_here_before = true;
+ on_actionSave_as_triggered();
+ /* been_here prevents infinite recursion */
+ been_here_before = false;
+ return true;
+ }
+
+ xaccReopenLog();
+ gnc_hook_run(HOOK_BOOK_SAVED, m_session.get());
+
+ statusBar()->showMessage(tr("File saved"), 5000);
+ return true;
+}
+
+} // END namespace gnc
Modified: gnucash/trunk/src/gnc/mainwindow.cpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.cpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/mainwindow.cpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -136,7 +136,7 @@
}
else
{
- return saveFile(m_currentFilename);
+ return saveFile();
}
}
@@ -147,7 +147,7 @@
if (fileName.isEmpty())
return false;
- return saveFile(fileName);
+ return saveFileAs(fileName);
}
// Auto-connected to ui->actionAbout's signal triggered()
@@ -469,12 +469,6 @@
}
}
-static void
-gnc_book_opened (Session& sess)
-{
- gnc_hook_run(HOOK_BOOK_OPENED, sess.get());
-}
-
void MainWindow::newFile()
{
if (maybeSave())
@@ -500,334 +494,10 @@
gnc_hook_run(HOOK_NEW_BOOK, NULL);
/* Call this after re-enabling events. */
- gnc_book_opened (m_session);
+ gnc_hook_run(HOOK_BOOK_OPENED, m_session.get());
setCurrentFile("");
}
}
-namespace
-{
-/** This is a workaround function object so that we can obtain a
- * QofPercentageFunc without extra boost::bind usage; obviously due to
- * the static member variable it will not work if multiple instances
- * are in use simultaneously */
-class progress_functor
-{
-public:
- progress_functor(QProgressBar *progressBar)
- {
- m_progressBar = progressBar;
- }
- ~progress_functor()
- {
- m_progressBar = NULL;
- }
- static void static_func(const char *message, double percent)
- {
- assert(m_progressBar);
- m_progressBar->setValue(int(percent));
- // Give the Qt event loop some time
- qApp->processEvents();
- }
-private:
- static QProgressBar *m_progressBar;
-};
-QProgressBar *progress_functor::m_progressBar = NULL;
-
-} // END namespace anonymous
-
-
-void MainWindow::loadFile(const QString &fileName)
-{
- 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 -- */
- m_session.call_close_hooks();
- gnc_hook_run(HOOK_BOOK_CLOSED, m_session.get());
- qof_session_destroy(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 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"));
- if (QMessageBox::question(this, fmt1, fmt2,
- QMessageBox::Ok | QMessageBox::Cancel)
- == 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 | QMessageBox::Cancel)
- == QMessageBox::Ok)
- {
- /* user told us to create a new database. Do it. */
- qof_session_begin (new_session, newfile, FALSE, TRUE);
- }
- }
-
- QApplication::setOverrideCursor(Qt::WaitCursor);
- /* 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))
- {
- we_are_in_error = true;
- }
- else
- {
- 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 | QMessageBox::Cancel)
- == QMessageBox::Ok);
- }
- }
-
- if (!we_are_in_error)
- {
- char * logpath = gnc_uri_get_path(newfile);
- PINFO ("logpath=%s", logpath ? logpath : "(null)");
- xaccLogSetBaseName (logpath);
- xaccLogDisable();
-
- {
- // Set up a progress bar in the statusBar()
- QProgressBar progressBar;
- progressBar.setMinimum(0);
- progressBar.setMaximum(100);
- statusBar()->showMessage(tr("Loading user data..."));
- statusBar()->addPermanentWidget(&progressBar);
- progressBar.show();
- // This local progress_functor is a workaround on how to
- // pass the suitable function pointer to session_load -
- // not very nice because of its static member, but it does
- // the trick for now.
- progress_functor functor(&progressBar);
-
- // Do the loading.
- qof_session_load (new_session, &progress_functor::static_func);
-
- // Remove the progress bar again from the status bar. No
- // explicit delete necessary because it is just a local
- // variable.
- statusBar()->removeWidget(&progressBar);
- }
- xaccLogEnable();
-
- /* check for i/o error, put up appropriate error dialog */
- io_err = qof_session_get_error (new_session);
-
- 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. Continue? FIXME")
- .arg(fileName)
- .arg(errorToString(io_err))
- .arg(errorToDescription(io_err)),
- QMessageBox::Ok | QMessageBox::Cancel)
- == QMessageBox::Ok);
- }
- }
-
-
- /* if we got to here, then we've successfully gotten a new session */
- /* close up the old file session (if any) */
- if (m_session.get())
- {
- qof_session_destroy(m_session.get());
- m_session.reset();
- }
- m_session.reset(new_session);
-
- qof_event_resume ();
-
- /* Call this after re-enabling events. */
- gnc_book_opened (m_session);
-
- // ////////////////////////////////////////////////////////////
- // Some display about this file
-
- Account root (m_session.get_book().get_root_account());
- if (root)
- {
- m_accountListModel = new AccountListModel(root, this);
- ui->tableView->setModel(m_accountListModel);
-
- m_accountTreeModel = new AccountTreeModel(root, this);
- ui->treeView->setModel(m_accountTreeModel);
-
- ui->treeViewTab->setProperty(PROPERTY_TAB_PREVIOUSPOS, ui->tabWidget->currentIndex());
- ui->tabWidget->setCurrentWidget(ui->treeViewTab);
- }
- else
- {
- //ui->labelMain->setText(tr("No root account"));
- }
-
- // ////////////////////////////////////////////////////////////
-
- QApplication::restoreOverrideCursor();
-
- setCurrentFile(fileName);
- statusBar()->showMessage(tr("File loaded"), 5000);
-}
-
-bool MainWindow::saveFile(const QString &fileName)
-{
- QFile file(fileName);
- if (!file.open(QFile::WriteOnly))
- {
- QMessageBox::warning(this, tr("Application"),
- tr("Cannot write file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
- return false;
- }
- file.close();
- QApplication::setOverrideCursor(Qt::WaitCursor);
-
- QofSession *session = m_session.get();
- /* 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 | QMessageBox::Cancel)
- == 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),
- QMessageBox::Ok | QMessageBox::Cancel)
- == QMessageBox::Ok)
- {
- /* 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: %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
- * 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);
- qof_session_destroy(m_session.get());
- 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...
- */
- m_session.reset(new_session);
-
- qof_event_resume();
-
- /* --------------- END CORE SESSION CODE -------------- */
-
-
- QApplication::restoreOverrideCursor();
-
- setCurrentFile(fileName);
- statusBar()->showMessage(tr("File saved"), 2000);
- return true;
-}
-
} // END namespace gnc
Modified: gnucash/trunk/src/gnc/mainwindow.hpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.hpp 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/gnc/mainwindow.hpp 2010-03-17 19:24:01 UTC (rev 18926)
@@ -87,14 +87,28 @@
void readSettings();
void writeSettings();
bool maybeSave();
- void loadFile(const QString &fileName);
- bool saveFile(const QString &fileName);
void setCurrentFile(const QString &fileName);
QString strippedName(const QString &fullFileName);
void viewOrHideTab(bool checkedView, QWidget *widget);
void reallyRemoveTab(int index);
void updateWindowTitle();
+ void loadFile(const QString &fileName);
+ bool saveFile();
+ bool saveFileAs(const QString &fileName);
+
+ typedef enum
+ {
+ GNC_FILE_DIALOG_OPEN,
+ GNC_FILE_DIALOG_IMPORT,
+ GNC_FILE_DIALOG_SAVE,
+ GNC_FILE_DIALOG_EXPORT
+ } GNCFileDialogType;
+ static bool show_session_error (QWidget *parent,
+ ::QofBackendError io_error,
+ const QString& newfile,
+ GNCFileDialogType type);
+
Ui::MainWindow *ui;
QString m_currentFilename;
Modified: gnucash/trunk/src/libqof/CMakeLists.txt
===================================================================
--- gnucash/trunk/src/libqof/CMakeLists.txt 2010-03-17 19:23:40 UTC (rev 18925)
+++ gnucash/trunk/src/libqof/CMakeLists.txt 2010-03-17 19:24:01 UTC (rev 18926)
@@ -10,11 +10,9 @@
# Workaround to create a very simple gncla-dir.h file
-FILE (WRITE ${CMAKE_CURRENT_BINARY_DIR}/qofla-dir.h.tmp "
+FILE (WRITE ${CMAKE_CURRENT_BINARY_DIR}/qofla-dir.h "
#define QOF_LIB_DIR \"${CMAKE_INSTALL_PREFIX}/lib/gnucash\"
")
-# Let cmake copy the created file only on changes.
-CONFIGURE_FILE (${CMAKE_CURRENT_BINARY_DIR}/qofla-dir.h.tmp ${CMAKE_CURRENT_BINARY_DIR}/qofla-dir.h COPYONLY)
INCLUDE_DIRECTORIES (${CMAKE_CURRENT_BINARY_DIR}) # for qofla-dir.h
More information about the gnucash-changes
mailing list