diff options
Diffstat (limited to 'cashflow.cpp')
| -rw-r--r-- | cashflow.cpp | 215 |
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(); + } +} |
