mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Cutecash: Fix file loading, saving, and save-as. Works fine now.
Also, use the new GDate setter/getter for the transaction time. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18926 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
59be2dc692
commit
4e3be7b89c
@ -126,9 +126,6 @@ IF (UNIX)
|
|||||||
")
|
")
|
||||||
ENDIF (UNIX)
|
ENDIF (UNIX)
|
||||||
|
|
||||||
# Let cmake copy the created file only on changes.
|
|
||||||
#CONFIGURE_FILE (${CONFIG_H} ${CMAKE_CURRENT_BINARY_DIR}/config.h COPYONLY)
|
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
# The subdirectories
|
# The subdirectories
|
||||||
|
@ -35,15 +35,13 @@ SET (libgnc_core_utils_SOURCES
|
|||||||
SET_SOURCE_FILES_PROPERTIES (${libgnc_core_utils_SOURCES} PROPERTIES OBJECT_DEPENDS ${CONFIG_H})
|
SET_SOURCE_FILES_PROPERTIES (${libgnc_core_utils_SOURCES} PROPERTIES OBJECT_DEPENDS ${CONFIG_H})
|
||||||
|
|
||||||
# Workaround to create a very simple gncla-dir.h file
|
# 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 PREFIX \"${CMAKE_INSTALL_PREFIX}\"
|
||||||
#define DATADIR \"${CMAKE_INSTALL_PREFIX}/share\"
|
#define DATADIR \"${CMAKE_INSTALL_PREFIX}/share\"
|
||||||
#define SYSCONFDIR \"${CMAKE_INSTALL_PREFIX}/etc\"
|
#define SYSCONFDIR \"${CMAKE_INSTALL_PREFIX}/etc\"
|
||||||
#define LIBDIR \"${CMAKE_INSTALL_PREFIX}/lib\"
|
#define LIBDIR \"${CMAKE_INSTALL_PREFIX}/lib\"
|
||||||
#define LOCALE_DATADIRNAME \"share\"
|
#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
|
SET (libgnc_core_utils_HEADERS
|
||||||
binreloc.h
|
binreloc.h
|
||||||
|
@ -21,6 +21,7 @@ SET (gnc_SOURCES
|
|||||||
SplitListModel.cpp
|
SplitListModel.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
|
mainwindow-file.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET (gnc_QOBJECT_HEADERS
|
SET (gnc_QOBJECT_HEADERS
|
||||||
|
@ -175,7 +175,7 @@ QUndoCommand* setTransactionDate(Transaction& t, const QDate& newValue)
|
|||||||
{
|
{
|
||||||
return new Cmd<Transaction, QDate>(QObject::tr("Edit Transaction Date"),
|
return new Cmd<Transaction, QDate>(QObject::tr("Edit Transaction Date"),
|
||||||
t, &Transaction::setDatePosted,
|
t, &Transaction::setDatePosted,
|
||||||
t.getDatePosted().date(), newValue);
|
t.getDatePosted(), newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,6 +63,13 @@ inline QDateTime toQDateTime(const ::Timespec& timespec)
|
|||||||
result.setTimeSpec(Qt::UTC);
|
result.setTimeSpec(Qt::UTC);
|
||||||
return result;
|
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)
|
inline ::Timespec toTimespec(const QDateTime& qdt)
|
||||||
{
|
{
|
||||||
::Timespec result;
|
::Timespec result;
|
||||||
|
@ -122,7 +122,7 @@ QVariant SplitListModel::data(const QModelIndex& index, int role) const
|
|||||||
{
|
{
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
return trans.getDatePosted().date();
|
return trans.getDatePosted();
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ bool SplitListModel::setData(const QModelIndex &index, const QVariant &value, in
|
|||||||
Transaction trans = split.getParent();
|
Transaction trans = split.getParent();
|
||||||
Split other = split.getOtherSplit();
|
Split other = split.getOtherSplit();
|
||||||
Q_ASSERT(other);
|
Q_ASSERT(other);
|
||||||
Commodity originCommodity =split.getAccount().getCommodity();
|
Commodity originCommodity = split.getAccount().getCommodity();
|
||||||
Commodity transCommodity = trans.getCurrency();
|
Commodity transCommodity = trans.getCurrency();
|
||||||
Commodity otherCommodity = other.getAccount().getCommodity();
|
Commodity otherCommodity = other.getAccount().getCommodity();
|
||||||
if (originCommodity != transCommodity
|
if (originCommodity != transCommodity
|
||||||
|
@ -87,10 +87,9 @@ public:
|
|||||||
bool isBalanced() const { return xaccTransIsBalanced(get()); }
|
bool isBalanced() const { return xaccTransIsBalanced(get()); }
|
||||||
Numeric getAccountConvRate(const Account& acc) const { return xaccTransGetAccountConvRate(get(), acc.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 QDate& d) { xaccTransSetDate(get(), d.day(), d.month(), d.year()); }
|
||||||
void setDatePosted(const QDateTime& t) { xaccTransSetDatePostedSecs(get(), t.toTime_t()); }
|
|
||||||
void setDateEntered(const QDateTime& t) { xaccTransSetDateEnteredSecs(get(), t.toTime_t()); }
|
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())); }
|
QDateTime getDateEntered() const { return toQDateTime(xaccTransRetDateEnteredTS(get())); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
774
src/gnc/mainwindow-file.cpp
Normal file
774
src/gnc/mainwindow-file.cpp
Normal file
@ -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@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
|
@ -136,7 +136,7 @@ bool MainWindow::on_actionSave_triggered()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return saveFile(m_currentFilename);
|
return saveFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ bool MainWindow::on_actionSave_as_triggered()
|
|||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return saveFile(fileName);
|
return saveFileAs(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-connected to ui->actionAbout's signal triggered()
|
// Auto-connected to ui->actionAbout's signal triggered()
|
||||||
@ -469,12 +469,6 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gnc_book_opened (Session& sess)
|
|
||||||
{
|
|
||||||
gnc_hook_run(HOOK_BOOK_OPENED, sess.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::newFile()
|
void MainWindow::newFile()
|
||||||
{
|
{
|
||||||
if (maybeSave())
|
if (maybeSave())
|
||||||
@ -500,334 +494,10 @@ void MainWindow::newFile()
|
|||||||
gnc_hook_run(HOOK_NEW_BOOK, NULL);
|
gnc_hook_run(HOOK_NEW_BOOK, NULL);
|
||||||
|
|
||||||
/* Call this after re-enabling events. */
|
/* Call this after re-enabling events. */
|
||||||
gnc_book_opened (m_session);
|
gnc_hook_run(HOOK_BOOK_OPENED, m_session.get());
|
||||||
|
|
||||||
setCurrentFile("");
|
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
|
} // END namespace gnc
|
||||||
|
@ -87,14 +87,28 @@ private:
|
|||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
bool maybeSave();
|
bool maybeSave();
|
||||||
void loadFile(const QString &fileName);
|
|
||||||
bool saveFile(const QString &fileName);
|
|
||||||
void setCurrentFile(const QString &fileName);
|
void setCurrentFile(const QString &fileName);
|
||||||
QString strippedName(const QString &fullFileName);
|
QString strippedName(const QString &fullFileName);
|
||||||
void viewOrHideTab(bool checkedView, QWidget *widget);
|
void viewOrHideTab(bool checkedView, QWidget *widget);
|
||||||
void reallyRemoveTab(int index);
|
void reallyRemoveTab(int index);
|
||||||
void updateWindowTitle();
|
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;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
QString m_currentFilename;
|
QString m_currentFilename;
|
||||||
|
@ -10,11 +10,9 @@ INCLUDE_DIRECTORIES (${CMAKE_SOURCE_DIR}/lib/libc) # for strptime.h
|
|||||||
|
|
||||||
|
|
||||||
# Workaround to create a very simple gncla-dir.h file
|
# 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\"
|
#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
|
INCLUDE_DIRECTORIES (${CMAKE_CURRENT_BINARY_DIR}) # for qofla-dir.h
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user