]> Nutra Git (v1) - nutratech/gui.git/commitdiff
better history
authorShane Jaroch <chown_tee@proton.me>
Wed, 21 Jan 2026 23:15:26 +0000 (18:15 -0500)
committerShane Jaroch <chown_tee@proton.me>
Wed, 21 Jan 2026 23:15:26 +0000 (18:15 -0500)
include/widgets/searchwidget.h
src/mainwindow.cpp
src/widgets/searchwidget.cpp

index 9b109aa3565bec6bbb083eb8eca66d20e26a801d..2efe7690e4b09b6298fed94aadddf11d48425898 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SEARCHWIDGET_H
 #define SEARCHWIDGET_H
 
+#include <QDateTime>
 #include <QLineEdit>
 #include <QPushButton>
 #include <QTableWidget>
@@ -18,18 +19,31 @@ public:
 signals:
     void foodSelected(int foodId, const QString& foodName);
     void addToMealRequested(int foodId, const QString& foodName, double grams);
+    void searchStatus(const QString& msg);
 
 private slots:
     void performSearch();
     void onRowDoubleClicked(int row, int column);
     void onCustomContextMenu(const QPoint& pos);
+    void showHistory();
 
 private:
+    void addToHistory(int foodId, const QString& foodName);
+    void loadHistory();
+
     QLineEdit* searchInput;
     QPushButton* searchButton;
+    QPushButton* historyButton;
     QTableWidget* resultsTable;
     FoodRepository repository;
     QTimer* searchTimer;
+
+    struct HistoryItem {
+        int id;
+        QString name;
+        QDateTime timestamp;
+    };
+    QList<HistoryItem> recentHistory;
 };
 
 #endif  // SEARCHWIDGET_H
index 4a80b855fb38aca31c29d7a1f950f7c974a1fe41..b9328149bf702b5e471a06fffd6e5d73de459385 100644 (file)
@@ -91,6 +91,8 @@ void MainWindow::setupUi() {
     connect(searchWidget, &SearchWidget::foodSelected, this,
             [=](int foodId, const QString& foodName) {
                 qDebug() << "Selected food:" << foodName << "(" << foodId << ")";
+                // Determine if we are in analysis mode or just searching
+                // For now, simpler handling:
                 detailsWidget->loadFood(foodId, foodName);
                 tabs->setCurrentWidget(detailsWidget);
             });
@@ -101,6 +103,9 @@ void MainWindow::setupUi() {
                 tabs->setCurrentWidget(mealWidget);
             });
 
+    connect(searchWidget, &SearchWidget::searchStatus, this,
+            [=](const QString& msg) { dbStatusLabel->setText(msg); });
+
     // Analysis Tab
     detailsWidget = new DetailsWidget(this);
     tabs->addTab(detailsWidget, "Analyze");
@@ -117,8 +122,6 @@ void MainWindow::setupUi() {
     connect(detailsWidget, &DetailsWidget::addToMeal, this,
             [=](int foodId, const QString& foodName, double grams) {
                 mealWidget->addFood(foodId, foodName, grams);
-                // Optional: switch tab?
-                // tabs->setCurrentWidget(mealWidget);
             });
 
     // Connect Meal Builder -> Daily Log
@@ -248,16 +251,19 @@ void MainWindow::updateRecentFileActions() {
     int numToShow = static_cast<int>(qMin(static_cast<std::size_t>(sortedFiles.size()),
                                           static_cast<std::size_t>(MaxRecentFiles)));
 
+    QFontMetrics fontMetrics(recentFilesMenu->font());
+
     for (int i = 0; i < numToShow; ++i) {
         QVariantMap m = sortedFiles[i];
         QString path = m["path"].toString();
         QString type = m["type"].toString();
         int version = m["version"].toInt();
-        QString name = QFileInfo(path).fileName();
 
-        // Format: "nt.sqlite3 (User v1)"
-        // Or per user request: "Display pragma version... for full transparency"
-        QString text = QString("&%1 %2 (%3 v%4)").arg(i + 1).arg(name).arg(type).arg(version);
+        // Elide path to ~400 pixels (roughly 50-60 chars depending on font)
+        QString elidedPath = fontMetrics.elidedText(path, Qt::ElideMiddle, 400);
+
+        // Format: "/path/to/file... (User v9)"
+        QString text = QString("&%1 %2 (%3 v%4)").arg(i + 1).arg(elidedPath).arg(type).arg(version);
 
         recentFileActions[static_cast<std::size_t>(i)]->setText(text);
         recentFileActions[static_cast<std::size_t>(i)]->setData(path);
index a4a0b805d3ef16afa0eb2d817324524b2a0615b3..7c5d19e77f4731dcb67c129e2d683a393bb09e8f 100644 (file)
@@ -1,14 +1,16 @@
 #include "widgets/searchwidget.h"
 
 #include <QAction>
+#include <QDateTime>
+#include <QElapsedTimer>
 #include <QHBoxLayout>
 #include <QHeaderView>
 #include <QMenu>
 #include <QMessageBox>
+#include <QSettings>
 #include <QVBoxLayout>
 
 #include "widgets/weightinputdialog.h"
-
 SearchWidget::SearchWidget(QWidget* parent) : QWidget(parent) {
     auto* layout = new QVBoxLayout(this);
 
@@ -29,7 +31,14 @@ SearchWidget::SearchWidget(QWidget* parent) : QWidget(parent) {
     connect(searchButton, &QPushButton::clicked, this, &SearchWidget::performSearch);
 
     searchLayout->addWidget(searchInput);
+    searchButton = new QPushButton("Search", this);
+    connect(searchButton, &QPushButton::clicked, this, &SearchWidget::performSearch);
     searchLayout->addWidget(searchButton);
+
+    historyButton = new QPushButton("History", this);
+    connect(historyButton, &QPushButton::clicked, this, &SearchWidget::showHistory);
+    searchLayout->addWidget(historyButton);
+
     layout->addLayout(searchLayout);
 
     // Results table
@@ -50,20 +59,29 @@ SearchWidget::SearchWidget(QWidget* parent) : QWidget(parent) {
             &SearchWidget::onCustomContextMenu);
 
     layout->addWidget(resultsTable);
+
+    loadHistory();
 }
 
 void SearchWidget::performSearch() {
     QString query = searchInput->text().trimmed();
     if (query.length() < 2) return;
 
+    QElapsedTimer timer;
+    timer.start();
+
     resultsTable->setRowCount(0);
 
     std::vector<FoodItem> results = repository.searchFoods(query);
+    int elapsed = timer.elapsed();
 
     resultsTable->setRowCount(static_cast<int>(results.size()));
     for (int i = 0; i < static_cast<int>(results.size()); ++i) {
         const auto& item = results[i];
         resultsTable->setItem(i, 0, new QTableWidgetItem(QString::number(item.id)));
+        resultsTable->setItem(i, 1,
+                              new QTableWidgetItem(item.description));  // Fixed: Description Column
+
         static const std::map<int, QString> groupAbbreviations = {
             {1100, "Vegetables"},      // Vegetables and Vegetable Products
             {600, "Soups/Sauces"},     // Soups, Sauces, and Gravies
@@ -105,6 +123,9 @@ void SearchWidget::performSearch() {
         resultsTable->setItem(i, 5, new QTableWidgetItem(QString::number(item.flavCount)));
         resultsTable->setItem(i, 6, new QTableWidgetItem(QString::number(item.score)));
     }
+
+    emit searchStatus(
+        QString("Search: matched %1 foods in %2 ms").arg(results.size()).arg(elapsed));
 }
 
 void SearchWidget::onRowDoubleClicked(int row, int column) {
@@ -113,7 +134,10 @@ void SearchWidget::onRowDoubleClicked(int row, int column) {
     QTableWidgetItem* descItem = resultsTable->item(row, 1);
 
     if (idItem != nullptr && descItem != nullptr) {
-        emit foodSelected(idItem->text().toInt(), descItem->text());
+        int id = idItem->text().toInt();
+        QString name = descItem->text();
+        addToHistory(id, name);
+        emit foodSelected(id, name);
     }
 }
 
@@ -136,6 +160,10 @@ void SearchWidget::onCustomContextMenu(const QPoint& pos) {
 
     QAction* selectedAction = menu.exec(resultsTable->viewport()->mapToGlobal(pos));
 
+    if (selectedAction) {
+        addToHistory(foodId, foodName);
+    }
+
     if (selectedAction == analyzeAction) {
         emit foodSelected(foodId, foodName);
     } else if (selectedAction == addToMealAction) {
@@ -146,3 +174,64 @@ void SearchWidget::onCustomContextMenu(const QPoint& pos) {
         }
     }
 }
+
+void SearchWidget::addToHistory(int foodId, const QString& foodName) {
+    // Remove if exists to move to top
+    for (int i = 0; i < recentHistory.size(); ++i) {
+        if (recentHistory[i].id == foodId) {
+            recentHistory.removeAt(i);
+            break;
+        }
+    }
+
+    HistoryItem item{foodId, foodName, QDateTime::currentDateTime()};
+    recentHistory.prepend(item);
+
+    // Limit to 50
+    while (recentHistory.size() > 50) {
+        recentHistory.removeLast();
+    }
+
+    // Save to settings
+    QSettings settings("NutraTech", "Nutra");
+    QList<QVariant> list;
+    for (const auto& h : recentHistory) {
+        QVariantMap m;
+        m["id"] = h.id;
+        m["name"] = h.name;
+        m["timestamp"] = h.timestamp;
+        list.append(m);
+    }
+    settings.setValue("recentFoods", list);
+}
+
+void SearchWidget::loadHistory() {
+    QSettings settings("NutraTech", "Nutra");
+    QList<QVariant> list = settings.value("recentFoods").toList();
+    recentHistory.clear();
+    for (const auto& v : list) {
+        QVariantMap m = v.toMap();
+        HistoryItem item;
+        item.id = m["id"].toInt();
+        item.name = m["name"].toString();
+        item.timestamp = m["timestamp"].toDateTime();
+        recentHistory.append(item);
+    }
+}
+
+void SearchWidget::showHistory() {
+    resultsTable->setRowCount(0);
+    resultsTable->setRowCount(recentHistory.size());
+
+    for (int i = 0; i < recentHistory.size(); ++i) {
+        const auto& item = recentHistory[i];
+        resultsTable->setItem(i, 0, new QTableWidgetItem(QString::number(item.id)));
+        resultsTable->setItem(i, 1, new QTableWidgetItem(item.name));
+        resultsTable->setItem(i, 2, new QTableWidgetItem("History"));
+        // Empty cols for nutrients etc since we don't store them in history
+        for (int c = 3; c < 7; ++c) {
+            resultsTable->setItem(i, c, new QTableWidgetItem(""));
+        }
+    }
+    emit searchStatus(QString("Showing %1 recent items").arg(recentHistory.size()));
+}