From 7ff0f8b71a4293214d3afbe61576e0c0b5ff5821 Mon Sep 17 00:00:00 2001 From: Crylia Date: Wed, 3 Jul 2024 17:41:33 +0200 Subject: [PATCH] Fix startup, and quitting, fixed squishing, added hover and double clicking, added back button --- .../FileController/FileController.cpp | 28 +++--- .../FileController/FileController.hpp | 6 ++ src/Core/FileMonitor/FileMonitor.cpp | 9 +- src/Core/FileMonitor/FileMonitor.hpp | 11 ++- src/View/GridItemView/GridItemView.cpp | 32 +++++-- src/View/GridItemView/GridItemView.hpp | 2 + src/View/MainWidget/MainWidget.cpp | 21 ++++- src/View/MainWidget/MainWidget.hpp | 1 + src/View/Path/Path.cpp | 4 +- src/View/Widgets/GridItem/GridItem.cpp | 94 ++++++++++++++++--- src/View/Widgets/GridItem/GridItem.hpp | 8 +- src/main.cpp | 9 +- 12 files changed, 164 insertions(+), 61 deletions(-) diff --git a/src/Controller/FileController/FileController.cpp b/src/Controller/FileController/FileController.cpp index 4356b1d..7f6a1a6 100644 --- a/src/Controller/FileController/FileController.cpp +++ b/src/Controller/FileController/FileController.cpp @@ -6,32 +6,35 @@ #include FileController::FileController( ) { -#ifdef _WIN32 m_fmWorker = std::make_shared( - std::filesystem::path(std::getenv("USERPROFILE")), std::chrono::milliseconds(1000)); -#else - m_fmWorker = std::make_shared( - std::filesystem::path(std::getenv("HOME")), - std::chrono::milliseconds(1000)); -#endif - m_fmWorker->moveToThread(&m_fsThread); + // starts the directory monitoring thread, forgot why it has to be a signal, only works this way not with a direct call connect(this, &FileController::operate, m_fmWorker.get( ), &FileMonitor::start); + // main signal to populate the file grid, passes the path and event each time a file is deleted, created or updated connect(m_fmWorker.get( ), &FileMonitor::changed, this, &FileController::update); + // Propagating signal from the monitor that fires when the path is changed connect(m_fmWorker.get( ), &FileMonitor::pathChanged, this, &FileController::newPath); - - //Why this no workie - //connect(this, &FileController::updatePath, m_fmWorker.get( ), &FileMonitor::SetPath); +#ifdef _WIN32 + m_fmWorker.get( )->SetPath(std::filesystem::path(std::getenv("USERPROFILE"))); +#else + m_fmWorker.get( )->SetPath(std::filesystem::path(std::getenv("HOME"))); +#endif + // Signal to update the path, when fired passes the new path and will be given to the monitor connect(this, &FileController::updatePath, this, [this](std::filesystem::path p) { + previousPaths.push(m_fmWorker.get( )->GetPath( )); m_fmWorker.get( )->SetPath(p); }); + connect(this, &FileController::previousPath, this, [this]( ) { + if (previousPaths.empty( )) return; - + m_fmWorker.get( )->SetPath(previousPaths.top( )); + previousPaths.pop( ); + }); m_fsThread.start( ); emit operate( ); @@ -39,6 +42,7 @@ FileController::FileController( ) { FileController::~FileController( ) { m_fsThread.quit( ); + m_fmWorker.get( )->stop( ); m_fsThread.wait( ); } diff --git a/src/Controller/FileController/FileController.hpp b/src/Controller/FileController/FileController.hpp index 7b27a4a..ae46bbc 100644 --- a/src/Controller/FileController/FileController.hpp +++ b/src/Controller/FileController/FileController.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include + #include "../../Core/FileMonitor/FileMonitor.hpp" class FileController : public QObject { @@ -19,6 +22,8 @@ public: FileController(const FileController&) = delete; FileController& operator=(const FileController&) = delete; + std::stack previousPaths; + private: // Private constructor to prevent instantiation FileController( ); @@ -42,4 +47,5 @@ signals: void pathChanged(const std::filesystem::path p); void contentChanged(std::filesystem::path path, FileEvent event); + void previousPath( ); }; diff --git a/src/Core/FileMonitor/FileMonitor.cpp b/src/Core/FileMonitor/FileMonitor.cpp index b01bb6d..0deda93 100644 --- a/src/Core/FileMonitor/FileMonitor.cpp +++ b/src/Core/FileMonitor/FileMonitor.cpp @@ -3,22 +3,17 @@ #include #include -FileMonitor::FileMonitor(std::filesystem::path path, - std::chrono::duration delay) - : m_path(path), m_delay(delay) { } +FileMonitor::FileMonitor(std::chrono::duration delay) + : m_delay(delay) { } void FileMonitor::SetPath(std::filesystem::path newPath) { m_path = newPath; - std::cout << m_path.string( ) << std::endl; emit pathChanged(m_path); initPathsMap( ); } void FileMonitor::initPathsMap( ) { m_paths.clear( ); - /* for (auto& file : std::filesystem::directory_iterator(m_path)) { - m_paths[file.path( )] = std::filesystem::last_write_time(file); - } */ } bool FileMonitor::is_hidden(const std::filesystem::path& p) { diff --git a/src/Core/FileMonitor/FileMonitor.hpp b/src/Core/FileMonitor/FileMonitor.hpp index d01b86c..2018294 100644 --- a/src/Core/FileMonitor/FileMonitor.hpp +++ b/src/Core/FileMonitor/FileMonitor.hpp @@ -18,20 +18,23 @@ class FileMonitor : public QObject { public: std::chrono::duration m_delay; - FileMonitor(std::filesystem::path path, - std::chrono::duration delay); + FileMonitor(std::chrono::duration delay); ~FileMonitor( ) = default; void SetPath(std::filesystem::path path); + std::filesystem::path GetPath( ) { + return m_path; + } + + void stop( ); public slots: void start( ); - void stop( ); private: std::unordered_map m_paths; - bool m_running; + bool m_running = true; std::filesystem::path m_path; bool contains(const std::filesystem::path& key); diff --git a/src/View/GridItemView/GridItemView.cpp b/src/View/GridItemView/GridItemView.cpp index 92c23c8..cb7386b 100644 --- a/src/View/GridItemView/GridItemView.cpp +++ b/src/View/GridItemView/GridItemView.cpp @@ -4,45 +4,57 @@ GridItemView::GridItemView(QWidget* parent) : QFrame(parent), fileController(FileController::instance( )) { - QGridLayout* mainLayout = new QGridLayout( ); + QVBoxLayout* mainLayout = new QVBoxLayout(this); + QGridLayout* gridLayout = new QGridLayout( ); - this->setLayout(mainLayout); + gridLayout->setAlignment(Qt::AlignTop); + + mainLayout->addLayout(gridLayout); + setLayout(mainLayout); connect(fileController, &FileController::pathChanged, this, - [this, mainLayout](const std::filesystem::path path) { + [this, gridLayout](const std::filesystem::path path) { // No, QT Does not offer a better way to clear a layout, at least this solution doesnt segfault QLayoutItem* wItem; - while ((wItem = mainLayout->takeAt(0)) != 0) { + while ((wItem = gridLayout->takeAt(0)) != 0) { if (wItem->widget( )) wItem->widget( )->setParent(nullptr); delete wItem; } + gridMap.clear( ); }); - connect(fileController, &FileController::contentChanged, this, [this, mainLayout](std::filesystem::path path, FileEvent event) { + connect(fileController, &FileController::contentChanged, this, [this, gridLayout](std::filesystem::path path, FileEvent event) { if (event == FileEvent::created) { auto w = new GridItem(path); gridMap[path] = w; - connect(w, &GridItem::clicked, this, [this, path]( ) { + connect(w, &GridItem::doubleClicked, this, [this, path]( ) { if (!std::filesystem::is_directory(path)) return; emit fileController->updatePath(path); }); + connect(w, &GridItem::clicked, this, [this, path]( ) { + if (std::filesystem::is_directory(path)) + return; + + std::string cmd = "xdg-open \"" + path.string( ) + "\""; + std::system(cmd.c_str( )); + }); int pos = gridMap.size( ) - 1; - mainLayout->addWidget(w, pos / 8, pos % 8); + gridLayout->addWidget(w, pos / 8, pos % 8); w->show( ); } else if (event == FileEvent::erased) { - mainLayout->removeWidget(gridMap[path]); + gridLayout->removeWidget(gridMap[path]); delete gridMap[path]; gridMap.erase(path); int pos = 0; for (const auto& [key, widget] : gridMap) { - mainLayout->addWidget(widget, pos / 8, pos % 8); + gridLayout->addWidget(widget, pos / 8, pos % 8); pos++; } } else if (event == FileEvent::modified) { - std::cout << "modified" << std::endl; + // Idk what this would be used for } }); diff --git a/src/View/GridItemView/GridItemView.hpp b/src/View/GridItemView/GridItemView.hpp index 21219d6..a7ae72b 100644 --- a/src/View/GridItemView/GridItemView.hpp +++ b/src/View/GridItemView/GridItemView.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include "../Widgets/GridItem/GridItem.hpp" #include "../../Controller/FileController/FileController.hpp" diff --git a/src/View/MainWidget/MainWidget.cpp b/src/View/MainWidget/MainWidget.cpp index f19d3c7..4dbc6c5 100644 --- a/src/View/MainWidget/MainWidget.cpp +++ b/src/View/MainWidget/MainWidget.cpp @@ -1,16 +1,29 @@ #include "MainWidget.hpp" +#include MainWidget::MainWidget(QWidget* parent) { auto path_mainContentLayout = new QVBoxLayout(this); - auto fileTree_fileGridLayout = new QHBoxLayout(this); + auto fileTree_fileGridLayout = new QHBoxLayout( ); + auto gridLayout = new GridItemView( ); + + auto path = new Path( ); + auto backButton = new QPushButton("<"); + backButton->setFixedSize(40, 40); + auto pathBackLayout = new QHBoxLayout( ); + pathBackLayout->addWidget(backButton); + pathBackLayout->addWidget(path); + + + auto fileController = FileController::instance( ); + connect(backButton, &QPushButton::clicked, this, [fileController]( ) { + emit fileController->previousPath( ); + }); - auto gridLayout = new GridItemView(this); - auto path = new Path(this); fileTree_fileGridLayout->addWidget(gridLayout); - path_mainContentLayout->addWidget(path); + path_mainContentLayout->addLayout(pathBackLayout); path_mainContentLayout->addLayout(fileTree_fileGridLayout); setLayout(path_mainContentLayout); diff --git a/src/View/MainWidget/MainWidget.hpp b/src/View/MainWidget/MainWidget.hpp index 9551fa6..63fa285 100644 --- a/src/View/MainWidget/MainWidget.hpp +++ b/src/View/MainWidget/MainWidget.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../Widgets/GridItem/GridItem.hpp" #include "../GridItemView/GridItemView.hpp" diff --git a/src/View/Path/Path.cpp b/src/View/Path/Path.cpp index 19e5665..71244a9 100644 --- a/src/View/Path/Path.cpp +++ b/src/View/Path/Path.cpp @@ -18,10 +18,10 @@ Path::Path(QWidget* parent) border: 2px solid #414141; border-radius: 6px; color: #D8D8D8; - font-size: 20px; + font-size: 22px; )"); - setFixedHeight(40); + setFixedHeight(48); connect(m_fileController, &FileController::pathChanged, this, [this](const std::filesystem::path path) { diff --git a/src/View/Widgets/GridItem/GridItem.cpp b/src/View/Widgets/GridItem/GridItem.cpp index a6ae135..0189bdf 100644 --- a/src/View/Widgets/GridItem/GridItem.cpp +++ b/src/View/Widgets/GridItem/GridItem.cpp @@ -6,10 +6,14 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent) m_path(path), m_name(QString::fromStdString(path.filename( ).string( ))), m_icon(getIconForFileType(path)) { - widgetSize = QSize(80, 128); + widgetSize = QSize(128, 128); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setMinimumSize(widgetSize); setMaximumSize(widgetSize); + setObjectName("gridItem"); + setAttribute(Qt::WA_Hover); + auto vLayout = new QVBoxLayout(this); vLayout->setSpacing(10); @@ -17,7 +21,8 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent) m_iconLabel->setPixmap(m_icon.pixmap(widgetSize.width( ), widgetSize.height( ))); m_iconLabel->setAlignment(Qt::AlignCenter); - m_nameLabel = new QLabel(m_name, this); + m_nameLabel = new QLabel(this); + formatText(m_name); m_nameLabel->setAlignment(Qt::AlignCenter); m_nameLabel->setWordWrap(true); @@ -27,26 +32,53 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent) GridItem::~GridItem( ) { } -QString GridItem::formatText(const QString& text) { - QFontMetrics fm(font( )); - QString elidedText = fm.elidedText(text, Qt::ElideRight, widgetSize.width( )); - QString result; - QStringList lines = elidedText.split('\n'); - for (int i = 0; i < std::min((int)lines.size( ), 3); ++i) - result.append(lines.at(i)).append('\n'); +void GridItem::formatText(const QString& text) { + QFontMetrics metrics(m_nameLabel->font( )); + QString elidedText = metrics.elidedText(text, Qt::ElideRight, m_nameLabel->width( ) * 3); - if (lines.size( ) > 3) - result.append("..."); + QStringList lines = elidedText.split(' '); + QStringList finalText; + QString currentLine; - return result.trimmed( ); + for (const QString& word : lines) { + QString testLine = currentLine.isEmpty( ) ? word : currentLine + ' ' + word; + if (metrics.horizontalAdvance(testLine) <= m_nameLabel->width( )) { + currentLine = testLine; + } else { + finalText.append(currentLine); + currentLine = word; + } + + if (finalText.size( ) == 2 && currentLine.isEmpty( ) == false) { + currentLine += "..."; + break; + } + } + + if (!currentLine.isEmpty( ) && finalText.size( ) < 3) { + finalText.append(currentLine); + } + + m_nameLabel->setText(finalText.join('\n')); +} + +bool isImageFile(std::filesystem::path path) { + static const std::vector imageExtensions = { ".png", ".jpg", ".jpeg", ".bmp", ".gif" }; + return std::find(imageExtensions.begin( ), imageExtensions.end( ), path.extension( ).string( )) != imageExtensions.end( ); } QIcon GridItem::getIconForFileType(const std::filesystem::path path) const { if (!std::filesystem::is_directory(path)) { QIcon icon; - auto mdb = new QMimeDatabase( ); - QMimeType mime_type = mdb->mimeTypeForFile(QString::fromStdString(path.string( ))); - icon = QIcon::fromTheme(mime_type.iconName( )); + if (isImageFile(path)) { + QPixmap pixmap(QString::fromStdString(path.string( ))); + icon = QIcon(pixmap); + } else { + auto mdb = new QMimeDatabase( ); + QMimeType mime_type = mdb->mimeTypeForFile(QString::fromStdString(path.string( ))); + icon = QIcon::fromTheme(mime_type.iconName( )); + delete mdb; + } if (!icon.isNull( )) { QPixmap pixmap = icon.pixmap(QSize(64, 64)); @@ -82,6 +114,38 @@ void GridItem::paintEvent(QPaintEvent* event) { void GridItem::mousePressEvent(QMouseEvent* event) { if (event->button( ) == Qt::LeftButton) { emit clicked( ); + } else if (event->button( ) == Qt::RightButton) { + } QWidget::mousePressEvent(event); } + +void GridItem::mouseDoubleClickEvent(QMouseEvent* event) { + if (event->button( ) == Qt::LeftButton) { + emit doubleClicked( ); + } + + QWidget::mousePressEvent(event); +} + +void GridItem::enterEvent(QEnterEvent* event) { + setStyleSheet(R"( + #gridItem{ + border: 2px solid #414141; + background-color: #00ACC1; + border-radius: 8px; + } + )"); + QWidget::enterEvent(event); +} + +void GridItem::leaveEvent(QEvent* event) { + setStyleSheet(R"( + #gridItem{ + background-color: none; + border: 0px solid #414141; + border-radius: 8px; + } + )"); + QWidget::leaveEvent(event); +} diff --git a/src/View/Widgets/GridItem/GridItem.hpp b/src/View/Widgets/GridItem/GridItem.hpp index f5fcd8f..72ac709 100644 --- a/src/View/Widgets/GridItem/GridItem.hpp +++ b/src/View/Widgets/GridItem/GridItem.hpp @@ -21,7 +21,7 @@ private: QSize widgetSize; - QString formatText(const QString& text); + void formatText(const QString& text); QIcon getIconForFileType(const std::filesystem::path path) const; @@ -35,9 +35,13 @@ public: void setIconSize(const QSize& size); protected: - void paintEvent(QPaintEvent* event)override; + void paintEvent(QPaintEvent* event) override; void mousePressEvent(QMouseEvent* event) override; + void mouseDoubleClickEvent(QMouseEvent*) override; + void enterEvent(QEnterEvent* event) override; + void leaveEvent(QEvent* event) override; signals: void clicked( ); + void doubleClicked( ); }; diff --git a/src/main.cpp b/src/main.cpp index ccaf990..cf06d79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,13 +2,12 @@ #include #include -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { QApplication app(argc, argv); - auto w = std::make_unique(); + auto w = std::make_unique( ); - w->setMinimumHeight(200); - w->show(); + w->show( ); - return app.exec(); + return app.exec( ); }