GSoC Cutecash project by Nitish Dodagatta (last half)

Summary of the project by the GSoC student, copied
from http://wiki.gnucash.org/wiki/GSoC2011#Student_Summaries :

A new user interface for Gnucash core using Qt/C++ was started by one
of the Gnucash developers in 2010. [1] The idea is to create a
lightweight user friendly UI, reusing the backend core API of
Gnucash. During the project, I created a widget to allow a user to add
two split transaction to/from different accounts. After that I worked
on adding an overview widget showing a list of recent transactions
entered. It consists of two report views containing income and
expense. This view also called as First Person Overview provides an
easy to browse list of transactions. The idea is to integrate common
handy features with these views. The present view lists four entries
for each transaction: date of the transaction, transaction
description, split account name and split amount. Each of the entries
are inside their own QWidget, so as to allow interactive features to
be coded on each of the entries.

The already existing code had some C++ wrappers to convert the return
values of C functions to Qt data types. I made use of them whenever
possible. And at some parts of the code I used the C functions
directly where it made things easier for me. The FPO consists of one
or more viewlets. A viewlet is nothing but a list of transactions, a
slightly minified version of General Journal, to easily browse
transactions sorted by date. The viewlet generator function works such
that there is no date entry or account name entry, if it is the same
as the previous (above) one. This information is then used by
ViewletView to generate the UI part. To make the views visually
appealing and readable, QStyleSheets are used which distinguishes the
various types of entries in the viewlet.

Overall, it was a rewarding experience, I learned a lot of new things,
common pitfalls, handy tips and tricks, and a better understanding of
the Gnucash core API . The project was observed only by myself and my
mentor. During the course I also generated windows builds for two of
my friends who were interested to have a look at the features
implemented. I received positive feedback from them and couple of
feature requests from them. Working on this project within GSoC was a
rewarding experience. I thank my mentor Christian Stimming for guiding
me along and giving very helpful advices and hints during the
summer. I definitely would like to continue contributing to Gnucash
community in future.

[1] http://wiki.gnucash.org/wiki/Cutecash

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@21241 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Christian Stimming 2011-09-07 18:03:20 +00:00
parent 3ac46f5572
commit b2e8c5d2de
20 changed files with 1501 additions and 210 deletions

View File

@ -29,6 +29,9 @@ SET (gnc_SOURCES
mainwindow.cpp
mainwindow-file.cpp
dashboard.cpp
fpo/FPO.cpp
fpo/ViewletModel.cpp
fpo/ViewletView.cpp
)
SET (gnc_QOBJECT_HEADERS
@ -39,6 +42,9 @@ SET (gnc_QOBJECT_HEADERS
SplitListView.hpp
mainwindow.hpp
dashboard.hpp
fpo/FPO.hpp
fpo/ViewletModel.hpp
fpo/ViewletView.hpp
)
SET (gnc_HEADERS ${gnc_QOBJECT_HEADERS}
Account.hpp
@ -63,6 +69,7 @@ SET (gnc_RESOURCES
gnucash.qrc
gtk-icons.qrc
fallback-icons.qrc
stylesheets.qrc
)
IF (WITH_SQL)

View File

@ -101,6 +101,8 @@ public:
: base_class(gnc_default_print_info(use_symbol))
{}
/* If the boolean set to true, then prefix 3 letter ISO 4217
currency code to the amount. */
PrintAmountInfo(const Account& account, bool use_symbol);
PrintAmountInfo(const Split& split, bool use_symbol);

View File

@ -110,6 +110,15 @@ void RecentFileMenu::readSettings(QSettings *settings, const QString &groupName)
updateMenu();
}
QString RecentFileMenu::getRecentFileName(QSettings *settings,
const QString &groupName)
{
settings->beginReadArray(groupName);
settings->setArrayIndex(0);
QString qs = settings->value("filename").toString();
settings->endArray();
return qs;
}
void RecentFileMenu::writeSettings(QSettings *settings, const QString &groupName)
{

View File

@ -50,6 +50,8 @@ public:
*/
void readSettings(QSettings *settings, const QString &groupName);
QString getRecentFileName(QSettings *settings, const QString &groupName);
/**
* Write the internal list to a QSettings array.
* @param settings QSettings to write to

View File

@ -1,19 +1,335 @@
/*
* Copyright (C) 2011 Free Software Foundation, Inc
*
* 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
* Dashboard for embedding various dock widgets.
*
* Dock Widgets:
* 1) Transfer Funds
* 2) First Person Overview
*/
#include "dashboard.hpp"
#include "ui_dashboard.h"
#include "engine/gnc-event.h" // for GNC_EVENT_ITEM_ADDED
#include <QtGui>
#include <QAbstractItemModel>
#include <QDate>
namespace gnc
{
Dashboard::Dashboard(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Dashboard)
ui(new Ui::Dashboard),
m_eventWrapper(*this, &Dashboard::transactionEvent),
m_eventWrapperAccount(*this, &Dashboard::accountEvent)
{
QSettings settings;
restoreGeometry(settings.value("dashboardGeometry").toByteArray());
ui->setupUi(this);
setCentralWidget(ui->firstPersonOverview);
// Generate UI
setUiWidgets();
setBasicTxnEntryFormLayout();
setCentralWidget(ui->dockwFPO);
setFPO();
//this->tabifyDockWidget(ui->dockwBasicTxn, ui->dockwSplitTxn);
//ui->dockwBasicTxn->raise();
ui->dockwSplitTxn->hide();
ui->dockwLogViewer->hide();
this->tabifyDockWidget(ui->txnEntryBasic, ui->txnEntrySplit);
ui->txnEntryBasic->raise();
/* Set stylesheet, so that some styling to viewlets can be applied */
/*QFile styleSheetFile(":/qss-default");
styleSheetFile.open(QFile::ReadOnly);
QString styleSheetName = QLatin1String(styleSheetFile.readAll());
this->setStyleSheet(styleSheetName);*/
restoreState(settings.value("dashboardState").toByteArray());
bool isBasicTxnDockVisible = settings.value("basic-txn-dockwidget-visible").toBool();
ui->dockwBasicTxn->setVisible(isBasicTxnDockVisible);
/*
// Trying to restore pos and size of dockwidget manually
QSettings settings;
QPoint bTxnWdgPos = settings.value("basic-txn-entry-dockwidget-pos").toPoint();
ui->dockwBasicTxn->move(bTxnWdgPos);
QSize bTxnWdgSize = settings.value("basic-txn-entry-dockwidget-size").toSize();
ui->dockwBasicTxn->resize(bTxnWdgSize);
*/
connect(btnCreateBasicTxn, SIGNAL(clicked()),
this, SLOT(on_btnCreateBasicTxn_clicked()));
}
Dashboard::~Dashboard()
{
/*
QSettings settings;
settings.setValue("basic-txn-entry-dockwidget-pos", ui->dockwBasicTxn->pos());
settings.setValue("basic-txn-entry-dockwidget-size", ui->dockwBasicTxn->size());
*/
delete ui;
}
void
Dashboard::mainWindowCloseEvent()
{
QSettings settings;
settings.setValue("dashboardGeometry", saveGeometry());
settings.setValue("dashboardState", saveState());
settings.setValue("basic-txn-dockwidget-visible", ui->dockwBasicTxn->isVisible());
//qDebug()<<"while writing dockwdg visibility is "<<settings.value("basic-txn-dockwidget-visible").toBool();
}
void
Dashboard::showDashboardWidgets()
{
QSettings settings;
ui->dockwBasicTxn->setVisible(settings.value("basic-txn-dockwidget-visible").toBool());
ui->dockwFPO->show();
}
/** Initialise widgets to startup defaults */
void
Dashboard::setUiWidgets()
{
numer = 0.0;
lblDescription = new QLabel(tr("Description:"));
lblDate = new QLabel(tr("Date:"));
lblTransferFrom = new QLabel(tr("Transfer From:"));
lblTransferTo = new QLabel(tr("TransferTo:"));
lblAmount = new QLabel(tr("Amount:"));
lblMemo = new QLabel(tr("Memo:"));
lblNum = new QLabel(tr("Num:"));
comboTransferFrom = new QComboBox();
comboTransferFrom->addItem(tr("- NA -"));
comboTransferTo = new QComboBox();
comboTransferTo->addItem(tr("- NA -"));
lineDescription = new QLineEdit();
lineAmount = new QLineEdit();
lineAmount->setText(tr("0.00"));
lineAmount->setValidator(new QDoubleValidator(0.0, 1e100, 2, this));
lineMemo = new QLineEdit();
lineNum = new QLineEdit();
dateTxnDate = new QDateEdit();
dateVal = QDate::currentDate();
dateTxnDate->setDate(dateVal);
btnCreateBasicTxn = new QPushButton(tr("Create Transaction"));
}
/** Layout for data entry. Type: Form Based
*
* Set this as default to make this layout as default
* for all data entry widgets. */
void
Dashboard::setBasicTxnEntryFormLayout()
{
gridBasicTxnEntry = new QGridLayout(ui->dockcBasicTxn);
gridBasicTxnEntry->addWidget(lblDescription, 0, 0);
gridBasicTxnEntry->addWidget(lineDescription, 0, 1);
gridBasicTxnEntry->addWidget(lblDate, 1, 0);
gridBasicTxnEntry->addWidget(dateTxnDate, 1, 1);
gridBasicTxnEntry->addWidget(lblTransferFrom, 2, 0);
gridBasicTxnEntry->addWidget(comboTransferFrom, 2, 1);
gridBasicTxnEntry->addWidget(lblTransferTo, 3, 0);
gridBasicTxnEntry->addWidget(comboTransferTo, 3, 1);
gridBasicTxnEntry->addWidget(lblAmount, 4, 0);
gridBasicTxnEntry->addWidget(lineAmount, 4, 1);
gridBasicTxnEntry->addWidget(lblMemo, 5, 0);
gridBasicTxnEntry->addWidget(lineMemo, 5, 1);
gridBasicTxnEntry->addWidget(lblNum, 6, 0);
gridBasicTxnEntry->addWidget(lineNum, 6, 1);
gridBasicTxnEntry->addWidget(btnCreateBasicTxn, 7, 1);
}
void
Dashboard::setFPO()
{
QHBoxLayout *FPOLayout = new QHBoxLayout;
ui->dockcFPO->setLayout(FPOLayout);
fpoWidget = new FPO(ui->dockcFPO, FPOLayout);
}
void
Dashboard::clearFields()
{
lineDescription->clear();
lineAmount->clear();
lineMemo->clear();
lineNum->clear();
}
void
Dashboard::transactionEvent( ::Transaction* trans, QofEventId event_type)
{
//qDebug() << "Dashboard::transactionEvent, id=" << qofEventToString(event_type);
switch (event_type)
{
case QOF_EVENT_MODIFY:
fpoWidget->leftViewlet->leftVUpdate();
fpoWidget->rightViewlet->rightVUpdate();
fpoWidget->defaultViewlet->defaultVUpdate();
break;
case GNC_EVENT_ITEM_REMOVED:
case GNC_EVENT_ITEM_ADDED:
// This event is triggered by a split being added (or removed)
// to a transaction. Ignored because we already reacted upon
// the MODIFY event.
break;
case QOF_EVENT_CREATE:
// This event is triggered by a newly created transaction, but
// we reacted on this in the accountEvent handler already.
break;
default:
qDebug() << "Dashboard::transactionEvent, ignored event id=" << qofEventToString(event_type);
break;
}
}
void
Dashboard::accountEvent( ::Account* acc, QofEventId event_type)
{
//qDebug() << "Dashboard::accountEvent, id=" << qofEventToString(event_type);
switch (event_type)
{
case GNC_EVENT_ITEM_REMOVED:
fpoWidget->leftViewlet->leftVUpdate();
fpoWidget->rightViewlet->rightVUpdate();
fpoWidget->defaultViewlet->defaultVUpdate();
break;
case GNC_EVENT_ITEM_CHANGED:
case GNC_EVENT_ITEM_ADDED:
case QOF_EVENT_MODIFY:
// These events are also triggered e.g. by a newly added
// transaction/split in this account. However, we already
// reacted on this by the above events, so we can ignore them
// here.
break;
default:
qDebug() << "Dashboard::accountEvent, ignored event id=" << qofEventToString(event_type);
break;
}
}
void
Dashboard::loadAccountsTreeComboBox(AccountListModel * const m_accountsListModel)
{
accountsList = m_accountsListModel;
comboTransferFrom->setModel(accountsList);
comboTransferTo->setModel(accountsList);
}
/***** Slots *****/
/** "Create Transaction" button for Basic Transaction Entry dock widget */
void
Dashboard::on_btnCreateBasicTxn_clicked()
{
if (lineDescription->text().isEmpty())
{
QMessageBox::StandardButton warnEmptyDesc;
warnEmptyDesc = QMessageBox::warning(this, tr("Empty Description"), "You have not set a description. Are you sure you want to create a transaction with no description?", QMessageBox::Yes | QMessageBox::No);
if (warnEmptyDesc == QMessageBox::No)
return;
}
// Allocate memory and start editing a new transaction
int index = comboTransferFrom->currentIndex();
account = accountsList->at(index);
book = gnc_account_get_book(account);
transaction = ::xaccMallocTransaction(book);
::xaccTransBeginEdit(transaction);
// Populate transaction details
dateVal = dateTxnDate->date();
::xaccTransSetDate(transaction, dateVal.day(), dateVal.month(),
dateVal.year());
::xaccTransSetNum(transaction, lineNum->text().toUtf8());
::xaccTransSetDescription(transaction, lineDescription->text().toUtf8());
currency = xaccAccountGetCommodity(account);
::xaccTransSetCurrency(transaction, currency);
denom = ::gnc_commodity_get_fraction(currency);
// Populate split 1
// Check whether the account for this split is a placeholder
qDebug() << ::xaccAccountGetPlaceholder(account);
// ^^ does not work as expected, returns false for placeholder accounts too. Why?
split = xaccMallocSplit(book);
::xaccTransAppendSplit(transaction, split);
::xaccAccountInsertSplit(account, split);
numer = lineAmount->text().toDouble();
amount = ::double_to_gnc_numeric(numer, denom,
GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_NEVER);
::xaccSplitSetValue(split, amount);
::xaccSplitSetAmount(split, amount);
// Populate split 2
split2 = ::xaccMallocSplit(book);
::xaccTransAppendSplit(transaction, split2);
int index2 = comboTransferTo->currentIndex();
account2 = accountsList->at(index2);
::xaccAccountInsertSplit(account2, split2);
amount2 = ::gnc_numeric_neg(amount);
::xaccSplitSetValue(split2, amount2);
::xaccSplitSetAmount(split2, amount2);
// Finally commit the transaction to storage backend.
::xaccTransCommitEdit(transaction);
statusBar()->showMessage(tr("Transaction has been created"), 2000);
clearFields();
}
void
Dashboard::on_dockwBasicTxn_visibilityChanged(bool visible)
{
((MainWindow *)parentWidget()->parentWidget()->parentWidget()->parentWidget())->dockWidgetsVisibilityChanged(0, visible);
}
void
Dashboard::transferFundsWidgetButtonToggled(bool checked)
{
if(checked)
{
ui->dockwBasicTxn->show();
}
else
{
ui->dockwBasicTxn->hide();
}
}
} // END namespace gnc

View File

@ -1,12 +1,53 @@
/*
* Copyright (C) 2011 Free Software Foundation, Inc
*
* 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
* Dashboard for embedding various dock widgets.
*/
#ifndef DASHBOARD_HPP
#define DASHBOARD_HPP
#include "config.h"
extern "C"
{
#include "qof.h"
#include "engine/Account.h"
#include "engine/Transaction.h"
}
#include "AccountItemModel.hpp"
#include "fpo/FPO.hpp"
#include "gnc/QofEventWrapper.hpp"
#include <QMainWindow>
#include <QAbstractItemModel>
#include <QtGui>
namespace Ui {
class Dashboard;
}
namespace gnc
{
class FPO;
class Dashboard : public QMainWindow
{
Q_OBJECT
@ -15,8 +56,68 @@ public:
explicit Dashboard(QWidget *parent = 0);
~Dashboard();
FPO *fpoWidget;
AccountListModel *accountsList;
void loadAccountsTreeComboBox(AccountListModel * const m_accountListModel);
void showDashboardWidgets();
void mainWindowCloseEvent();
public slots:
void transferFundsWidgetButtonToggled(bool checked);
void transactionEvent( ::Transaction* trans, QofEventId event_type);
void accountEvent( ::Account* acc, QofEventId event_type);
private:
Ui::Dashboard *ui;
/* UI widgets */
QGridLayout *gridBasicTxnEntry;
QHBoxLayout *hbox;
QVBoxLayout *vbox;
QLabel *lblDescription;
QLabel *lblDate;
QLabel *lblTransferFrom;
QLabel *lblTransferTo;
QLabel *lblAmount;
QLabel *lblMemo;
QLabel *lblNum;
QComboBox *comboTransferFrom;
QComboBox *comboTransferTo;
QLineEdit *lineDescription;
QLineEdit *lineAmount;
QLineEdit *lineMemo;
QLineEdit *lineNum;
QDateEdit *dateTxnDate;
QDate dateVal;
QPushButton *btnCreateBasicTxn;
/* Transaction related data types */
::QofBook *book;
::Transaction *transaction;
::gnc_commodity *currency;
int denom;
::Account *account;
::Split *split;
double numer;
::gnc_numeric amount;
::Account *account2;
::Split *split2;
::gnc_numeric amount2;
void setUiWidgets();
void setBasicTxnEntryFormLayout();
void setFPO();
void clearFields();
QofEventWrapper<Dashboard, ::Transaction*> m_eventWrapper;
QofEventWrapper<Dashboard, ::Account*> m_eventWrapperAccount;
private slots:
void on_btnCreateBasicTxn_clicked();
void on_dockwBasicTxn_visibilityChanged(bool visible);
};
} // END namespace gnc
#endif // DASHBOARD_HPP

View File

@ -7,12 +7,15 @@
<x>0</x>
<y>0</y>
<width>1049</width>
<height>600</height>
<height>617</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="dockOptions">
<set>QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::ForceTabbedDocks</set>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
@ -25,23 +28,23 @@
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="txnEntryBasic">
<widget class="QDockWidget" name="dockwBasicTxn">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>425</width>
<height>260</height>
<width>300</width>
<height>265</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>425</width>
<height>260</height>
<width>500</width>
<height>275</height>
</size>
</property>
<property name="baseSize">
@ -53,191 +56,55 @@
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="accessibleName">
<string/>
</property>
<property name="features">
<set>QDockWidget::AllDockWidgetFeatures</set>
</property>
<property name="allowedAreas">
<set>Qt::AllDockWidgetAreas</set>
</property>
<property name="windowTitle">
<string>Basic</string>
</property>
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>80</x>
<y>0</y>
<width>331</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>101</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Description</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>55</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>Date</string>
</property>
</widget>
<widget class="QDateEdit" name="dateEdit">
<property name="geometry">
<rect>
<x>80</x>
<y>30</y>
<width>110</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>250</x>
<y>200</y>
<width>151</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Create Transaction</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_5">
<property name="geometry">
<rect>
<x>80</x>
<y>170</y>
<width>331</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>210</x>
<y>60</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Transfer To</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_4">
<property name="geometry">
<rect>
<x>80</x>
<y>140</y>
<width>331</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_8">
<property name="geometry">
<rect>
<x>10</x>
<y>170</y>
<width>55</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>Num</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>10</x>
<y>60</y>
<width>101</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Transfer From</string>
</property>
</widget>
<widget class="QComboBox" name="comboBox_2">
<property name="geometry">
<rect>
<x>210</x>
<y>80</y>
<width>201</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_2">
<property name="geometry">
<rect>
<x>80</x>
<y>110</y>
<width>331</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<width>55</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>Memo</string>
</property>
</widget>
<widget class="QComboBox" name="comboBox">
<property name="geometry">
<rect>
<x>10</x>
<y>80</y>
<width>191</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<width>55</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>Amount</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="dockcBasicTxn"/>
</widget>
<widget class="QDockWidget" name="txnEntrySplit">
<widget class="QDockWidget" name="dockwSplitTxn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>265</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>500</width>
<height>275</height>
</size>
</property>
<property name="features">
<set>QDockWidget::AllDockWidgetFeatures</set>
</property>
<property name="allowedAreas">
<set>Qt::AllDockWidgetAreas</set>
</property>
<property name="windowTitle">
<string>Split</string>
</property>
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<widget class="QWidget" name="dockcSplitTxn">
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
@ -417,26 +284,44 @@
</widget>
</widget>
</widget>
<widget class="QDockWidget" name="firstPersonOverview">
<property name="enabled">
<bool>true</bool>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_3"/>
</widget>
<widget class="QDockWidget" name="logViewer">
<widget class="QDockWidget" name="dockwLogViewer">
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="windowTitle">
<string>Event Logger</string>
</property>
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_5"/>
<widget class="QWidget" name="dockcLogViewer"/>
</widget>
<widget class="QDockWidget" name="dockwFPO">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="features">
<set>QDockWidget::NoDockWidgetFeatures</set>
</property>
<property name="allowedAreas">
<set>Qt::BottomDockWidgetArea|Qt::TopDockWidgetArea</set>
</property>
<property name="windowTitle">
<string/>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="dockcFPO"/>
</widget>
</widget>
<resources/>

26
src/gnc/fpo/FPO.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "FPO.hpp"
#include "gnc/dashboard.hpp"
#include "gnc/mainwindow.hpp"
#include <QLabel>
namespace gnc
{
FPO::FPO(QWidget *parent, QHBoxLayout *FPOLayout) :
QWidget(parent)
{
/* Left viewlet */
leftViewlet = new ViewletView(parent, FPOLayout);
leftViewlet->leftVSet(parent, FPOLayout);
/* Right viewlet */
rightViewlet = new ViewletView(parent, FPOLayout);
rightViewlet->rightVSet(parent, FPOLayout);
/* Default viewlet */
defaultViewlet = new ViewletView(parent, FPOLayout);
defaultViewlet->defaultVSet(parent, FPOLayout);
}
} // END namespace gnc

35
src/gnc/fpo/FPO.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef FPO_HPP
#define FPO_HPP
#include "ViewletView.hpp"
#include "gnc/Session.hpp"
#include <QWidget>
#include <QGridLayout>
namespace gnc
{
class ViewletView;
class FPO : public QWidget
{
Q_OBJECT
public:
explicit FPO(QWidget *parent = 0, QHBoxLayout *FPOLayout = NULL);
ViewletView *leftViewlet;
ViewletView *rightViewlet;
ViewletView *defaultViewlet;
Session m_session;
signals:
void sessionLoaded();
public slots:
};
} // END namespace gnc
#endif // FPO_HPP

View File

@ -0,0 +1,213 @@
#include "ViewletModel.hpp"
#include "gnc/Transaction.hpp"
#include "gnc/Account.hpp"
#include "gnc/Numeric.hpp"
namespace gnc
{
ViewletModel::ViewletModel()
{
}
void
ViewletModel::defaultVGenerate(::Account *selectedAccount)
{
SplitQList splitList = buildSplitListDateSort(selectedAccount);
buildMiniJournalStruct(splitList);
}
void
ViewletModel::leftVGenerate(::Account *selectedAccount)
{
::QofBook *book = gnc_account_get_book(selectedAccount);
::Account *rootAccount = gnc_book_get_root_account(book);
GList *accountsGList = gnc_account_get_descendants(rootAccount);
AccountQList accountsList = Account::fromGList(accountsGList);
int numOfAccounts = accountsList.count();
qDebug()<<"Total num of accounts: "<<numOfAccounts;
AccountQList expenseAccountsList;
for(int i = 0; i < numOfAccounts; i++)
{
if(xaccAccountGetType(accountsList.at(i)) == 9)
{
expenseAccountsList.append(accountsList.at(i));
}
}
SplitQList splitsList = buildSplitListDateSort(expenseAccountsList);
buildMiniJournalStruct(splitsList);
}
void
ViewletModel::rightVGenerate(::Account *selectedAccount)
{
::QofBook *book = gnc_account_get_book(selectedAccount);
::Account *rootAccount = gnc_book_get_root_account(book);
GList *accountsGList = gnc_account_get_descendants(rootAccount);
AccountQList accountsList = Account::fromGList(accountsGList);
int numOfAccounts = accountsList.count();
qDebug()<<"Total num of accounts: "<<numOfAccounts;
AccountQList expenseAccountsList;
for(int i = 0; i < numOfAccounts; i++)
{
if(xaccAccountGetType(accountsList.at(i)) == 8)
{
expenseAccountsList.append(accountsList.at(i));
}
}
SplitQList splitsList = buildSplitListDateSort(expenseAccountsList);
buildMiniJournalStruct(splitsList);
}
#if 0
/* get all transactions earlier than the specified date */
QofQuery *qr = qof_query_create_for (GNC_ID_SPLIT);
qof_query_set_book(qr, ::gnc_account_get_book(selectedAccount));
// To look for dates, you need to create a "PredData" object
Timespec calve_date;
//calve_date = gdate_to_timespec(trans.getGDatePosted());
QofQueryPredData *pred_data = qof_query_date_predicate (QOF_COMPARE_LTE,
QOF_DATE_MATCH_NORMAL,
calve_date);
// and additionally a "query parameter" object
GSList *param_list = qof_query_build_param_list (TRANS_DATE_POSTED, NULL);
// The "PredData" and the "query parameter" object are added to this query
qof_query_add_term (qr, param_list, pred_data,
QOF_QUERY_FIRST_TERM);
// Query is run; result is returned
GList *result = qof_query_run (qr);
SplitQList querySplitList = Split::fromGList(result);
Split qSplit;
int numOfQuerSplits = querySplitList.count();
for(i=0; i < numOfQuerSplits; ++i)
{
qSplit = querySplitList.at(i);
//qDebug()<<qSplit.getCorrAccountName();
qDebug()<<qSplit.getParent().getDatePosted().toString();
}
// "result" is now a GList of "Transaction*" because at
//qof_query_create_for, we've asked for transactions.
// When finished, delete the QofQuery object but this will
// also delete the "result" list.
qof_query_destroy (qr);
#endif
SplitQList
ViewletModel::buildSplitListDateSort(::Account *selectedAccount)
{
::SplitList * splitL = ::xaccAccountGetSplitList(selectedAccount);
return Split::fromGList(splitL);
}
SplitQList
ViewletModel::buildSplitListDateSort(AccountQList accountsList)
{
int numOfAccounts = accountsList.count();
qDebug() <<"Num of accounts of X TYPE: "<<numOfAccounts;
SplitQList allSplitsList;
for(int i=0; i< numOfAccounts; i++)
{
::Account *C_acct = static_cast< ::Account *>(accountsList.at(i));
SplitQList tempList = Split::fromGList(::xaccAccountGetSplitList(C_acct));
int numOfSplits = tempList.count();
for(int i=0; i<numOfSplits; i++)
{
allSplitsList.append(tempList.at(i));
}
}
qSort(allSplitsList.begin(), allSplitsList.end(), &ViewletModel::lessThanByDate);
return allSplitsList;
}
bool
ViewletModel::lessThanByDate(::Split* a, ::Split* b)
{
::Transaction* tx_a = xaccSplitGetParent(a);
::Transaction* tx_b = xaccSplitGetParent(b);
return xaccTransGetDate(tx_a) < xaccTransGetDate(tx_b);
}
void
ViewletModel::buildMiniJournalStruct(SplitQList splitList)
{
int numOfSplits = splitList.count();
Split split;
int i;
QDate tempDate;
QString tempAccount;
for (i = 0; i < numOfSplits; i++)
{
split = splitList.at(i);
Transaction txn = split.getParent();
structViewletEntries entry;
if(i == 0)
{
tempDate = txn.getDatePosted();
entry.isDateEqual = false;
tempAccount = split.getCorrAccountName();
entry.isSplitAccountEqual = false;
}
else
{
if(txn.getDatePosted() == tempDate)
{
entry.isDateEqual = true;
tempDate = txn.getDatePosted();
}
else
{
entry.isDateEqual = false;
tempDate = txn.getDatePosted();
}
if(split.getCorrAccountName() == tempAccount)
{
entry.isSplitAccountEqual = true;
}
else
{
entry.isSplitAccountEqual = false;
tempAccount = split.getCorrAccountName();
}
}
entry.txnDate = txn.getDatePosted().toString();
entry.splitAccount = split.getCorrAccountName();
entry.txnDescription = txn.getDescription();
Numeric splitAmount;
splitAmount = split.getAmount();
PrintAmountInfo printInfo(split, true);
entry.splitAmount = splitAmount.printAmount(printInfo);
//qDebug()<<entry.isDateEqual;
//qDebug()<<entry.isSplitAccountEqual;
queueEntries.enqueue(entry);
}
}
} // END namespace gnc

View File

@ -0,0 +1,53 @@
#ifndef VIEWLETMODEL_HPP
#define VIEWLETMODEL_HPP
#include <QtCore>
#include <QtGui>
#include "config.h"
extern "C"
{
#include "qof.h"
#include "engine/Account.h"
#include "engine/Transaction.h"
#include "engine/Split.h"
}
#include "gnc/Split.hpp"
#include "gnc/SplitListModel.hpp"
namespace gnc
{
class ViewletModel
{
public:
ViewletModel();
void defaultVGenerate(::Account * selectedAccount);
void leftVGenerate(::Account * selectedAccount);
void rightVGenerate(::Account *selectedAccount);
struct structViewletEntries
{
QString txnDate;
bool isDateEqual;
QString splitAccount;
bool isSplitAccountEqual;
QString txnDescription;
QString splitAmount;
};
structViewletEntries tempEntry;
QQueue<structViewletEntries> queueEntries;
private:
SplitQList buildSplitListDateSort(::Account *selectedAccount);
SplitQList buildSplitListDateSort(AccountQList accountsList);
bool static lessThanByDate(::Split* a, ::Split* b);
void buildMiniJournalStruct(SplitQList splitList);
};
} // END namespace gnc
#endif // VIEWLETMODEL_HPP

351
src/gnc/fpo/ViewletView.cpp Normal file
View File

@ -0,0 +1,351 @@
#include "ViewletView.hpp"
namespace gnc
{
ViewletView::ViewletView(QWidget * parent, QHBoxLayout * FPOlayout) :
QWidget(parent)
{
viewletModel = new ViewletModel();
}
/***** Public *****/
void
ViewletView::defaultVSet(QWidget *parent, QHBoxLayout *FPOLayout)
{
/* For default viewlet */
comboAccountsList = new QComboBox();
comboAccountsList->addItem(tr("-NA-"));
connect(comboAccountsList, SIGNAL(currentIndexChanged(int)),
this, SLOT(defaultVUpdate()));
/* Add a new QWidget (acts as a container for this viewlet) to the
layout of QWidget (QDockWidget>QWidget, i.e, dockwFPO>dockcFPO)
in dashboard QMainWindow.
*/
QWidget *viewletContainer = new QWidget;
FPOLayout->addWidget(viewletContainer);
/* Set a layout for the container QWidget */
QVBoxLayout *vLay = new QVBoxLayout;
viewletContainer->setLayout(vLay);
/***** Start of viewlet specific implementations *****/
/* Specification:
This default viewlet contains two widgets, 1) An account
selection widget, and 2) A scroll area which wraps a QWidget
to show the entries.*/
/** @bugid_1 1) Account selection feature of the viewlet */
/*
comboAccountsList = new QComboBox();
comboAccountsList->addItem(tr("-NA-"));
*/
vLay->addWidget(comboAccountsList);
/* 2) The actual viewlet display of account selected in 1) */
QWidget *defaultViewletWidget = new QWidget();
defaultVLayout = new QVBoxLayout();
QScrollArea *viewletScrollArea = new QScrollArea();
viewletScrollArea->setWidget(defaultViewletWidget);
viewletScrollArea->setAlignment(Qt::AlignLeft);
viewletScrollArea->setWidgetResizable(true);
defaultViewletWidget->setLayout(defaultVLayout);
vLay->addWidget(viewletScrollArea);
//create viewlet
if(comboAccountsList->currentIndex())
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
viewletModel->defaultVGenerate(selectedAccount);
defaultVDraw();
}
}
void
ViewletView::leftVSet(QWidget *parent, QHBoxLayout *FPOLayout)
{
connect(this, SIGNAL(fileLoaded()),
this, SLOT(leftVLoad()));
//connect(comboAccountsList, SIGNAL(currentIndexChanged(int)),
// this, SLOT(leftVUpdate()));
//not required. remove after cleaning loadAccountsTreeComboBox()
comboAccountsList = new QComboBox();
comboAccountsList->addItem(tr("-NA-"));
QWidget *viewletContainer = new QWidget;
FPOLayout->addWidget(viewletContainer);
QVBoxLayout *vLay = new QVBoxLayout;
viewletContainer->setLayout(vLay);
QLabel *title = new QLabel(tr("Expense"));
vLay->addWidget(title);
/* The actual viewlet display of account(s) chosen*/
QWidget *defaultViewletWidget = new QWidget();
defaultVLayout = new QVBoxLayout();
QScrollArea *viewletScrollArea = new QScrollArea();
viewletScrollArea->setWidget(defaultViewletWidget);
viewletScrollArea->setAlignment(Qt::AlignLeft);
viewletScrollArea->setWidgetResizable(true);
defaultViewletWidget->setLayout(defaultVLayout);
vLay->addWidget(viewletScrollArea);
/*//create viewlet
if(comboAccountsList->currentIndex())
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
defaultVDraw();
}*/
}
void
ViewletView::rightVSet(QWidget *parent, QHBoxLayout *FPOLayout)
{
connect(this, SIGNAL(fileLoaded()),
this, SLOT(rightVLoad()));
//connect(comboAccountsList, SIGNAL(currentIndexChanged(int)),
// this, SLOT(leftVUpdate()));
//not required. remove after cleaning loadAccountsTreeComboBox()
comboAccountsList = new QComboBox();
comboAccountsList->addItem(tr("-NA-"));
QWidget *viewletContainer = new QWidget;
FPOLayout->addWidget(viewletContainer);
QVBoxLayout *vLay = new QVBoxLayout;
viewletContainer->setLayout(vLay);
QLabel *title = new QLabel(tr("Income"));
vLay->addWidget(title);
/* The actual viewlet display of account(s) chosen*/
QWidget *defaultViewletWidget = new QWidget();
defaultVLayout = new QVBoxLayout();
QScrollArea *viewletScrollArea = new QScrollArea();
viewletScrollArea->setWidget(defaultViewletWidget);
viewletScrollArea->setAlignment(Qt::AlignLeft);
viewletScrollArea->setWidgetResizable(true);
defaultViewletWidget->setLayout(defaultVLayout);
vLay->addWidget(viewletScrollArea);
/*//create viewlet
if(comboAccountsList->currentIndex())
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
defaultVDraw();
}*/
}
/***** Private *****/
/** Create the widgets for the viewlet entries
Passes the selected account to the model. The updated textual
data in the struct of the model is used in the newly created
widgets.
*/
void
ViewletView::defaultVDraw()
{
/* Update the struct in ViewletModel with data from the selected
account
*/
int numOfTransactions = viewletModel->queueEntries.count();
for (int i = 0; i < numOfTransactions; i++)
{
viewletModel->tempEntry = viewletModel->queueEntries.at(i);
//1 & 2
if((!viewletModel->tempEntry.isDateEqual && !viewletModel->tempEntry.isSplitAccountEqual)
|| (!viewletModel->tempEntry.isDateEqual && viewletModel->tempEntry.isSplitAccountEqual))
{
dateCheckOutput();
accountCheckOutput();
descriptionAmountOutput();
}
//3
if(viewletModel->tempEntry.isDateEqual && !viewletModel->tempEntry.isSplitAccountEqual)
{
accountCheckOutput();
descriptionAmountOutput();
}
//4
if(viewletModel->tempEntry.isDateEqual && viewletModel->tempEntry.isSplitAccountEqual)
{
descriptionAmountOutput();
}
}
}
void
ViewletView::dateCheckOutput()
{
QWidget *dateLevelContainer = new QWidget();
QVBoxLayout *dateLayout = new QVBoxLayout;
dateLevelContainer->setLayout(dateLayout);
/* Append the pointer of this top level widget
of the viewlet for later removal during update */
viewletWidgetContainersList.append(dateLevelContainer);
defaultVLayout->addWidget(dateLevelContainer, 10, Qt::AlignTop);
txnDate = viewletModel->tempEntry.txnDate;
setLabel(txnDate, "dateWidget", dateLayout);
QWidget *accountLevelContainer = new QWidget();
accountLayout = new QVBoxLayout;
accountLevelContainer->setLayout(accountLayout);
dateLayout->addWidget(accountLevelContainer);
}
void
ViewletView::accountCheckOutput()
{
QWidget *singleAccountLevelContainer = new QWidget();
QVBoxLayout *singleAccountLayout = new QVBoxLayout();
singleAccountLevelContainer->setLayout(singleAccountLayout);
accountLayout->addWidget(singleAccountLevelContainer);
// 1
splitAccount = viewletModel->tempEntry.splitAccount;
setLabel(splitAccount, "accountWidget", singleAccountLayout);
QWidget *descriptionAmountLevelContainer = new QWidget();
descriptionAmountLayout = new QVBoxLayout();
descriptionAmountLevelContainer->setLayout(descriptionAmountLayout);
// 2
singleAccountLayout->addWidget(descriptionAmountLevelContainer);
}
void
ViewletView::descriptionAmountOutput()
{
txnDescription = viewletModel->tempEntry.txnDescription;
setLabel(txnDescription, "descWidget", descriptionAmountLayout);
splitAmount = viewletModel->tempEntry.splitAmount;
setLabel(splitAmount, "amountWidget", descriptionAmountLayout);
}
void
ViewletView::defaultVRemoveWidgets()
{
/* Remove old widgets. */
int numOfContainers = viewletWidgetContainersList.count();
for (int i=0; i<numOfContainers; i++)
{
delete viewletWidgetContainersList.at(i);
}
/* Empty the data structures */
viewletModel->queueEntries.clear();
viewletWidgetContainersList.clear();
}
/**********/
void
ViewletView::setLabel(QString data, QString objectName, QVBoxLayout *layout)
{
QLabel *lbl = new QLabel();
lbl->setText(data);
layout->addWidget(lbl);
/* Used as CSS ID by QStyleSheet */
lbl->setObjectName(objectName);
viewletWidgetsList.append(lbl);
}
void
ViewletView::loadAccountsTreeComboBox(AccountListModel * const m_accountsListModel)
{
accountsList = m_accountsListModel;
comboAccountsList->setModel(accountsList);
emit fileLoaded();
}
/***** Slots *****/
void
ViewletView::defaultVUpdate()
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
defaultVRemoveWidgets();
viewletModel->defaultVGenerate(selectedAccount);
defaultVDraw();
}
void
ViewletView::leftVUpdate()
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
//Call this in dboard gnc event switch
defaultVRemoveWidgets();
viewletModel->leftVGenerate(selectedAccount);
defaultVDraw();
}
void
ViewletView::leftVLoad()
{
selectedAccount = accountsList->at(1);
defaultVRemoveWidgets();
viewletModel->leftVGenerate(selectedAccount);
defaultVDraw();
}
void
ViewletView::rightVUpdate()
{
selectedAccountIndex = comboAccountsList->currentIndex();
selectedAccount = accountsList->at(selectedAccountIndex);
//Call this in dboard gnc event switch
defaultVRemoveWidgets();
viewletModel->rightVGenerate(selectedAccount);
defaultVDraw();
}
void
ViewletView::rightVLoad()
{
selectedAccount = accountsList->at(1);
defaultVRemoveWidgets();
viewletModel->rightVGenerate(selectedAccount);
defaultVDraw();
}
} // END namespace gnc

101
src/gnc/fpo/ViewletView.hpp Normal file
View File

@ -0,0 +1,101 @@
#ifndef VIEWLETVIEW_HPP
#define VIEWLETVIEW_HPP
#include "config.h"
extern "C"
{
#include "qof.h"
#include "engine/Account.h"
#include "engine/Transaction.h"
#include "engine/Split.h"
}
#include "gnc/mainwindow.hpp"
#include "gnc/fpo/ViewletModel.hpp"
#include "gnc/AccountItemModel.hpp"
#include "gnc/SplitListModel.hpp"
#include <QtCore>
#include <QAbstractItemModel>
#include <QtGui>
#include <QWidget>
namespace gnc
{
class ViewletModel;
class ViewletView : public QWidget
{
Q_OBJECT
public:
explicit ViewletView(QWidget * parent = 0, QHBoxLayout * FPOLayout = NULL);
void loadAccountsTreeComboBox(AccountListModel * const m_accountsListModel);
/* Call the appropriate method to set the viewlet of that type */
void defaultVSet(QWidget * parent, QHBoxLayout * FPOLayout);
void leftVSet(QWidget * parent, QHBoxLayout * FPOLayout);
void rightVSet(QWidget * parent, QHBoxLayout * FPOLayout);
void leftVUpdate();
void rightVUpdate();
signals:
void fileLoaded();
public slots:
void defaultVUpdate();
private:
ViewletModel *viewletModel;
AccountListModel *accountsList;
QString txnDate;
QString txnDescription;
QString splitAccount;
QString splitAmount;
QVBoxLayout *defaultVLayout;
QVBoxLayout *leftVLayout;
QVBoxLayout *rightVLayout;
QVBoxLayout *accountLayout;
QVBoxLayout *descriptionAmountLayout;
/* A simple list to store widgets generated by any of the three
viewlet types. When the viewlet updates, a new viewlet could
be drawn by first removing the old widgets in this list. */
QList<QWidget *> viewletWidgetsList;
QList<QWidget *> viewletWidgetContainersList;
/** @bugid_1 */
QComboBox * comboAccountsList;
/** @todo */
::SplitList * pSplitList;
::Account * selectedAccount;
int selectedAccountIndex;
/* Widget generator */
void setLabel(QString data, QString objectName, QVBoxLayout *layout);
/* Viewlet generator methods */
void defaultVDraw();
void defaultVRemoveWidgets();
//void leftVDraw();
void leftVRemoveWidgets();
//void rightVDraw();
void rightVRemoveWidgets();
void dateCheckOutput();
void accountCheckOutput();
void descriptionAmountOutput();
private slots:
void leftVLoad();
void rightVLoad();
};
} // END namespace gnc
#endif // VIEWLETVIEW_HPP

View File

@ -187,6 +187,12 @@ main(int argc, char ** argv)
gnc::MainWindow mainWin;
mainWin.show();
/* set stylesheet */
QFile styleSheetFile(":/qss-default");
styleSheetFile.open(QFile::ReadOnly);
QString styleSheetName = QLatin1String(styleSheetFile.readAll());
app.setStyleSheet(styleSheetName);
// Go into the main qt event loop
r = app.exec();

View File

@ -53,6 +53,9 @@ extern "C"
#include "gnc/SplitListModel.hpp"
#include "gnc/RecentFileMenu.hpp"
/* Temp solution for accounts list */
#include "gnc/fpo/ViewletView.hpp"
#include "gnc/Cmd.hpp"
namespace gnc
@ -537,9 +540,14 @@ void MainWindow::loadFile(const QString &fileName)
m_accountTreeModel = new AccountTreeModel(root, this);
ui->treeView->setModel(m_accountTreeModel);
/* Load the tree in combo boxes of dashboard */
dboard->loadAccountsTreeComboBox(m_accountListModel);
dboard->fpoWidget->defaultViewlet->loadAccountsTreeComboBox(m_accountListModel);
dboard->fpoWidget->leftViewlet->loadAccountsTreeComboBox(m_accountListModel);
dboard->fpoWidget->rightViewlet->loadAccountsTreeComboBox(m_accountListModel);
ui->treeViewTab->setProperty(PROPERTY_TAB_PREVIOUSPOS, ui->tabWidget->currentIndex());
ui->tabWidget->setCurrentWidget(ui->treeViewTab);
ui->tabWidget->setCurrentWidget(dboard);
}
else
{

View File

@ -32,7 +32,6 @@
#include "config.h"
#include "mainwindow.hpp"
#include "ui_mainwindow.h"
#include "dashboard.hpp"
// gnucash includes
#include <glib/gi18n.h>
@ -88,8 +87,10 @@ MainWindow::MainWindow()
createStatusBar();
setIcons();
Dashboard *dboard = new Dashboard(this);
ui->tabWidget->addTab(dboard, tr("Dashboard"));
dboard = new Dashboard(this);
dboard->setWindowTitle("Dashboard");
//dboard->show();
ui->tabWidget->addTab(dboard, "Dashboard");
/* Properties used by QSettings */
QCoreApplication::setOrganizationName("Gnucash");
@ -100,15 +101,23 @@ MainWindow::MainWindow()
connect(m_undoStack, SIGNAL(cleanChanged(bool)),
this, SLOT(documentCleanStateChanged(bool)));
connect(m_btnTransferFundsWidget, SIGNAL(toggled(bool)),
dboard, SLOT(transferFundsWidgetButtonToggled(bool)));
connect(this, SIGNAL(dashboardVisible(bool)),
dboard, SLOT(transferFundsWidgetButtonToggled(bool)));
setWindowIcon(QIcon(":/pixmaps/gnucash-icon-64x64.png"));
/* Check if the system supports freedesktop standards for icons,
* if not, then use the bundled icon set. */
if (!QIcon::hasThemeIcon("document-open")) {
QIcon::setThemeName("oxygen");
}
newFile();
setUnifiedTitleAndToolBarOnMac(true);
autoLoadRecentFile();
}
MainWindow::~MainWindow()
@ -253,6 +262,14 @@ void MainWindow::createToolBars()
m_editToolBar->addAction(ui->actionCut);
m_editToolBar->addAction(ui->actionCopy);
m_editToolBar->addAction(ui->actionPaste);
m_dashboardToolBar = addToolBar(tr("Dashboard"));
m_dashboardToolBar->setObjectName("m_dashboardToolBar");
m_btnTransferFundsWidget = new QToolButton;
m_btnTransferFundsWidget->setCheckable(true);
QSettings settings;
m_btnTransferFundsWidget->setChecked(settings.value("basic-txn-dockwidget-visible").toBool());
m_dashboardToolBar->addWidget(m_btnTransferFundsWidget);
}
void MainWindow::createStatusBar()
@ -275,6 +292,7 @@ void MainWindow::setIcons()
ui->actionSave_as->setIcon(QIcon::fromTheme("document-save-as"));
ui->actionExit->setIcon(QIcon::fromTheme("window-close"));
ui->actionAbout->setIcon(QIcon::fromTheme("help-about"));
m_btnTransferFundsWidget->setIcon(QIcon::fromTheme("help-about"));
}
void MainWindow::readSettings()
@ -282,16 +300,32 @@ void MainWindow::readSettings()
QSettings settings;
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
QSize size = settings.value("size", QSize(400, 400)).toSize();
resize(size);
move(pos);
//resize(size);
//move(pos);
restoreState(settings.value("state").toByteArray());
restoreGeometry(settings.value("geometry").toByteArray());
m_menuRecentFiles->readSettings(&settings, "RecentFiles");
}
void MainWindow::autoLoadRecentFile()
{
QSettings settings;
QString lastOpenedFile = "";
lastOpenedFile = m_menuRecentFiles->getRecentFileName(&settings,
"RecentFiles");
if(maybeSave())
{
loadFile(lastOpenedFile);
}
}
void MainWindow::writeSettings()
{
QSettings settings;
settings.setValue("pos", pos());
settings.setValue("size", size());
//settings.setValue("pos", pos());
//settings.setValue("size", size());
settings.setValue("state", saveState());
settings.setValue("geometry", saveGeometry());
m_menuRecentFiles->writeSettings(&settings, "RecentFiles");
}
@ -365,6 +399,13 @@ void MainWindow::on_tabWidget_tabCloseRequested(int index)
ui->actionViewAccountList->setChecked(false);
reallyRemoveTab(index);
}
else if (widget == dboard)
{
ui->actionViewDashboard->setChecked(false);
m_dashboardToolBar->setEnabled(false);
m_dashboardToolBar->setHidden(true);
reallyRemoveTab(index);
}
else
{
QVariant prevPos = widget->property(PROPERTY_TAB_PREVIOUSPOS);
@ -393,6 +434,11 @@ void MainWindow::on_actionViewWelcomepage_triggered(bool checked)
viewOrHideTab(checked, ui->textBrowserTab);
}
void MainWindow::on_actionViewDashboard_triggered(bool checked)
{
viewOrHideTab(checked, dboard);
}
void MainWindow::viewOrHideTab(bool checked, QWidget *widget)
{
if (checked)
@ -411,6 +457,13 @@ void MainWindow::viewOrHideTab(bool checked, QWidget *widget)
ui->tabWidget->insertTab(tabPosition.toInt(), widget, tabLabel.toString());
if (tabIsCurrent)
ui->tabWidget->setCurrentWidget(widget);
if(widget == dboard)
{
m_dashboardToolBar->setEnabled(true);
m_dashboardToolBar->setHidden(false);
emit dashboardVisible(true);
}
}
else
{
@ -436,6 +489,18 @@ void MainWindow::on_tabWidget_currentChanged(int index)
QWidget *widget = ui->tabWidget->widget(index);
bool tabWithAccounts = (widget != ui->textBrowserTab);
ui->menuAccount->setEnabled(tabWithAccounts);
if(ui->tabWidget->currentWidget() == dboard)
{
m_dashboardToolBar->setEnabled(true);
m_dashboardToolBar->setHidden(false);
dboard->showDashboardWidgets();
}
else
{
m_dashboardToolBar->setEnabled(false);
m_dashboardToolBar->setHidden(true);
}
}
void MainWindow::accountItemActivated(const QModelIndex & index)
@ -503,6 +568,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
{
if (maybeSave())
{
dboard->mainWindowCloseEvent();
writeSettings();
event->accept();
@ -555,4 +621,14 @@ void MainWindow::newFile()
}
}
void MainWindow::dockWidgetsVisibilityChanged(int wdg, bool visible)
{
if(wdg == 0)
{
/** todo: handle tabs */
m_btnTransferFundsWidget->setChecked(visible);
}
}
} // END namespace gnc

View File

@ -28,6 +28,7 @@
#include <QSharedPointer>
#include "gnc/Session.hpp"
#include "gnc/AccountItemModel.hpp"
#include "gnc/dashboard.hpp"
class QAction;
class QMenu;
@ -35,6 +36,7 @@ class QPlainTextEdit;
class QTextEdit;
class QTabWidget;
class QUndoStack;
class QToolButton;
namespace Ui
{
@ -45,6 +47,7 @@ namespace gnc
{
class RecentFileMenu;
class Dashboard;
/** The main window of Cutecash.
*
@ -61,6 +64,7 @@ public:
const QString& getCurrentFilename() const { return m_currentFilename; }
bool hasOpenedFile() const { return !m_currentFilename.isEmpty(); }
void dockWidgetsVisibilityChanged(int wdg, bool visible);
public slots:
void accountItemActivated(const QModelIndex & index);
@ -70,6 +74,9 @@ public slots:
protected:
void closeEvent(QCloseEvent *event);
signals:
void dashboardVisible(bool visible);
private slots:
void newFile();
void on_actionOpen_triggered();
@ -84,6 +91,7 @@ private slots:
void on_actionViewAccountTree_triggered(bool checked);
void on_actionViewAccountList_triggered(bool checked);
void on_actionViewWelcomepage_triggered(bool checked);
void on_actionViewDashboard_triggered(bool checked);
void documentWasModified();
void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected );
@ -92,7 +100,8 @@ private:
void createToolBars();
void createStatusBar();
void setIcons();
void readSettings();
void readSettings();
void autoLoadRecentFile();
void writeSettings();
bool maybeSave();
void setCurrentFile(const QString &fileName);
@ -123,11 +132,15 @@ private:
QToolBar *m_fileToolBar;
QToolBar *m_editToolBar;
QToolBar *m_dashboardToolBar;
QAction *m_actionUndo;
QAction *m_actionRedo;
QToolButton *m_btnTransferFundsWidget;
QSharedPointer<RecentFileMenu> m_menuRecentFiles;
QUndoStack *m_undoStack;
Dashboard *dboard;
Session m_session;
AccountListModel *m_accountListModel;
AccountTreeModel *m_accountTreeModel;

View File

@ -63,7 +63,7 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt; font-weight:600;&quot;&gt;Cutecash&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt; font-weight:600;&quot;&gt;Free Finance Software. Easy to develop, easy to use.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;Currently this is more or less a proof-of-concept for developers:&lt;/span&gt;&lt;/p&gt;
@ -190,6 +190,7 @@ p, li { white-space: pre-wrap; }
<addaction name="actionViewWelcomepage"/>
<addaction name="actionViewAccountList"/>
<addaction name="actionViewAccountTree"/>
<addaction name="actionViewDashboard"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
@ -370,6 +371,39 @@ p, li { white-space: pre-wrap; }
<string>&amp;Close Current Tab</string>
</property>
</action>
<action name="actionViewDashboard">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Dashboard</string>
</property>
</action>
<action name="actionViewTransferFunds">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Transfer Funds</string>
</property>
</action>
<action name="actionViewFPO">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;FPO</string>
</property>
</action>
</widget>
<resources>
<include location="gnucash.qrc"/>

48
src/gnc/qss/default.qss Normal file
View File

@ -0,0 +1,48 @@
#dateWidget {
background-color: #FAA0A0;
color:black;
border-style: outset;
border-width: 1px;
border-radius: 5px;
border-color: beige;
border-bottom-width: 2px;
border-bottom-color: darkgray;
border-bottom-style: solid;
min-width: 12em;
padding: 2px;
}
#accountWidget {
background-color: #A0A1FA;
border-style: outset;
border-width: 1px;
border-radius: 5px;
border-color: beige;
padding: 2px;
/* Test with colours */
/*
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.5, y2: 0.5,
stop: 0 #FF92BB, stop: 1 white);
*/
}
#descWidget {
background-color: #A9FAA0;
border-style: outset;
border-width: 1px;
border-radius: 5px;
border-color: beige;
padding: 2px;
}
#amountWidget {
background-color: #F0F7F0;
border-style: outset;
border-width: 1px;
border-radius: 5px;
border-color: beige;
padding: 2px;
}

5
src/gnc/stylesheets.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file alias="qss-default">qss/default.qss</file>
</qresource>
</RCC>