From: Shane Jaroch Date: Wed, 21 Jan 2026 10:59:23 +0000 (-0500) Subject: add some UI components to mainwindow X-Git-Url: https://git.nutra.tk/v2?a=commitdiff_plain;h=68da43216f6afc477447ae2dc07f29c42bf4cd4c;p=nutratech%2Fgui.git add some UI components to mainwindow --- diff --git a/CMakeLists.txt b/CMakeLists.txt index dc3de9a..a638c40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set(PROJECT_SOURCES # Versioning if(NOT NUTRA_VERSION) execute_process( - COMMAND git describe --tags --always --dirty + COMMAND git describe --tags --always WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_VERSION ERROR_QUIET diff --git a/Makefile b/Makefile index 3f58b8e..c7690f0 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CTEST := ctest SRC_DIRS := src # Get version from git -VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "v0.0.0") +VERSION := $(shell git describe --tags --always 2>/dev/null || echo "v0.0.0") # Find source files for linting LINT_LOCS_CPP ?= $(shell git ls-files '*.cpp') diff --git a/include/mainwindow.h b/include/mainwindow.h index fce7ce9..12e4bf2 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -14,16 +14,25 @@ public: MainWindow(QWidget *parent = nullptr); ~MainWindow() override; +private slots: + void onOpenDatabase(); + void onRecentFileClick(); + void onSettings(); + void onAbout(); + private: void setupUi(); + void updateRecentFileActions(); + void addToRecentFiles(const QString &path); QTabWidget *tabs; SearchWidget *searchWidget; DetailsWidget *detailsWidget; MealWidget *mealWidget; -private slots: - void onAbout(); + QMenu *recentFilesMenu; + static constexpr int MaxRecentFiles = 5; + QAction *recentFileActions[MaxRecentFiles]; }; #endif // MAINWINDOW_H diff --git a/src/main.cpp b/src/main.cpp index a6857d0..3e33a54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -44,19 +45,32 @@ int main(int argc, char *argv[]) { } if (dbPath.isEmpty()) { - // If not found, default to XDG AppData location for error message/setup - // But we can't create it here. - dbPath = QDir::homePath() + "/.nutra/usda.sqlite3"; // Fallback default qWarning() << "Database not found in standard locations."; + QMessageBox::StandardButton resBtn = QMessageBox::question( + nullptr, "Database Not Found", + "The Nutrient database (usda.sqlite3) was not found.\nWould you like " + "to browse for it manually?", + QMessageBox::No | QMessageBox::Yes, QMessageBox::Yes); + + if (resBtn == QMessageBox::Yes) { + dbPath = QFileDialog::getOpenFileName( + nullptr, "Find usda.sqlite3", QDir::homePath(), + "SQLite Databases (*.sqlite3 *.db)"); + } + + if (dbPath.isEmpty()) { + return 1; // User cancelled or still not found + } } if (!DatabaseManager::instance().connect(dbPath)) { QString errorMsg = QString("Failed to connect to database at:\n%1\n\nPlease ensure the " - "database file exists or reinstall the application.") + "database file exists or browse for a valid SQLite file.") .arg(dbPath); qCritical() << errorMsg; QMessageBox::critical(nullptr, "Database Error", errorMsg); + // Let's try to let the user browse one more time before giving up return 1; } qDebug() << "Connected to database at:" << dbPath; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f56469d..facd93f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,14 +1,26 @@ #include "mainwindow.h" +#include "db/databasemanager.h" +#include +#include +#include #include #include #include +#include +#include #include - -#include -#include #include -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupUi(); } +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + for (int i = 0; i < MaxRecentFiles; ++i) { + recentFileActions[i] = new QAction(this); + recentFileActions[i]->setVisible(false); + connect(recentFileActions[i], &QAction::triggered, this, + &MainWindow::onRecentFileClick); + } + setupUi(); + updateRecentFileActions(); +} MainWindow::~MainWindow() = default; @@ -17,7 +29,24 @@ void MainWindow::setupUi() { setWindowIcon(QIcon(":/resources/nutrition_icon-no_bg.png")); resize(1000, 700); - // Menu Bar + // File Menu + auto *fileMenu = menuBar()->addMenu("&File"); + auto *openDbAction = fileMenu->addAction("&Open Database..."); + recentFilesMenu = fileMenu->addMenu("Recent Databases"); + fileMenu->addSeparator(); + auto *exitAction = fileMenu->addAction("E&xit"); + connect(openDbAction, &QAction::triggered, this, &MainWindow::onOpenDatabase); + connect(exitAction, &QAction::triggered, this, &QWidget::close); + + for (int i = 0; i < MaxRecentFiles; ++i) + recentFilesMenu->addAction(recentFileActions[i]); + + // Edit Menu + auto *editMenu = menuBar()->addMenu("&Edit"); + auto *settingsAction = editMenu->addAction("&Settings"); + connect(settingsAction, &QAction::triggered, this, &MainWindow::onSettings); + + // Help Menu auto *helpMenu = menuBar()->addMenu("&Help"); auto *aboutAction = helpMenu->addAction("&About"); connect(aboutAction, &QAction::triggered, this, &MainWindow::onAbout); @@ -59,6 +88,76 @@ void MainWindow::setupUi() { }); } +void MainWindow::onOpenDatabase() { + QString fileName = QFileDialog::getOpenFileName( + this, "Open USDA Database", "", "SQLite Databases (*.sqlite3 *.db)"); + + if (!fileName.isEmpty()) { + if (DatabaseManager::instance().connect(fileName)) { + qDebug() << "Switched to database:" << fileName; + addToRecentFiles(fileName); + // In a real app, we'd emit a signal or refresh all widgets + // For now, let's just log and show success + QMessageBox::information(this, "Database Opened", + "Successfully connected to: " + fileName); + } else { + QMessageBox::critical(this, "Database Error", + "Failed to connect to the database."); + } + } +} + +void MainWindow::onRecentFileClick() { + auto *action = qobject_cast(sender()); + if (action != nullptr) { + QString fileName = action->data().toString(); + if (DatabaseManager::instance().connect(fileName)) { + qDebug() << "Switched to database (recent):" << fileName; + addToRecentFiles(fileName); + QMessageBox::information(this, "Database Opened", + "Successfully connected to: " + fileName); + } else { + QMessageBox::critical(this, "Database Error", + "Failed to connect to: " + fileName); + } + } +} + +void MainWindow::updateRecentFileActions() { + QSettings settings("NutraTech", "Nutra"); + QStringList files = settings.value("recentFiles").toStringList(); + + int numRecentFiles = qMin(files.size(), MaxRecentFiles); + + for (int i = 0; i < numRecentFiles; ++i) { + QString text = + QString("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName()); + recentFileActions[i]->setText(text); + recentFileActions[i]->setData(files[i]); + recentFileActions[i]->setVisible(true); + } + for (int i = numRecentFiles; i < MaxRecentFiles; ++i) + recentFileActions[i]->setVisible(false); + + recentFilesMenu->setEnabled(numRecentFiles > 0); +} + +void MainWindow::addToRecentFiles(const QString &path) { + QSettings settings("NutraTech", "Nutra"); + QStringList files = settings.value("recentFiles").toStringList(); + files.removeAll(path); + files.prepend(path); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + settings.setValue("recentFiles", files); + updateRecentFileActions(); +} + +void MainWindow::onSettings() { + QMessageBox::information(this, "Settings", "Settings dialog coming soon!"); +} + void MainWindow::onAbout() { QMessageBox::about( this, "About Nutrient Coach",