first commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#include "databasemanager.h"
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
#include <QVariant>
|
||||
#include <QFileInfo>
|
||||
|
||||
DatabaseManager::DatabaseManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
DatabaseManager::~DatabaseManager()
|
||||
{
|
||||
if (m_db.isOpen()) {
|
||||
m_db.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseManager::initialize(const QString &dbPath)
|
||||
{
|
||||
// Check if database is already initialized
|
||||
if (m_initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
QFileInfo fileInfo(dbPath);
|
||||
if (!fileInfo.exists() || !fileInfo.isFile()) {
|
||||
qDebug() << "Database file does not exist:" << dbPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up database connection
|
||||
m_db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
m_db.setDatabaseName(dbPath);
|
||||
|
||||
// Open database
|
||||
if (!m_db.open()) {
|
||||
qDebug() << "Failed to open database:" << m_db.lastError().text();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify required table exists
|
||||
QSqlQuery query;
|
||||
if (!query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='ocr_results'")) {
|
||||
qDebug() << "Failed to execute query:" << query.lastError().text();
|
||||
m_db.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!query.next()) {
|
||||
qDebug() << "The required table 'ocr_results' does not exist in the database.";
|
||||
m_db.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the table has the required columns
|
||||
if (!query.exec("PRAGMA table_info(ocr_results)")) {
|
||||
qDebug() << "Failed to get table info:" << query.lastError().text();
|
||||
m_db.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasFullPath = false;
|
||||
bool hasOcrText = false;
|
||||
|
||||
while (query.next()) {
|
||||
QString columnName = query.value(1).toString();
|
||||
if (columnName == "full_path") hasFullPath = true;
|
||||
if (columnName == "ocr_text") hasOcrText = true;
|
||||
}
|
||||
|
||||
if (!hasFullPath || !hasOcrText) {
|
||||
qDebug() << "Missing required columns in ocr_results table. Need 'full_path' and 'ocr_text'";
|
||||
m_db.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
qDebug() << "Database initialized successfully.";
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<DatabaseManager::ImageItem> DatabaseManager::getAllImages()
|
||||
{
|
||||
QList<ImageItem> images;
|
||||
|
||||
if (!m_initialized) {
|
||||
qDebug() << "Database not initialized.";
|
||||
return images;
|
||||
}
|
||||
|
||||
// Verify database is still connected
|
||||
if (!m_db.isOpen() && !m_db.open()) {
|
||||
qDebug() << "Database connection lost and cannot be reopened:" << m_db.lastError().text();
|
||||
m_initialized = false;
|
||||
return images;
|
||||
}
|
||||
|
||||
QSqlQuery query;
|
||||
query.prepare("SELECT full_path, ocr_text FROM ocr_results");
|
||||
|
||||
if (!query.exec()) {
|
||||
qDebug() << "Failed to fetch images:" << query.lastError().text();
|
||||
return images;
|
||||
}
|
||||
|
||||
// Check if files exist as we add them
|
||||
while (query.next()) {
|
||||
ImageItem item;
|
||||
item.filePath = query.value(0).toString();
|
||||
item.ocrText = query.value(1).toString();
|
||||
|
||||
// Only add images that have a non-empty path
|
||||
if (!item.filePath.isEmpty()) {
|
||||
images.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
QList<DatabaseManager::ImageItem> DatabaseManager::searchImages(const QString &searchText)
|
||||
{
|
||||
QList<ImageItem> images;
|
||||
|
||||
if (!m_initialized) {
|
||||
qDebug() << "Database not initialized.";
|
||||
return images;
|
||||
}
|
||||
|
||||
// Verify database is still connected
|
||||
if (!m_db.isOpen() && !m_db.open()) {
|
||||
qDebug() << "Database connection lost and cannot be reopened:" << m_db.lastError().text();
|
||||
m_initialized = false;
|
||||
return images;
|
||||
}
|
||||
|
||||
// If search text is empty, return all images
|
||||
if (searchText.isEmpty()) {
|
||||
return getAllImages();
|
||||
}
|
||||
|
||||
QSqlQuery query;
|
||||
// Use LIKE query with wildcards for flexible searching
|
||||
query.prepare("SELECT full_path, ocr_text FROM ocr_results WHERE ocr_text LIKE :search");
|
||||
|
||||
// Ensure search text is properly sanitized
|
||||
QString sanitizedSearch = searchText;
|
||||
sanitizedSearch.replace('\'', "''"); // Escape single quotes
|
||||
|
||||
query.bindValue(":search", "%" + sanitizedSearch + "%");
|
||||
|
||||
if (!query.exec()) {
|
||||
qDebug() << "Failed to search images:" << query.lastError().text();
|
||||
return images;
|
||||
}
|
||||
|
||||
while (query.next()) {
|
||||
ImageItem item;
|
||||
item.filePath = query.value(0).toString();
|
||||
item.ocrText = query.value(1).toString();
|
||||
|
||||
// Only add images that have a non-empty path
|
||||
if (!item.filePath.isEmpty()) {
|
||||
images.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef DATABASEMANAGER_H
|
||||
#define DATABASEMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QThread>
|
||||
|
||||
/**
|
||||
* @brief The DatabaseManager class handles all database operations
|
||||
* for the screenshot gallery application.
|
||||
*/
|
||||
class DatabaseManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Struct to represent an image item with its path and OCR text
|
||||
*/
|
||||
struct ImageItem {
|
||||
QString filePath;
|
||||
QString ocrText;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DatabaseManager constructor
|
||||
* @param parent The parent QObject
|
||||
*/
|
||||
explicit DatabaseManager(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief DatabaseManager destructor
|
||||
*/
|
||||
~DatabaseManager();
|
||||
|
||||
/**
|
||||
* @brief Initialize the database connection
|
||||
* @param dbPath Path to the SQLite database
|
||||
* @return True if connection was successful, false otherwise
|
||||
*/
|
||||
bool initialize(const QString &dbPath);
|
||||
|
||||
/**
|
||||
* @brief Get all images from the database
|
||||
* @return List of ImageItem objects
|
||||
*/
|
||||
QList<ImageItem> getAllImages();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Search for images matching the search text
|
||||
* @param searchText Text to search for in OCR results
|
||||
* @return List of ImageItem objects that match the search
|
||||
*/
|
||||
QList<ImageItem> searchImages(const QString &searchText);
|
||||
|
||||
private:
|
||||
QSqlDatabase m_db;
|
||||
bool m_initialized;
|
||||
};
|
||||
|
||||
#endif // DATABASEMANAGER_H
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "imagegallery.h"
|
||||
#include <QMouseEvent>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
|
||||
// ImageThumbnail implementation
|
||||
ImageThumbnail::ImageThumbnail(const QString &filePath, QWidget *parent)
|
||||
: QLabel(parent)
|
||||
, m_filePath(filePath)
|
||||
{
|
||||
setFixedSize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
|
||||
setAlignment(Qt::AlignCenter);
|
||||
setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
setLineWidth(2);
|
||||
setScaledContents(false);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
setToolTip(filePath);
|
||||
|
||||
// Enable text wrapping and text interaction
|
||||
setWordWrap(true);
|
||||
setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
// Set a minimum size policy
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
void ImageThumbnail::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
emit thumbnailClicked(m_filePath);
|
||||
}
|
||||
QLabel::mousePressEvent(event);
|
||||
}
|
||||
|
||||
// ImageGallery implementation
|
||||
ImageGallery::ImageGallery(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_dbManager(nullptr)
|
||||
{
|
||||
// Create scroll area
|
||||
m_scrollArea = new QScrollArea(this);
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
// Create container widget for the grid layout
|
||||
m_containerWidget = new QWidget(m_scrollArea);
|
||||
m_gridLayout = new QGridLayout(m_containerWidget);
|
||||
m_gridLayout->setSpacing(10);
|
||||
|
||||
m_scrollArea->setWidget(m_containerWidget);
|
||||
|
||||
// Create layout for the gallery widget
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(m_scrollArea);
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
ImageGallery::~ImageGallery()
|
||||
{
|
||||
clearGallery();
|
||||
}
|
||||
|
||||
void ImageGallery::setDatabaseManager(DatabaseManager *dbManager)
|
||||
{
|
||||
m_dbManager = dbManager;
|
||||
}
|
||||
|
||||
void ImageGallery::displayImages(const QList<DatabaseManager::ImageItem> &images)
|
||||
{
|
||||
// Clear existing thumbnails
|
||||
clearGallery();
|
||||
|
||||
const int numImages = images.size();
|
||||
int row = 0, col = 0;
|
||||
|
||||
for (int i = 0; i < numImages; ++i) {
|
||||
const auto &item = images[i];
|
||||
|
||||
// Check if file exists before creating thumbnail
|
||||
QFileInfo fileInfo(item.filePath);
|
||||
if (!fileInfo.exists() || !fileInfo.isReadable()) {
|
||||
qDebug() << "Image file does not exist or is not readable:" << item.filePath;
|
||||
continue; // Skip this image
|
||||
}
|
||||
|
||||
// Create and add thumbnail
|
||||
QPixmap thumbnail = createThumbnail(item.filePath, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
|
||||
ImageThumbnail *thumbnailLabel = new ImageThumbnail(item.filePath, this);
|
||||
thumbnailLabel->setPixmap(thumbnail);
|
||||
|
||||
// Set tooltip to show file path and partial OCR text
|
||||
QString tooltipText = item.filePath;
|
||||
if (!item.ocrText.isEmpty()) {
|
||||
// Limit OCR text length in tooltip
|
||||
QString shortOcrText = item.ocrText;
|
||||
if (shortOcrText.length() > 100) {
|
||||
shortOcrText = shortOcrText.left(97) + "...";
|
||||
}
|
||||
tooltipText += "\n\nOCR Text:\n" + shortOcrText;
|
||||
}
|
||||
thumbnailLabel->setToolTip(tooltipText);
|
||||
|
||||
// Connect the thumbnail click signal
|
||||
connect(thumbnailLabel, &ImageThumbnail::thumbnailClicked,
|
||||
this, &ImageGallery::handleThumbnailClicked);
|
||||
|
||||
// Add to grid
|
||||
m_gridLayout->addWidget(thumbnailLabel, row, col);
|
||||
m_thumbnails.append(thumbnailLabel);
|
||||
|
||||
// Update row and column
|
||||
col++;
|
||||
if (col >= COLUMNS) {
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
// Display a message when no images are found
|
||||
if (m_thumbnails.isEmpty()) {
|
||||
// Create a special ImageThumbnail for the "no images" message
|
||||
ImageThumbnail *noImagesLabel = new ImageThumbnail("", this);
|
||||
noImagesLabel->setText("No images found matching your search criteria");
|
||||
noImagesLabel->setAlignment(Qt::AlignCenter);
|
||||
m_gridLayout->addWidget(noImagesLabel, 0, 0, 1, COLUMNS);
|
||||
m_thumbnails.append(noImagesLabel);
|
||||
}
|
||||
|
||||
// Add stretch to the bottom of the grid
|
||||
m_gridLayout->setRowStretch(row + 1, 1);
|
||||
}
|
||||
|
||||
void ImageGallery::clearGallery()
|
||||
{
|
||||
// Remove all thumbnails
|
||||
for (auto thumbnail : m_thumbnails) {
|
||||
m_gridLayout->removeWidget(thumbnail);
|
||||
disconnect(thumbnail, nullptr, this, nullptr);
|
||||
delete thumbnail;
|
||||
}
|
||||
|
||||
m_thumbnails.clear();
|
||||
}
|
||||
|
||||
void ImageGallery::handleSearchTextChanged(const QString &searchText)
|
||||
{
|
||||
if (m_dbManager) {
|
||||
QList<DatabaseManager::ImageItem> images = m_dbManager->searchImages(searchText);
|
||||
displayImages(images);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageGallery::handleThumbnailClicked(const QString &filePath)
|
||||
{
|
||||
// Show a wait cursor while attempting to open the file
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// Check if file exists
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (fileInfo.exists() && fileInfo.isFile()) {
|
||||
try {
|
||||
// Use QDesktopServices to open the file with the default application
|
||||
bool success = QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
|
||||
if (!success) {
|
||||
qDebug() << "Failed to open file with default application:" << filePath;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "Exception occurred while opening file:" << e.what();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "File does not exist:" << filePath;
|
||||
}
|
||||
|
||||
// Restore cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
QPixmap ImageGallery::createThumbnail(const QString &filePath, int width, int height)
|
||||
{
|
||||
// Verify file exists before attempting to load
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (!fileInfo.exists() || !fileInfo.isReadable()) {
|
||||
qDebug() << "Image file does not exist or is not readable:" << filePath;
|
||||
return createPlaceholderThumbnail(width, height, "File not found");
|
||||
}
|
||||
|
||||
// Try to load the image
|
||||
QPixmap pixmap(filePath);
|
||||
|
||||
// If loading failed, create a placeholder
|
||||
if (pixmap.isNull()) {
|
||||
qDebug() << "Failed to load image:" << filePath;
|
||||
return createPlaceholderThumbnail(width, height, "Failed to load");
|
||||
}
|
||||
|
||||
// Scale pixmap while maintaining aspect ratio
|
||||
return pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
QPixmap ImageGallery::createPlaceholderThumbnail(int width, int height, const QString &message)
|
||||
{
|
||||
// Create a placeholder image with text
|
||||
QPixmap placeholder(width, height);
|
||||
placeholder.fill(Qt::lightGray);
|
||||
|
||||
// Draw some text on the placeholder
|
||||
QPainter painter(&placeholder);
|
||||
painter.setPen(Qt::darkGray);
|
||||
|
||||
// Use a nice font
|
||||
QFont font = painter.font();
|
||||
font.setPointSize(12);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
|
||||
// Draw the text centered in the pixmap
|
||||
painter.drawText(placeholder.rect(), Qt::AlignCenter, message);
|
||||
|
||||
// Add a border
|
||||
painter.setPen(QPen(Qt::darkGray, 2));
|
||||
painter.drawRect(1, 1, width-2, height-2);
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef IMAGEGALLERY_H
|
||||
#define IMAGEGALLERY_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QList>
|
||||
#include <QScrollArea>
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QResizeEvent>
|
||||
#include "databasemanager.h"
|
||||
|
||||
// Global constants
|
||||
static const int COLUMNS = 4;
|
||||
static const int THUMBNAIL_WIDTH = 256;
|
||||
static const int THUMBNAIL_HEIGHT = 256;
|
||||
|
||||
class ImageThumbnail : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ImageThumbnail(const QString &filePath, QWidget *parent = nullptr);
|
||||
|
||||
QString getFilePath() const { return m_filePath; }
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
signals:
|
||||
void thumbnailClicked(const QString &filePath);
|
||||
|
||||
private:
|
||||
QString m_filePath;
|
||||
};
|
||||
|
||||
class ImageGallery : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ImageGallery(QWidget *parent = nullptr);
|
||||
~ImageGallery();
|
||||
|
||||
void setDatabaseManager(DatabaseManager *dbManager);
|
||||
void displayImages(const QList<DatabaseManager::ImageItem> &images);
|
||||
void clearGallery();
|
||||
|
||||
public slots:
|
||||
void handleSearchTextChanged(const QString &searchText);
|
||||
void handleThumbnailClicked(const QString &filePath);
|
||||
|
||||
private:
|
||||
QGridLayout *m_gridLayout;
|
||||
QScrollArea *m_scrollArea;
|
||||
QWidget *m_containerWidget;
|
||||
DatabaseManager *m_dbManager;
|
||||
QList<ImageThumbnail*> m_thumbnails;
|
||||
|
||||
QPixmap createThumbnail(const QString &filePath, int width, int height);
|
||||
QPixmap createPlaceholderThumbnail(int width, int height, const QString &message);
|
||||
};
|
||||
|
||||
#endif // IMAGEGALLERY_H
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <QApplication>
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Set application properties
|
||||
app.setApplicationName("Screenshot Gallery");
|
||||
app.setApplicationVersion("1.0.0");
|
||||
|
||||
// Create and show main window
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
||||
// Enter application event loop
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
#include <QResizeEvent>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <stdexcept>
|
||||
|
||||
// Define the static constant for the default database path
|
||||
const QString MainWindow::DEFAULT_DB_PATH = "/home/master/screenshot_ocr.db";
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_dbManager(new DatabaseManager(this))
|
||||
, m_searchDelayTimer(new QTimer(this))
|
||||
, m_hasValidDatabase(false)
|
||||
{
|
||||
// Set window title and size
|
||||
setWindowTitle(tr("Screenshot OCR Gallery"));
|
||||
resize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
||||
|
||||
// Center window on screen
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
if (screen) {
|
||||
const QRect availableGeometry = screen->availableGeometry();
|
||||
const QSize size = geometry().size();
|
||||
move((availableGeometry.width() - size.width()) / 2,
|
||||
(availableGeometry.height() - size.height()) / 2);
|
||||
}
|
||||
|
||||
// Set up UI
|
||||
createLayout();
|
||||
|
||||
// Initialize timer for delayed search
|
||||
m_searchDelayTimer->setSingleShot(true);
|
||||
m_searchDelayTimer->setInterval(SEARCH_DELAY_MS);
|
||||
connect(m_searchDelayTimer, &QTimer::timeout, this, &MainWindow::performSearch);
|
||||
|
||||
// Initialize database and display images
|
||||
initializeDatabase();
|
||||
displayAllImages();
|
||||
|
||||
// Set focus to search bar
|
||||
m_searchBar->setFocus();
|
||||
|
||||
// Set status bar
|
||||
statusBar()->showMessage(tr("Ready"));
|
||||
updateStatusBar();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
// All QObjects will be automatically deleted via parent-child relationship
|
||||
}
|
||||
|
||||
void MainWindow::createLayout()
|
||||
{
|
||||
// Create central widget
|
||||
m_centralWidget = new QWidget(this);
|
||||
setCentralWidget(m_centralWidget);
|
||||
|
||||
// Create main layout
|
||||
m_mainLayout = new QVBoxLayout(m_centralWidget);
|
||||
|
||||
// Create title label
|
||||
m_titleLabel = new QLabel(tr("Screenshot OCR Gallery"), this);
|
||||
QFont titleFont = m_titleLabel->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
m_titleLabel->setFont(titleFont);
|
||||
m_titleLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
// Create search bar
|
||||
m_searchBar = new QLineEdit(this);
|
||||
m_searchBar->setPlaceholderText(tr("Search OCR text..."));
|
||||
m_searchBar->setClearButtonEnabled(true);
|
||||
|
||||
// Create gallery widget
|
||||
m_imageGallery = new ImageGallery(this);
|
||||
|
||||
// Add widgets to layout
|
||||
m_mainLayout->addWidget(m_titleLabel);
|
||||
m_mainLayout->addWidget(m_searchBar);
|
||||
m_mainLayout->addWidget(m_imageGallery, 1);
|
||||
|
||||
// Connect signals
|
||||
connect(m_searchBar, &QLineEdit::textChanged, this, &MainWindow::handleSearchTextChanged);
|
||||
}
|
||||
|
||||
void MainWindow::initializeDatabase()
|
||||
{
|
||||
// Check if database file exists
|
||||
QFileInfo dbFileInfo(DEFAULT_DB_PATH);
|
||||
if (!dbFileInfo.exists() || !dbFileInfo.isFile()) {
|
||||
QString errorMsg = tr("Database file not found: %1").arg(DEFAULT_DB_PATH);
|
||||
statusBar()->showMessage(errorMsg, 10000);
|
||||
QMessageBox::critical(this, tr("Database Error"), errorMsg);
|
||||
qDebug() << "Database file not found:" << DEFAULT_DB_PATH;
|
||||
m_hasValidDatabase = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to initialize database
|
||||
if (!m_dbManager->initialize(DEFAULT_DB_PATH)) {
|
||||
QString errorMsg = tr("Failed to connect to database");
|
||||
statusBar()->showMessage(errorMsg, 10000);
|
||||
QMessageBox::warning(this, tr("Database Error"),
|
||||
tr("Failed to connect to database: %1\nThe application will continue with limited functionality.")
|
||||
.arg(DEFAULT_DB_PATH));
|
||||
qDebug() << "Failed to initialize database";
|
||||
m_hasValidDatabase = false;
|
||||
} else {
|
||||
statusBar()->showMessage(tr("Connected to database"), 3000);
|
||||
m_imageGallery->setDatabaseManager(m_dbManager);
|
||||
m_hasValidDatabase = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::displayAllImages()
|
||||
{
|
||||
if (!m_hasValidDatabase) {
|
||||
m_imageGallery->clearGallery();
|
||||
statusBar()->showMessage(tr("No database connection available. Cannot display images."), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
QList<DatabaseManager::ImageItem> allImages = m_dbManager->getAllImages();
|
||||
if (allImages.isEmpty()) {
|
||||
statusBar()->showMessage(tr("No images found in database"), 5000);
|
||||
}
|
||||
|
||||
m_imageGallery->displayImages(allImages);
|
||||
updateStatusBar();
|
||||
}
|
||||
|
||||
void MainWindow::handleSearchTextChanged()
|
||||
{
|
||||
if (!m_hasValidDatabase) {
|
||||
statusBar()->showMessage(tr("Database not available for search"), 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Restart the timer each time the user types
|
||||
m_searchDelayTimer->start();
|
||||
|
||||
// If search bar is cleared, immediately show all images
|
||||
if (m_searchBar->text().isEmpty() && !m_lastSearchText.isEmpty()) {
|
||||
m_lastSearchText.clear();
|
||||
m_searchDelayTimer->stop();
|
||||
performSearch();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::performSearch()
|
||||
{
|
||||
if (!m_hasValidDatabase) {
|
||||
statusBar()->showMessage(tr("Cannot perform search: No database connection"), 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
QString currentText = m_searchBar->text();
|
||||
|
||||
// Only perform search if text has changed
|
||||
if (currentText != m_lastSearchText) {
|
||||
m_lastSearchText = currentText;
|
||||
|
||||
try {
|
||||
m_imageGallery->handleSearchTextChanged(currentText);
|
||||
updateStatusBar();
|
||||
} catch (const std::exception &e) {
|
||||
QString errorMsg = tr("Search error: %1").arg(e.what());
|
||||
statusBar()->showMessage(errorMsg, 5000);
|
||||
qDebug() << errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusBar()
|
||||
{
|
||||
if (!m_hasValidDatabase) {
|
||||
statusBar()->showMessage(tr("Database not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int imageCount = m_dbManager->searchImages(m_lastSearchText).count();
|
||||
int totalImages = m_dbManager->getAllImages().count();
|
||||
|
||||
if (m_lastSearchText.isEmpty()) {
|
||||
statusBar()->showMessage(tr("Displaying all %1 images").arg(totalImages));
|
||||
} else {
|
||||
statusBar()->showMessage(tr("Found %1 of %2 images matching \"%3\"")
|
||||
.arg(imageCount)
|
||||
.arg(totalImages)
|
||||
.arg(m_lastSearchText));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
statusBar()->showMessage(tr("Error updating status: %1").arg(e.what()), 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QMainWindow::resizeEvent(event);
|
||||
|
||||
// The ImageGallery widget will automatically adjust to the new size
|
||||
// because of the layout system, but you can add custom resize handling here if needed
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QStatusBar>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include "databasemanager.h"
|
||||
#include "imagegallery.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void handleSearchTextChanged();
|
||||
void performSearch();
|
||||
void updateStatusBar();
|
||||
|
||||
private:
|
||||
void createLayout();
|
||||
void initializeDatabase();
|
||||
void displayAllImages();
|
||||
|
||||
// UI Components
|
||||
QWidget *m_centralWidget;
|
||||
QVBoxLayout *m_mainLayout;
|
||||
QLineEdit *m_searchBar;
|
||||
QLabel *m_titleLabel;
|
||||
ImageGallery *m_imageGallery;
|
||||
|
||||
// Data
|
||||
DatabaseManager *m_dbManager;
|
||||
QString m_lastSearchText;
|
||||
QTimer *m_searchDelayTimer;
|
||||
bool m_hasValidDatabase;
|
||||
|
||||
// Constants
|
||||
static constexpr int SEARCH_DELAY_MS = 300; // Delay for search typing
|
||||
static constexpr int DEFAULT_WINDOW_WIDTH = 1200;
|
||||
static constexpr int DEFAULT_WINDOW_HEIGHT = 800;
|
||||
static const QString DEFAULT_DB_PATH;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
Reference in New Issue
Block a user