version 2

This commit is contained in:
master
2025-11-15 21:49:04 -05:00
parent 8c55eeffd4
commit f2cf0d7d89
28 changed files with 1315 additions and 1007 deletions
+15 -7
View File
@@ -1,14 +1,16 @@
# Screenshot OCR Gallery
A Qt6-based image gallery application that allows you to search through OCR data from your screenshots with live preview.
A Qt6-based image gallery application that allows you to search through OCR data from your screenshots with live preview and dynamic resizing.
## Features
- Fast visual navigation through your screenshot collection
- Live search through OCR text as you type
- 4×4 image gallery grid with 256px wide previews
- Ultra-responsive live search through OCR text as you type with optimized performance
- Dynamic grid layout that automatically reflows (1x, 2x, 3x, 4x, etc.) based on window width
- No horizontal scrollbars - content always fits the window width
- Filename overlay at the bottom of each image for easy identification
- Opens images in your default image viewer on click
- Responsive design that adjusts to window size
- Minimal 2px spacing between images for a compact view
- Proper error handling for missing files and database issues
## Requirements
@@ -88,9 +90,15 @@ After building, run the application:
1. When the application starts, it will display all screenshots found in the database
2. Type in the search bar to filter images by OCR text content
3. Results update as you type
4. Click on any image to open it in your default image viewer
5. Hover over an image to see the file path and a preview of its OCR text
3. Results update instantly as you type with optimized search performance
4. When you clear the search bar, all images are immediately shown
5. Resize the application window to see the grid automatically reflow:
- Wider windows show more columns (4x, 5x, etc.)
- Narrower windows reduce to fewer columns (3x, 2x)
- Very narrow windows show a single centered column (1x)
- No horizontal scrolling - content always fits the available width
6. Each image displays its filename at the bottom for easy identification
7. Click on any image to open it in your default image viewer
## Troubleshooting
@@ -288,6 +288,7 @@
/usr/include/pthread.h
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -1174,6 +1175,7 @@ CMakeFiles/screenshot-gallery.dir/screenshot-gallery_autogen/mocs_compilation.cp
/usr/include/pthread.h
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -1756,6 +1758,7 @@ CMakeFiles/screenshot-gallery.dir/src/databasemanager.cpp.o
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QFileInfo
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QString
@@ -2248,6 +2251,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QFileInfo
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -2256,6 +2260,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o
/usr/include/qt6/QtCore/QSizeF
/usr/include/qt6/QtCore/QString
/usr/include/qt6/QtCore/QThread
/usr/include/qt6/QtCore/QTimer
/usr/include/qt6/QtCore/QUrl
/usr/include/qt6/QtCore/q17memory.h
/usr/include/qt6/QtCore/q20functional.h
@@ -2386,6 +2391,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o
/usr/include/qt6/QtCore/qtextstream.h
/usr/include/qt6/QtCore/qtformat_impl.h
/usr/include/qt6/QtCore/qthread.h
/usr/include/qt6/QtCore/qtimer.h
/usr/include/qt6/QtCore/qtimezone.h
/usr/include/qt6/QtCore/qtmetamacros.h
/usr/include/qt6/QtCore/qtnoop.h
@@ -2462,7 +2468,9 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o
/usr/include/qt6/QtSql/qtsqlexports.h
/usr/include/qt6/QtSql/qtsqlglobal.h
/usr/include/qt6/QtWidgets/QApplication
/usr/include/qt6/QtWidgets/QFrame
/usr/include/qt6/QtWidgets/QGridLayout
/usr/include/qt6/QtWidgets/QHBoxLayout
/usr/include/qt6/QtWidgets/QLabel
/usr/include/qt6/QtWidgets/QPushButton
/usr/include/qt6/QtWidgets/QScrollArea
@@ -2798,6 +2806,7 @@ CMakeFiles/screenshot-gallery.dir/src/main.cpp.o
/usr/include/pthread.h
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -3380,6 +3389,7 @@ CMakeFiles/screenshot-gallery.dir/src/mainwindow.cpp.o
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QFileInfo
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -287,6 +287,7 @@ screenshot-gallery_autogen/timestamp: /home/master/screenshot-gallery/CMakeLists
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -1172,6 +1173,7 @@ CMakeFiles/screenshot-gallery.dir/screenshot-gallery_autogen/mocs_compilation.cp
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -1753,6 +1755,7 @@ CMakeFiles/screenshot-gallery.dir/src/databasemanager.cpp.o: /home/master/screen
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QFileInfo \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QString \
@@ -2244,6 +2247,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: /home/master/screensho
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QFileInfo \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -2252,6 +2256,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: /home/master/screensho
/usr/include/qt6/QtCore/QSizeF \
/usr/include/qt6/QtCore/QString \
/usr/include/qt6/QtCore/QThread \
/usr/include/qt6/QtCore/QTimer \
/usr/include/qt6/QtCore/QUrl \
/usr/include/qt6/QtCore/q17memory.h \
/usr/include/qt6/QtCore/q20functional.h \
@@ -2382,6 +2387,7 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: /home/master/screensho
/usr/include/qt6/QtCore/qtextstream.h \
/usr/include/qt6/QtCore/qtformat_impl.h \
/usr/include/qt6/QtCore/qthread.h \
/usr/include/qt6/QtCore/qtimer.h \
/usr/include/qt6/QtCore/qtimezone.h \
/usr/include/qt6/QtCore/qtmetamacros.h \
/usr/include/qt6/QtCore/qtnoop.h \
@@ -2458,7 +2464,9 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: /home/master/screensho
/usr/include/qt6/QtSql/qtsqlexports.h \
/usr/include/qt6/QtSql/qtsqlglobal.h \
/usr/include/qt6/QtWidgets/QApplication \
/usr/include/qt6/QtWidgets/QFrame \
/usr/include/qt6/QtWidgets/QGridLayout \
/usr/include/qt6/QtWidgets/QHBoxLayout \
/usr/include/qt6/QtWidgets/QLabel \
/usr/include/qt6/QtWidgets/QPushButton \
/usr/include/qt6/QtWidgets/QScrollArea \
@@ -2793,6 +2801,7 @@ CMakeFiles/screenshot-gallery.dir/src/main.cpp.o: /home/master/screenshot-galler
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -3374,6 +3383,7 @@ CMakeFiles/screenshot-gallery.dir/src/mainwindow.cpp.o: /home/master/screenshot-
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QFileInfo \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -4282,6 +4292,8 @@ CMakeFiles/screenshot-gallery.dir/src/mainwindow.cpp.o:
/usr/lib/cmake/Qt6/QtPublicAppleHelpers.cmake:
/usr/lib/cmake/Qt6/Qt6Targets.cmake:
/usr/lib/cmake/Qt6Widgets/Qt6WidgetsDependencies.cmake:
/usr/include/c++/15.2.1/variant:
@@ -4522,6 +4534,8 @@ CMakeFiles/screenshot-gallery.dir/screenshot-gallery_autogen/mocs_compilation.cp
/usr/include/c++/15.2.1/bits/std_function.h:
/usr/include/qt6/QtCore/QMap:
/usr/include/c++/15.2.1/typeinfo:
/usr/include/c++/15.2.1/bits/specfun.h:
@@ -5094,6 +5108,8 @@ screenshot-gallery_autogen/UVLADIE3JM/moc_imagegallery.cpp:
/usr/include/c++/15.2.1/algorithm:
/usr/include/qt6/QtWidgets/QFrame:
/usr/include/c++/15.2.1/backward/auto_ptr.h:
/usr/include/c++/15.2.1/bits/basic_ios.h:
@@ -5278,6 +5294,8 @@ CMakeFiles/4.1.2/CMakeCXXCompiler.cmake:
/usr/include/qt6/QtCore/q20utility.h:
/usr/include/qt6/QtWidgets/QHBoxLayout:
/usr/include/qt6/QtCore/qabstracteventdispatcher.h:
/usr/lib/cmake/Qt6Gui/Qt6QEglFSKmsGbmIntegrationPluginConfig.cmake:
@@ -5330,8 +5348,6 @@ CMakeFiles/4.1.2/CMakeCXXCompiler.cmake:
/usr/include/qt6/QtCore/qbytearrayview.h:
/usr/lib/cmake/Qt6/Qt6Targets.cmake:
/usr/include/c++/15.2.1/bits/uses_allocator_args.h:
/usr/include/qt6/QtCore/qchar.h:
@@ -339,8 +339,8 @@ CMakeFiles/screenshot-gallery.dir/screenshot-gallery_autogen/mocs_compilation.cp
/usr/include/c++/15.2.1/bits/unique_lock.h \
/usr/include/c++/15.2.1/condition_variable \
/usr/include/c++/15.2.1/bits/atomic_futex.h \
/usr/include/c++/15.2.1/bits/std_thread.h \
/usr/include/qt6/QtCore/qtmochelpers.h \
/usr/include/c++/15.2.1/bits/std_thread.h /usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/qmap.h /usr/include/qt6/QtCore/qtmochelpers.h \
/usr/include/qt6/QtCore/qtmocconstants.h \
/usr/include/qt6/QtCore/q20algorithm.h \
/usr/include/qt6/QtCore/q23type_traits.h \
@@ -338,10 +338,11 @@ CMakeFiles/screenshot-gallery.dir/src/databasemanager.cpp.o: \
/usr/include/c++/15.2.1/bits/unique_lock.h \
/usr/include/c++/15.2.1/condition_variable \
/usr/include/c++/15.2.1/bits/atomic_futex.h \
/usr/include/c++/15.2.1/bits/std_thread.h \
/usr/include/qt6/QtCore/QVariant /usr/include/qt6/QtCore/qvariant.h \
/usr/include/qt6/QtCore/QFileInfo /usr/include/qt6/QtCore/qfileinfo.h \
/usr/include/qt6/QtCore/qfile.h /usr/include/qt6/QtCore/qfiledevice.h \
/usr/include/c++/15.2.1/bits/std_thread.h /usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/qmap.h /usr/include/qt6/QtCore/QVariant \
/usr/include/qt6/QtCore/qvariant.h /usr/include/qt6/QtCore/QFileInfo \
/usr/include/qt6/QtCore/qfileinfo.h /usr/include/qt6/QtCore/qfile.h \
/usr/include/qt6/QtCore/qfiledevice.h \
/usr/include/qt6/QtCore/qiodevice.h /usr/include/qt6/QtCore/qspan.h \
/usr/include/c++/15.2.1/cassert /usr/include/qt6/QtCore/q20iterator.h \
/usr/include/c++/15.2.1/filesystem /usr/include/c++/15.2.1/bits/fs_fwd.h \
@@ -402,11 +402,11 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: \
/usr/include/c++/15.2.1/bits/unique_lock.h \
/usr/include/c++/15.2.1/condition_variable \
/usr/include/c++/15.2.1/bits/atomic_futex.h \
/usr/include/c++/15.2.1/bits/std_thread.h \
/usr/include/qt6/QtGui/QMouseEvent /usr/include/qt6/QtCore/QFileInfo \
/usr/include/qt6/QtCore/qfileinfo.h /usr/include/qt6/QtCore/qfile.h \
/usr/include/qt6/QtCore/qfiledevice.h /usr/include/c++/15.2.1/filesystem \
/usr/include/c++/15.2.1/bits/fs_fwd.h \
/usr/include/c++/15.2.1/bits/std_thread.h /usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/qmap.h /usr/include/qt6/QtGui/QMouseEvent \
/usr/include/qt6/QtCore/QFileInfo /usr/include/qt6/QtCore/qfileinfo.h \
/usr/include/qt6/QtCore/qfile.h /usr/include/qt6/QtCore/qfiledevice.h \
/usr/include/c++/15.2.1/filesystem /usr/include/c++/15.2.1/bits/fs_fwd.h \
/usr/include/c++/15.2.1/bits/fs_path.h /usr/include/c++/15.2.1/locale \
/usr/include/c++/15.2.1/bits/locale_facets.h \
/usr/include/c++/15.2.1/cwctype /usr/include/wctype.h \
@@ -438,4 +438,8 @@ CMakeFiles/screenshot-gallery.dir/src/imagegallery.cpp.o: \
/usr/include/qt6/QtCore/qurl.h /usr/include/qt6/QtGui/QPainter \
/usr/include/qt6/QtGui/qpainter.h /usr/include/qt6/QtGui/qtextoption.h \
/usr/include/qt6/QtGui/qpen.h /usr/include/qt6/QtWidgets/QApplication \
/usr/include/qt6/QtWidgets/qapplication.h
/usr/include/qt6/QtWidgets/qapplication.h \
/usr/include/qt6/QtWidgets/QFrame /usr/include/qt6/QtWidgets/qframe.h \
/usr/include/qt6/QtWidgets/QHBoxLayout \
/usr/include/qt6/QtWidgets/qboxlayout.h /usr/include/qt6/QtCore/QTimer \
/usr/include/qt6/QtCore/qtimer.h
@@ -395,7 +395,8 @@ CMakeFiles/screenshot-gallery.dir/src/main.cpp.o: \
/usr/include/c++/15.2.1/bits/unique_lock.h \
/usr/include/c++/15.2.1/condition_variable \
/usr/include/c++/15.2.1/bits/atomic_futex.h \
/usr/include/c++/15.2.1/bits/std_thread.h \
/usr/include/c++/15.2.1/bits/std_thread.h /usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/qmap.h \
/home/master/screenshot-gallery/src/imagegallery.h \
/usr/include/qt6/QtWidgets/QWidget /usr/include/qt6/QtWidgets/qwidget.h \
/usr/include/qt6/QtWidgets/QGridLayout \
@@ -386,7 +386,8 @@ CMakeFiles/screenshot-gallery.dir/src/mainwindow.cpp.o: \
/usr/include/c++/15.2.1/bits/unique_lock.h \
/usr/include/c++/15.2.1/condition_variable \
/usr/include/c++/15.2.1/bits/atomic_futex.h \
/usr/include/c++/15.2.1/bits/std_thread.h \
/usr/include/c++/15.2.1/bits/std_thread.h /usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/qmap.h \
/home/master/screenshot-gallery/src/imagegallery.h \
/usr/include/qt6/QtWidgets/QWidget /usr/include/qt6/QtWidgets/qwidget.h \
/usr/include/qt6/QtWidgets/QGridLayout \
File diff suppressed because it is too large Load Diff
@@ -288,6 +288,7 @@
/usr/include/pthread.h
/usr/include/qt6/QtCore/QDebug
/usr/include/qt6/QtCore/QList
/usr/include/qt6/QtCore/QMap
/usr/include/qt6/QtCore/QObject
/usr/include/qt6/QtCore/QPair
/usr/include/qt6/QtCore/QProcess
@@ -287,6 +287,7 @@ screenshot-gallery_autogen/timestamp: /home/master/screenshot-gallery/CMakeLists
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -1279,6 +1280,8 @@ screenshot-gallery_autogen/timestamp: /home/master/screenshot-gallery/CMakeLists
/usr/lib/cmake/Qt6/QtPublicAppleHelpers.cmake:
/usr/lib/cmake/Qt6/Qt6Targets.cmake:
/usr/lib/cmake/Qt6Widgets/Qt6WidgetsDependencies.cmake:
/usr/include/c++/15.2.1/variant:
@@ -1495,6 +1498,8 @@ screenshot-gallery_autogen/timestamp: /home/master/screenshot-gallery/CMakeLists
/usr/include/c++/15.2.1/bits/std_function.h:
/usr/include/qt6/QtCore/QMap:
/usr/include/c++/15.2.1/typeinfo:
/usr/include/c++/15.2.1/bits/specfun.h:
@@ -2243,8 +2248,6 @@ CMakeFiles/4.1.2/CMakeCXXCompiler.cmake:
/usr/include/qt6/QtCore/qbytearrayview.h:
/usr/lib/cmake/Qt6/Qt6Targets.cmake:
/usr/include/c++/15.2.1/bits/uses_allocator_args.h:
/usr/include/qt6/QtCore/qchar.h:
Binary file not shown.
@@ -273,6 +273,7 @@
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QString \
@@ -132,7 +132,9 @@ template <> constexpr inline auto ImageGallery::qt_create_metaobjectdata<qt_meta
"",
"searchText",
"handleThumbnailClicked",
"filePath"
"filePath",
"handleContainerResized",
"updateGridLayout"
};
QtMocHelpers::UintData qt_methods {
@@ -144,6 +146,10 @@ template <> constexpr inline auto ImageGallery::qt_create_metaobjectdata<qt_meta
QtMocHelpers::SlotData<void(const QString &)>(4, 2, QMC::AccessPublic, QMetaType::Void, {{
{ QMetaType::QString, 5 },
}}),
// Slot 'handleContainerResized'
QtMocHelpers::SlotData<void()>(6, 2, QMC::AccessPublic, QMetaType::Void),
// Slot 'updateGridLayout'
QtMocHelpers::SlotData<void()>(7, 2, QMC::AccessPublic, QMetaType::Void),
};
QtMocHelpers::UintData qt_properties {
};
@@ -169,6 +175,8 @@ void ImageGallery::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id
switch (_id) {
case 0: _t->handleSearchTextChanged((*reinterpret_cast<std::add_pointer_t<QString>>(_a[1]))); break;
case 1: _t->handleThumbnailClicked((*reinterpret_cast<std::add_pointer_t<QString>>(_a[1]))); break;
case 2: _t->handleContainerResized(); break;
case 3: _t->updateGridLayout(); break;
default: ;
}
}
@@ -193,14 +201,14 @@ int ImageGallery::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 2)
if (_id < 4)
qt_static_metacall(this, _c, _id, _a);
_id -= 2;
_id -= 4;
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 2)
if (_id < 4)
*reinterpret_cast<QMetaType *>(_a[0]) = QMetaType();
_id -= 2;
_id -= 4;
}
return _id;
}
@@ -275,6 +275,7 @@
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
@@ -276,6 +276,7 @@
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
+1
View File
@@ -284,6 +284,7 @@ screenshot-gallery_autogen/timestamp: \
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QDebug \
/usr/include/qt6/QtCore/QList \
/usr/include/qt6/QtCore/QMap \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QPair \
/usr/include/qt6/QtCore/QProcess \
+57 -7
View File
@@ -9,6 +9,11 @@ DatabaseManager::DatabaseManager(QObject *parent)
: QObject(parent)
, m_initialized(false)
{
// Initialize search cache
m_searchCache.clear();
// Create index on ocr_text if it doesn't exist
// This will be executed once the database is initialized
}
DatabaseManager::~DatabaseManager()
@@ -78,6 +83,10 @@ bool DatabaseManager::initialize(const QString &dbPath)
return false;
}
// Create an index on the ocr_text column if it doesn't exist
// This will speed up text searches dramatically
query.exec("CREATE INDEX IF NOT EXISTS idx_ocr_text ON ocr_results(ocr_text)");
m_initialized = true;
qDebug() << "Database initialized successfully.";
return true;
@@ -99,6 +108,9 @@ QList<DatabaseManager::ImageItem> DatabaseManager::getAllImages()
return images;
}
// Start transaction to speed up query
m_db.transaction();
QSqlQuery query;
query.prepare("SELECT full_path, ocr_text FROM ocr_results");
@@ -108,6 +120,9 @@ QList<DatabaseManager::ImageItem> DatabaseManager::getAllImages()
}
// Check if files exist as we add them
// Reserve space for results to avoid reallocations
images.reserve(query.size() > 0 ? query.size() : 100);
while (query.next()) {
ImageItem item;
item.filePath = query.value(0).toString();
@@ -119,6 +134,7 @@ QList<DatabaseManager::ImageItem> DatabaseManager::getAllImages()
}
}
m_db.commit();
return images;
}
@@ -140,24 +156,43 @@ QList<DatabaseManager::ImageItem> DatabaseManager::searchImages(const QString &s
// If search text is empty, return all images
if (searchText.isEmpty()) {
// Clear the search cache when empty search is performed
m_searchCache.clear();
return getAllImages();
}
// Check if we have a cached result for this search query
if (m_searchCache.contains(searchText)) {
return m_searchCache[searchText];
}
// Start transaction to speed up queries
m_db.transaction();
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 + "%");
// Optimize the query based on length of search text
if (searchText.length() <= 3) {
// For short search terms, use a more targeted approach
query.prepare("SELECT full_path, ocr_text FROM ocr_results WHERE ocr_text LIKE :search");
query.bindValue(":search", "%" + searchText + "%");
} else {
// For longer search terms, use LIKE with a more specific pattern at start
// which can utilize indexes better if they exist
query.prepare("SELECT full_path, ocr_text FROM ocr_results WHERE ocr_text LIKE :search OR ocr_text LIKE :wordstart");
query.bindValue(":search", "%" + searchText + "%");
query.bindValue(":wordstart", "% " + searchText + "%");
}
if (!query.exec()) {
qDebug() << "Failed to search images:" << query.lastError().text();
m_db.rollback();
return images;
}
// Reserve space for results to avoid reallocations
images.reserve(query.size() > 0 ? query.size() : 100);
while (query.next()) {
ImageItem item;
item.filePath = query.value(0).toString();
@@ -169,5 +204,20 @@ QList<DatabaseManager::ImageItem> DatabaseManager::searchImages(const QString &s
}
}
m_db.commit();
// Cache the result for future queries
if (images.size() > 0) {
m_searchCache.insert(searchText, images);
// Limit cache size to avoid memory issues
if (m_searchCache.size() > MAX_CACHE_SIZE) {
// Remove the first key (oldest entry)
if (!m_searchCache.isEmpty()) {
m_searchCache.remove(m_searchCache.firstKey());
}
}
}
return images;
}
+7
View File
@@ -10,6 +10,7 @@
#include <QList>
#include <QPair>
#include <QThread>
#include <QMap>
/**
* @brief The DatabaseManager class handles all database operations
@@ -63,6 +64,12 @@ public slots:
private:
QSqlDatabase m_db;
bool m_initialized;
// Cache for search results to improve response time
QMap<QString, QList<ImageItem>> m_searchCache;
// Maximum number of cached search queries
static const int MAX_CACHE_SIZE = 50;
};
#endif // DATABASEMANAGER_H
+182 -16
View File
@@ -6,6 +6,9 @@
#include <QUrl>
#include <QPainter>
#include <QApplication>
#include <QFrame>
#include <QHBoxLayout>
#include <QTimer>
// ImageThumbnail implementation
ImageThumbnail::ImageThumbnail(const QString &filePath, QWidget *parent)
@@ -18,7 +21,7 @@ ImageThumbnail::ImageThumbnail(const QString &filePath, QWidget *parent)
setLineWidth(2);
setScaledContents(false);
setCursor(Qt::PointingHandCursor);
setToolTip(filePath);
// We're removing tooltips as requested
// Enable text wrapping and text interaction
setWordWrap(true);
@@ -44,13 +47,22 @@ ImageGallery::ImageGallery(QWidget *parent)
// Create scroll area
m_scrollArea = new QScrollArea(this);
m_scrollArea->setWidgetResizable(true);
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Prevent horizontal scrollbar
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
// Create container widget for the grid layout
m_containerWidget = new QWidget(m_scrollArea);
// Make container expand to fill the available width
m_containerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
// Create grid layout with minimal spacing
m_gridLayout = new QGridLayout(m_containerWidget);
m_gridLayout->setSpacing(10);
m_gridLayout->setSpacing(THUMBNAIL_SPACING);
m_gridLayout->setContentsMargins(THUMBNAIL_SPACING, THUMBNAIL_SPACING, THUMBNAIL_SPACING, THUMBNAIL_SPACING);
// Initialize column count based on container width
m_columnsCount = 4; // Default value, will be updated in updateGridLayout
m_scrollArea->setWidget(m_containerWidget);
@@ -58,6 +70,19 @@ ImageGallery::ImageGallery(QWidget *parent)
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(m_scrollArea);
setLayout(mainLayout);
// No need to connect to container widget - we'll use resizeEvent instead
// Initial layout update
QTimer::singleShot(0, this, &ImageGallery::updateGridLayout);
// Install event filter on viewport to catch resize events
m_scrollArea->viewport()->installEventFilter(this);
// We'll still keep a periodic check as backup
QTimer *resizeTimer = new QTimer(this);
connect(resizeTimer, &QTimer::timeout, this, &ImageGallery::handleContainerResized);
resizeTimer->start(300); // Check every 300ms
}
ImageGallery::~ImageGallery()
@@ -75,6 +100,9 @@ void ImageGallery::displayImages(const QList<DatabaseManager::ImageItem> &images
// Clear existing thumbnails
clearGallery();
// Update grid layout to ensure correct column count before adding images
updateGridLayout();
const int numImages = images.size();
int row = 0, col = 0;
@@ -93,17 +121,29 @@ void ImageGallery::displayImages(const QList<DatabaseManager::ImageItem> &images
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);
// Add filename overlay at the bottom of the thumbnail
QFileInfo fileNameInfo(item.filePath);
QString fileName = fileNameInfo.fileName();
// Create overlay container with dark background
QFrame* overlay = new QFrame(thumbnailLabel);
overlay->setStyleSheet("background-color: rgba(0, 0, 0, 0.7);");
overlay->setFixedHeight(20);
overlay->setFixedWidth(THUMBNAIL_WIDTH);
// Create label for the filename
QLabel* fileNameLabel = new QLabel(fileName, overlay);
fileNameLabel->setStyleSheet("color: white; background: transparent;");
fileNameLabel->setAlignment(Qt::AlignCenter);
fileNameLabel->setFixedWidth(THUMBNAIL_WIDTH - 10);
// Layout for the overlay
QHBoxLayout* overlayLayout = new QHBoxLayout(overlay);
overlayLayout->setContentsMargins(5, 0, 5, 0);
overlayLayout->addWidget(fileNameLabel);
// Position the overlay at the bottom of the thumbnail
overlay->move(0, THUMBNAIL_HEIGHT - overlay->height());
// Connect the thumbnail click signal
connect(thumbnailLabel, &ImageThumbnail::thumbnailClicked,
@@ -115,7 +155,7 @@ void ImageGallery::displayImages(const QList<DatabaseManager::ImageItem> &images
// Update row and column
col++;
if (col >= COLUMNS) {
if (col >= m_columnsCount) {
col = 0;
row++;
}
@@ -127,7 +167,7 @@ void ImageGallery::displayImages(const QList<DatabaseManager::ImageItem> &images
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_gridLayout->addWidget(noImagesLabel, 0, 0, 1, m_columnsCount);
m_thumbnails.append(noImagesLabel);
}
@@ -202,6 +242,132 @@ QPixmap ImageGallery::createThumbnail(const QString &filePath, int width, int he
return pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
void ImageGallery::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
// Trigger grid layout update when gallery is resized
QTimer::singleShot(0, this, &ImageGallery::updateGridLayout);
// Ensure the container widget fills the viewport width
if (m_scrollArea && m_containerWidget) {
int viewportWidth = m_scrollArea->viewport()->width();
m_containerWidget->setMinimumWidth(viewportWidth);
// Immediately update layout to avoid visual glitches during resize
m_gridLayout->activate();
m_containerWidget->updateGeometry();
}
}
// Event filter to catch viewport resize events
bool ImageGallery::eventFilter(QObject *watched, QEvent *event)
{
// Check if this is a resize event on the viewport
if (watched == m_scrollArea->viewport() && event->type() == QEvent::Resize) {
// Update the grid layout
updateGridLayout();
return false; // Allow event to propagate
}
// Pass unhandled events to parent
return QWidget::eventFilter(watched, event);
}
void ImageGallery::handleContainerResized()
{
// This will be called periodically to check if container size changed
static int lastWidth = -1;
int currentWidth = m_containerWidget->width();
if (currentWidth > 0 && currentWidth != lastWidth) {
lastWidth = currentWidth;
updateGridLayout();
}
}
void ImageGallery::updateGridLayout()
{
// Get the viewport width to determine available space
int viewportWidth = m_scrollArea->viewport()->width();
if (viewportWidth <= 0) {
return; // Can't determine width yet
}
// Force container width to match the viewport
m_containerWidget->setMinimumWidth(viewportWidth);
// Account for left and right margins in the grid layout
int availableWidth = viewportWidth - (m_gridLayout->contentsMargins().left() + m_gridLayout->contentsMargins().right());
// Calculate how many thumbnails can fit, accounting for spacing between them
int effectiveThumbnailWidth = THUMBNAIL_WIDTH + THUMBNAIL_SPACING;
// Calculate column count, allowing even very narrow views to show at least 1 column
int newColumnCount = std::max(1, availableWidth / (THUMBNAIL_WIDTH + 2 * THUMBNAIL_SPACING));
// Only update if column count changes
if (newColumnCount != m_columnsCount) {
m_columnsCount = newColumnCount;
// If we have thumbnails, rearrange them in the grid
if (!m_thumbnails.isEmpty()) {
// We need to readjust all the thumbnails to the new grid layout
// First remove all widgets from the grid
for (auto thumbnail : m_thumbnails) {
m_gridLayout->removeWidget(thumbnail);
}
// Then add them back in the new arrangement
int row = 0, col = 0;
for (auto thumbnail : m_thumbnails) {
m_gridLayout->addWidget(thumbnail, row, col);
col++;
if (col >= m_columnsCount) {
col = 0;
row++;
}
}
// Force layout update
m_gridLayout->invalidate();
m_containerWidget->adjustSize();
m_containerWidget->updateGeometry();
// Handle single column mode specially
if (m_columnsCount == 1) {
// Center the thumbnails in the viewport
int centeringMargin = (viewportWidth - THUMBNAIL_WIDTH) / 2;
centeringMargin = std::max(THUMBNAIL_SPACING, centeringMargin);
m_gridLayout->setContentsMargins(centeringMargin, THUMBNAIL_SPACING, centeringMargin, THUMBNAIL_SPACING);
// Let all thumbnails expand to fill available width in single column mode
for (auto thumbnail : m_thumbnails) {
thumbnail->setMaximumWidth(THUMBNAIL_WIDTH);
thumbnail->setAlignment(Qt::AlignCenter);
}
} else {
// For multi-column, use minimal margins
m_gridLayout->setContentsMargins(THUMBNAIL_SPACING, THUMBNAIL_SPACING, THUMBNAIL_SPACING, THUMBNAIL_SPACING);
// Reset thumbnail constraints
for (auto thumbnail : m_thumbnails) {
thumbnail->setMaximumWidth(QWIDGETSIZE_MAX);
}
// For multi-column, let the container fill the viewport
m_containerWidget->setMinimumWidth(viewportWidth);
}
// Update the layout again after a short delay to handle edge cases
QTimer::singleShot(10, this, [this](){
m_gridLayout->update();
m_containerWidget->update();
});
}
}
}
QPixmap ImageGallery::createPlaceholderThumbnail(int width, int height, const QString &message)
{
// Create a placeholder image with text
+8 -1
View File
@@ -14,9 +14,9 @@
#include "databasemanager.h"
// Global constants
static const int COLUMNS = 4;
static const int THUMBNAIL_WIDTH = 256;
static const int THUMBNAIL_HEIGHT = 256;
static const int THUMBNAIL_SPACING = 2; // Reduced spacing between thumbnails
class ImageThumbnail : public QLabel
{
@@ -52,6 +52,12 @@ public:
public slots:
void handleSearchTextChanged(const QString &searchText);
void handleThumbnailClicked(const QString &filePath);
void handleContainerResized(); // New slot to handle resize events
void updateGridLayout(); // Adjusts grid based on current window size
protected:
void resizeEvent(QResizeEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
private:
QGridLayout *m_gridLayout;
@@ -59,6 +65,7 @@ private:
QWidget *m_containerWidget;
DatabaseManager *m_dbManager;
QList<ImageThumbnail*> m_thumbnails;
int m_columnsCount; // Dynamic column count based on window size
QPixmap createThumbnail(const QString &filePath, int width, int height);
QPixmap createPlaceholderThumbnail(int width, int height, const QString &message);
+25 -7
View File
@@ -19,6 +19,9 @@ MainWindow::MainWindow(QWidget *parent)
setWindowTitle(tr("Screenshot OCR Gallery"));
resize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
// Remove fixed minimum size to allow for single column layout at any width
// setMinimumSize(640, 480);
// Center window on screen
QScreen *screen = QGuiApplication::primaryScreen();
if (screen) {
@@ -61,6 +64,8 @@ void MainWindow::createLayout()
// Create main layout
m_mainLayout = new QVBoxLayout(m_centralWidget);
m_mainLayout->setSpacing(5); // Reduce spacing between elements
m_mainLayout->setContentsMargins(5, 5, 5, 5); // Reduce margins
// Create title label
m_titleLabel = new QLabel(tr("Screenshot OCR Gallery"), this);
@@ -77,6 +82,7 @@ void MainWindow::createLayout()
// Create gallery widget
m_imageGallery = new ImageGallery(this);
m_imageGallery->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Add widgets to layout
m_mainLayout->addWidget(m_titleLabel);
@@ -140,15 +146,16 @@ void MainWindow::handleSearchTextChanged()
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()) {
if (m_searchBar->text().isEmpty()) {
m_lastSearchText.clear();
m_searchDelayTimer->stop();
performSearch();
displayAllImages(); // Show all images immediately
return; // Skip the timer since we've already updated
}
// For non-empty searches, restart the timer each time the user types
m_searchDelayTimer->start();
}
void MainWindow::performSearch()
@@ -203,6 +210,17 @@ 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
// Notify the image gallery of the resize event
if (m_imageGallery) {
// The gallery will handle its own layout updates through its resize event
// Just make sure it's visible and has the correct size policy
m_imageGallery->setVisible(true);
}
// Update status bar to show current window dimensions
// This helps with debugging layout issues
if (statusBar() && statusBar()->isVisible()) {
QString sizeInfo = QString("Window size: %1×%2").arg(width()).arg(height());
statusBar()->showMessage(sizeInfo, 1000);
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ private:
bool m_hasValidDatabase;
// Constants
static constexpr int SEARCH_DELAY_MS = 300; // Delay for search typing
static constexpr int SEARCH_DELAY_MS = 50; // Reduced delay for more responsive typing
static constexpr int DEFAULT_WINDOW_WIDTH = 1200;
static constexpr int DEFAULT_WINDOW_HEIGHT = 800;
static const QString DEFAULT_DB_PATH;