aboutsummaryrefslogtreecommitdiff
path: root/cashflow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cashflow.cpp')
-rw-r--r--cashflow.cpp215
1 files changed, 138 insertions, 77 deletions
diff --git a/cashflow.cpp b/cashflow.cpp
index 8e48d27..8eb46a4 100644
--- a/cashflow.cpp
+++ b/cashflow.cpp
@@ -1,10 +1,13 @@
#include "cashflow.h"
#include "ui_cashflow.h"
+#include "settingsdialog.h"
#include <QMessageBox>
#include <QDir>
#include <QStandardPaths>
#include <QFontDialog>
#include <QLocale>
+#include <QFileDialog>
+#include <QApplication>
CashFlow::CashFlow(QWidget *parent)
: QMainWindow(parent)
@@ -13,30 +16,24 @@ CashFlow::CashFlow(QWidget *parent)
, currentRecurringId(-1)
, startingBalance(0.0)
, currentAmountFont("Courier New", 10)
+ , weekStartDay(1) // Default to Monday
{
ui->setupUi(this);
// Initialize database
database = new Database();
- QString dbPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/cashflow.db";
- QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
- if (!database->open(dbPath)) {
- QMessageBox::critical(this, "Database Error", "Failed to open database: " + database->lastError());
- return;
- }
+ // Try to open default database
+ QString defaultDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
+ QDir().mkpath(defaultDir);
+ QString defaultPath = defaultDir + "/default.cashflo.sqlite";
setupConnections();
- loadSettings();
- // Set default date range (current month to 3 months out)
- QDate today = QDate::currentDate();
- ui->dateFromEdit->setDate(QDate(today.year(), today.month(), 1));
- ui->dateToEdit->setDate(today.addMonths(3));
-
- clearTransactionEntry();
- clearRecurringEntry();
- refreshView();
+ if (!openDatabase(defaultPath)) {
+ QMessageBox::critical(this, "Database Error", "Failed to open default database: " + database->lastError());
+ return;
+ }
}
CashFlow::~CashFlow()
@@ -46,6 +43,14 @@ CashFlow::~CashFlow()
}
void CashFlow::setupConnections() {
+ // File menu
+ connect(ui->actionNew, &QAction::triggered, this, &CashFlow::onNewFile);
+ connect(ui->actionOpen, &QAction::triggered, this, &CashFlow::onOpenFile);
+ connect(ui->actionQuit, &QAction::triggered, this, &CashFlow::onQuit);
+
+ // Settings menu
+ connect(ui->actionPreferences, &QAction::triggered, this, &CashFlow::onPreferences);
+
// Transaction tab
connect(ui->dateFromEdit, &QDateEdit::dateChanged, this, &CashFlow::onDateRangeChanged);
connect(ui->dateToEdit, &QDateEdit::dateChanged, this, &CashFlow::onDateRangeChanged);
@@ -69,14 +74,6 @@ void CashFlow::setupConnections() {
// Set up Delete key shortcut for transaction table
ui->deleteBtn->setShortcut(Qt::Key_Delete);
- // Auto-save transaction fields on change
- connect(ui->entryDateEdit, &QDateEdit::dateChanged, this, &CashFlow::onTransactionFieldChanged);
- connect(ui->entryAmountSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CashFlow::onTransactionFieldChanged);
- connect(ui->entryAccountCombo, &QComboBox::currentTextChanged, this, &CashFlow::onTransactionFieldChanged);
- connect(ui->entryCategoryCombo, &QComboBox::currentTextChanged, this, &CashFlow::onTransactionFieldChanged);
- connect(ui->entryDescriptionEdit, &QLineEdit::textChanged, this, &CashFlow::onTransactionFieldChanged);
- connect(ui->entryTypeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CashFlow::onTransactionFieldChanged);
-
// Color-code amount inputs
connect(ui->entryAmountSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CashFlow::updateAmountColors);
connect(ui->recurringAmountSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &CashFlow::updateAmountColors);
@@ -87,10 +84,6 @@ void CashFlow::setupConnections() {
connect(ui->newRecurringBtn, &QPushButton::clicked, this, &CashFlow::onNewRecurring);
connect(ui->deleteRecurringBtn, &QPushButton::clicked, this, &CashFlow::onDeleteRecurring);
- // Settings tab
- connect(ui->amountFontBtn, &QPushButton::clicked, this, &CashFlow::onChooseAmountFont);
- connect(ui->saveSettingsBtn, &QPushButton::clicked, this, &CashFlow::onSaveSettings);
-
// Set up Delete key shortcut for recurring table
ui->deleteRecurringBtn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Delete));
}
@@ -282,9 +275,14 @@ QDate CashFlow::getPeriodEnd(const QDate &date, PeriodType periodType) {
case Daily:
return date;
case Weekly: {
- // End on Sunday (7)
- int daysUntilSunday = 7 - date.dayOfWeek();
- return date.addDays(daysUntilSunday);
+ // End on day before week start day
+ int weekEndDay = (weekStartDay == 1) ? 7 : weekStartDay - 1;
+ int currentDay = date.dayOfWeek();
+ int daysUntilWeekEnd = (weekEndDay - currentDay + 7) % 7;
+ if (daysUntilWeekEnd == 0 && currentDay != weekEndDay) {
+ daysUntilWeekEnd = 7; // If we're past the end, go to next week's end
+ }
+ return date.addDays(daysUntilWeekEnd);
}
case Monthly:
return QDate(date.year(), date.month(), date.daysInMonth());
@@ -322,9 +320,10 @@ QDate CashFlow::getPeriodStart(const QDate &date, PeriodType periodType) {
case Daily:
return date;
case Weekly: {
- // Start on Monday (1)
- int daysFromMonday = date.dayOfWeek() - 1;
- return date.addDays(-daysFromMonday);
+ // Start on configured week start day (1=Monday, 7=Sunday)
+ int currentDay = date.dayOfWeek(); // 1=Monday, 7=Sunday
+ int daysFromWeekStart = (currentDay - weekStartDay + 7) % 7;
+ return date.addDays(-daysFromWeekStart);
}
case Monthly:
return QDate(date.year(), date.month(), 1);
@@ -595,6 +594,23 @@ void CashFlow::onTransactionSelected() {
}
void CashFlow::onSaveTransaction() {
+ // Skip validation if this is a new empty transaction being auto-saved
+ bool isEmptyNew = (currentTransactionId == -1 &&
+ ui->entryAccountCombo->currentText().isEmpty() &&
+ ui->entryAmountSpin->value() == 0.0);
+
+ if (!isEmptyNew) {
+ // Validate required fields
+ if (ui->entryAccountCombo->currentText().isEmpty()) {
+ QMessageBox::warning(this, "Required Field", "Account is required.");
+ return;
+ }
+ if (ui->entryAmountSpin->value() == 0.0) {
+ QMessageBox::warning(this, "Required Field", "Amount cannot be zero.");
+ return;
+ }
+ }
+
Transaction t;
t.id = currentTransactionId;
t.date = ui->entryDateEdit->date();
@@ -629,15 +645,6 @@ void CashFlow::onSaveTransaction() {
}
}
-void CashFlow::onTransactionFieldChanged() {
- // Auto-save if we're editing an existing transaction or have data entered
- if (currentTransactionId != -1 ||
- !ui->entryAccountCombo->currentText().isEmpty() ||
- ui->entryAmountSpin->value() != 0.0) {
- onSaveTransaction();
- }
-}
-
void CashFlow::onNewTransaction() {
clearTransactionEntry();
ui->entryDateEdit->setDate(QDate::currentDate());
@@ -849,59 +856,113 @@ void CashFlow::updateAmountColors() {
void CashFlow::loadSettings() {
// Load settings from database
- QString currency = database->getSetting("currency_symbol", "$");
QString fontFamily = database->getSetting("amount_font", "Courier New");
int fontSize = database->getSetting("amount_font_size", "10").toInt();
- int defaultPeriod = database->getSetting("default_period", "2").toInt(); // 2 = Monthly
+ int defaultPeriod = database->getSetting("default_period", "2").toInt();
bool showAccountBalances = database->getSetting("show_account_balances", "0").toInt();
+ weekStartDay = database->getSetting("week_start_day", "1").toInt();
- // Set settings UI
- ui->currencyEdit->setText(currency);
+ // Apply to member variables and main UI
currentAmountFont = QFont(fontFamily, fontSize);
- ui->amountFontBtn->setText(QString("%1, %2pt").arg(fontFamily).arg(fontSize));
- ui->defaultPeriodCombo->setCurrentIndex(defaultPeriod);
- ui->defaultShowAccountBalancesCheck->setChecked(showAccountBalances);
-
- // Apply defaults to main UI (only on initial load)
ui->periodCombo->setCurrentIndex(defaultPeriod);
ui->showAccountBalancesCheck->setChecked(showAccountBalances);
}
-void CashFlow::applySettings() {
- // Currency symbol is now part of the formatted text in line edits
- // Font is already stored in currentAmountFont
-
- // Refresh to apply font changes
- refreshView();
+QString CashFlow::formatCurrency(double amount) const {
+ QLocale locale;
+ return locale.toString(amount, 'f', 2);
}
-void CashFlow::onSaveSettings() {
- // Save settings to database
- database->setSetting("currency_symbol", ui->currencyEdit->text());
- database->setSetting("amount_font", currentAmountFont.family());
- database->setSetting("amount_font_size", QString::number(currentAmountFont.pointSize()));
- database->setSetting("default_period", QString::number(ui->defaultPeriodCombo->currentIndex()));
- database->setSetting("show_account_balances", QString::number(ui->defaultShowAccountBalancesCheck->isChecked() ? 1 : 0));
+bool CashFlow::openDatabase(const QString &filePath) {
+ if (database->open(filePath)) {
+ currentFilePath = filePath;
+ QFileInfo fileInfo(filePath);
+ setWindowTitle(QString("CashFlo - %1").arg(fileInfo.fileName()));
+
+ loadSettings();
+
+ // Set default date range (current month to 3 months out)
+ QDate today = QDate::currentDate();
+ ui->dateFromEdit->setDate(QDate(today.year(), today.month(), 1));
+ ui->dateToEdit->setDate(today.addMonths(3));
+
+ clearTransactionEntry();
+ clearRecurringEntry();
+ refreshView();
+
+ return true;
+ }
+ return false;
+}
+
+void CashFlow::onNewFile() {
+ QString defaultDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
+ QDir().mkpath(defaultDir);
+
+ QString fileName = QFileDialog::getSaveFileName(
+ this,
+ "New CashFlo File",
+ defaultDir,
+ "CashFlo Files (*.cashflo.sqlite);;All Files (*)"
+ );
- // Apply settings
- applySettings();
+ if (fileName.isEmpty()) {
+ return;
+ }
+
+ // Ensure .cashflo.sqlite extension
+ if (!fileName.endsWith(".cashflo.sqlite", Qt::CaseInsensitive)) {
+ fileName += ".cashflo.sqlite";
+ }
+
+ // Remove file if it exists
+ if (QFile::exists(fileName)) {
+ QFile::remove(fileName);
+ }
+
+ // Close current database
+ delete database;
+ database = new Database();
- QMessageBox::information(this, "Settings Saved", "Settings have been saved successfully.");
+ if (!openDatabase(fileName)) {
+ QMessageBox::critical(this, "Error", "Failed to create new file: " + database->lastError());
+ }
}
-void CashFlow::onChooseAmountFont() {
- bool ok;
- QFont selectedFont = QFontDialog::getFont(&ok, currentAmountFont, this, "Choose Amount Font", QFontDialog::MonospacedFonts);
+void CashFlow::onOpenFile() {
+ QString defaultDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
+
+ QString fileName = QFileDialog::getOpenFileName(
+ this,
+ "Open CashFlo File",
+ defaultDir,
+ "CashFlo Files (*.cashflo.sqlite);;All Files (*)"
+ );
+
+ if (fileName.isEmpty()) {
+ return;
+ }
+
+ // Close current database
+ delete database;
+ database = new Database();
- if (ok) {
- currentAmountFont = selectedFont;
- ui->amountFontBtn->setText(QString("%1, %2pt").arg(selectedFont.family()).arg(selectedFont.pointSize()));
+ if (!openDatabase(fileName)) {
+ QMessageBox::critical(this, "Error", "Failed to open file: " + database->lastError());
}
}
-QString CashFlow::formatCurrency(double amount) const {
- QLocale locale;
- return locale.toString(amount, 'f', 2);
+void CashFlow::onQuit() {
+ QApplication::quit();
}
-
+void CashFlow::onPreferences() {
+ SettingsDialog dialog(database, this);
+ if (dialog.exec() == QDialog::Accepted) {
+ // Reload settings
+ currentAmountFont = dialog.getCurrentAmountFont();
+ weekStartDay = dialog.getWeekStartDay();
+ loadSettings();
+ refreshView();
+ }
+}