Fix startup, and quitting, fixed squishing, added hover and double clicking, added back button

This commit is contained in:
2024-07-03 17:41:33 +02:00
parent abc97d95ef
commit 7ff0f8b71a
12 changed files with 164 additions and 61 deletions

View File

@@ -6,32 +6,35 @@
#include <unordered_map> #include <unordered_map>
FileController::FileController( ) { FileController::FileController( ) {
#ifdef _WIN32
m_fmWorker = std::make_shared<FileMonitor>( m_fmWorker = std::make_shared<FileMonitor>(
std::filesystem::path(std::getenv("USERPROFILE")),
std::chrono::milliseconds(1000)); std::chrono::milliseconds(1000));
#else
m_fmWorker = std::make_shared<FileMonitor>(
std::filesystem::path(std::getenv("HOME")),
std::chrono::milliseconds(1000));
#endif
m_fmWorker->moveToThread(&m_fsThread); 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( ), connect(this, &FileController::operate, m_fmWorker.get( ),
&FileMonitor::start); &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, connect(m_fmWorker.get( ), &FileMonitor::changed, this,
&FileController::update); &FileController::update);
// Propagating signal from the monitor that fires when the path is changed
connect(m_fmWorker.get( ), &FileMonitor::pathChanged, this, connect(m_fmWorker.get( ), &FileMonitor::pathChanged, this,
&FileController::newPath); &FileController::newPath);
#ifdef _WIN32
//Why this no workie m_fmWorker.get( )->SetPath(std::filesystem::path(std::getenv("USERPROFILE")));
//connect(this, &FileController::updatePath, m_fmWorker.get( ), &FileMonitor::SetPath); #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) { connect(this, &FileController::updatePath, this, [this](std::filesystem::path p) {
previousPaths.push(m_fmWorker.get( )->GetPath( ));
m_fmWorker.get( )->SetPath(p); 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( ); m_fsThread.start( );
emit operate( ); emit operate( );
@@ -39,6 +42,7 @@ FileController::FileController( ) {
FileController::~FileController( ) { FileController::~FileController( ) {
m_fsThread.quit( ); m_fsThread.quit( );
m_fmWorker.get( )->stop( );
m_fsThread.wait( ); m_fsThread.wait( );
} }

View File

@@ -4,6 +4,9 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <filesystem> #include <filesystem>
#include <QApplication>
#include <stack>
#include "../../Core/FileMonitor/FileMonitor.hpp" #include "../../Core/FileMonitor/FileMonitor.hpp"
class FileController : public QObject { class FileController : public QObject {
@@ -19,6 +22,8 @@ public:
FileController(const FileController&) = delete; FileController(const FileController&) = delete;
FileController& operator=(const FileController&) = delete; FileController& operator=(const FileController&) = delete;
std::stack<std::filesystem::path> previousPaths;
private: private:
// Private constructor to prevent instantiation // Private constructor to prevent instantiation
FileController( ); FileController( );
@@ -42,4 +47,5 @@ signals:
void pathChanged(const std::filesystem::path p); void pathChanged(const std::filesystem::path p);
void contentChanged(std::filesystem::path path, FileEvent event); void contentChanged(std::filesystem::path path, FileEvent event);
void previousPath( );
}; };

View File

@@ -3,22 +3,17 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
FileMonitor::FileMonitor(std::filesystem::path path, FileMonitor::FileMonitor(std::chrono::duration<int, std::milli> delay)
std::chrono::duration<int, std::milli> delay) : m_delay(delay) { }
: m_path(path), m_delay(delay) { }
void FileMonitor::SetPath(std::filesystem::path newPath) { void FileMonitor::SetPath(std::filesystem::path newPath) {
m_path = newPath; m_path = newPath;
std::cout << m_path.string( ) << std::endl;
emit pathChanged(m_path); emit pathChanged(m_path);
initPathsMap( ); initPathsMap( );
} }
void FileMonitor::initPathsMap( ) { void FileMonitor::initPathsMap( ) {
m_paths.clear( ); 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) { bool FileMonitor::is_hidden(const std::filesystem::path& p) {

View File

@@ -18,20 +18,23 @@ class FileMonitor : public QObject {
public: public:
std::chrono::duration<int, std::milli> m_delay; std::chrono::duration<int, std::milli> m_delay;
FileMonitor(std::filesystem::path path, FileMonitor(std::chrono::duration<int, std::milli> delay);
std::chrono::duration<int, std::milli> delay);
~FileMonitor( ) = default; ~FileMonitor( ) = default;
void SetPath(std::filesystem::path path); void SetPath(std::filesystem::path path);
std::filesystem::path GetPath( ) {
return m_path;
}
void stop( );
public slots: public slots:
void start( ); void start( );
void stop( );
private: private:
std::unordered_map<std::filesystem::path, std::filesystem::file_time_type> std::unordered_map<std::filesystem::path, std::filesystem::file_time_type>
m_paths; m_paths;
bool m_running; bool m_running = true;
std::filesystem::path m_path; std::filesystem::path m_path;
bool contains(const std::filesystem::path& key); bool contains(const std::filesystem::path& key);

View File

@@ -4,45 +4,57 @@
GridItemView::GridItemView(QWidget* parent) GridItemView::GridItemView(QWidget* parent)
: QFrame(parent), fileController(FileController::instance( )) { : 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, 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 // No, QT Does not offer a better way to clear a layout, at least this solution doesnt segfault
QLayoutItem* wItem; QLayoutItem* wItem;
while ((wItem = mainLayout->takeAt(0)) != 0) { while ((wItem = gridLayout->takeAt(0)) != 0) {
if (wItem->widget( )) if (wItem->widget( ))
wItem->widget( )->setParent(nullptr); wItem->widget( )->setParent(nullptr);
delete wItem; 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) { if (event == FileEvent::created) {
auto w = new GridItem(path); auto w = new GridItem(path);
gridMap[path] = w; gridMap[path] = w;
connect(w, &GridItem::clicked, this, [this, path]( ) { connect(w, &GridItem::doubleClicked, this, [this, path]( ) {
if (!std::filesystem::is_directory(path)) if (!std::filesystem::is_directory(path))
return; return;
emit fileController->updatePath(path); 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; int pos = gridMap.size( ) - 1;
mainLayout->addWidget(w, pos / 8, pos % 8); gridLayout->addWidget(w, pos / 8, pos % 8);
w->show( ); w->show( );
} else if (event == FileEvent::erased) { } else if (event == FileEvent::erased) {
mainLayout->removeWidget(gridMap[path]); gridLayout->removeWidget(gridMap[path]);
delete gridMap[path]; delete gridMap[path];
gridMap.erase(path); gridMap.erase(path);
int pos = 0; int pos = 0;
for (const auto& [key, widget] : gridMap) { for (const auto& [key, widget] : gridMap) {
mainLayout->addWidget(widget, pos / 8, pos % 8); gridLayout->addWidget(widget, pos / 8, pos % 8);
pos++; pos++;
} }
} else if (event == FileEvent::modified) { } else if (event == FileEvent::modified) {
std::cout << "modified" << std::endl; // Idk what this would be used for
} }
}); });

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include <QFrame> #include <QFrame>
#include <QScrollArea>
#include <cstdlib>
#include "../Widgets/GridItem/GridItem.hpp" #include "../Widgets/GridItem/GridItem.hpp"
#include "../../Controller/FileController/FileController.hpp" #include "../../Controller/FileController/FileController.hpp"

View File

@@ -1,16 +1,29 @@
#include "MainWidget.hpp" #include "MainWidget.hpp"
#include <iostream>
MainWidget::MainWidget(QWidget* parent) { MainWidget::MainWidget(QWidget* parent) {
auto path_mainContentLayout = new QVBoxLayout(this); 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); fileTree_fileGridLayout->addWidget(gridLayout);
path_mainContentLayout->addWidget(path); path_mainContentLayout->addLayout(pathBackLayout);
path_mainContentLayout->addLayout(fileTree_fileGridLayout); path_mainContentLayout->addLayout(fileTree_fileGridLayout);
setLayout(path_mainContentLayout); setLayout(path_mainContentLayout);

View File

@@ -4,6 +4,7 @@
#include <QLabel> #include <QLabel>
#include <QWidget> #include <QWidget>
#include <QGridLayout> #include <QGridLayout>
#include <QPushButton>
#include "../Widgets/GridItem/GridItem.hpp" #include "../Widgets/GridItem/GridItem.hpp"
#include "../GridItemView/GridItemView.hpp" #include "../GridItemView/GridItemView.hpp"

View File

@@ -18,10 +18,10 @@ Path::Path(QWidget* parent)
border: 2px solid #414141; border: 2px solid #414141;
border-radius: 6px; border-radius: 6px;
color: #D8D8D8; color: #D8D8D8;
font-size: 20px; font-size: 22px;
)"); )");
setFixedHeight(40); setFixedHeight(48);
connect(m_fileController, &FileController::pathChanged, this, connect(m_fileController, &FileController::pathChanged, this,
[this](const std::filesystem::path path) { [this](const std::filesystem::path path) {

View File

@@ -6,10 +6,14 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent)
m_path(path), m_path(path),
m_name(QString::fromStdString(path.filename( ).string( ))), m_name(QString::fromStdString(path.filename( ).string( ))),
m_icon(getIconForFileType(path)) { m_icon(getIconForFileType(path)) {
widgetSize = QSize(80, 128); widgetSize = QSize(128, 128);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setMinimumSize(widgetSize); setMinimumSize(widgetSize);
setMaximumSize(widgetSize); setMaximumSize(widgetSize);
setObjectName("gridItem");
setAttribute(Qt::WA_Hover);
auto vLayout = new QVBoxLayout(this); auto vLayout = new QVBoxLayout(this);
vLayout->setSpacing(10); 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->setPixmap(m_icon.pixmap(widgetSize.width( ), widgetSize.height( )));
m_iconLabel->setAlignment(Qt::AlignCenter); 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->setAlignment(Qt::AlignCenter);
m_nameLabel->setWordWrap(true); m_nameLabel->setWordWrap(true);
@@ -27,26 +32,53 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent)
GridItem::~GridItem( ) { } GridItem::~GridItem( ) { }
QString GridItem::formatText(const QString& text) { void GridItem::formatText(const QString& text) {
QFontMetrics fm(font( )); QFontMetrics metrics(m_nameLabel->font( ));
QString elidedText = fm.elidedText(text, Qt::ElideRight, widgetSize.width( )); QString elidedText = metrics.elidedText(text, Qt::ElideRight, m_nameLabel->width( ) * 3);
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');
if (lines.size( ) > 3) QStringList lines = elidedText.split(' ');
result.append("..."); 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<std::string> 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 { QIcon GridItem::getIconForFileType(const std::filesystem::path path) const {
if (!std::filesystem::is_directory(path)) { if (!std::filesystem::is_directory(path)) {
QIcon icon; QIcon icon;
auto mdb = new QMimeDatabase( ); if (isImageFile(path)) {
QMimeType mime_type = mdb->mimeTypeForFile(QString::fromStdString(path.string( ))); QPixmap pixmap(QString::fromStdString(path.string( )));
icon = QIcon::fromTheme(mime_type.iconName( )); 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( )) { if (!icon.isNull( )) {
QPixmap pixmap = icon.pixmap(QSize(64, 64)); QPixmap pixmap = icon.pixmap(QSize(64, 64));
@@ -82,6 +114,38 @@ void GridItem::paintEvent(QPaintEvent* event) {
void GridItem::mousePressEvent(QMouseEvent* event) { void GridItem::mousePressEvent(QMouseEvent* event) {
if (event->button( ) == Qt::LeftButton) { if (event->button( ) == Qt::LeftButton) {
emit clicked( ); emit clicked( );
} else if (event->button( ) == Qt::RightButton) {
} }
QWidget::mousePressEvent(event); 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);
}

View File

@@ -21,7 +21,7 @@ private:
QSize widgetSize; QSize widgetSize;
QString formatText(const QString& text); void formatText(const QString& text);
QIcon getIconForFileType(const std::filesystem::path path) const; QIcon getIconForFileType(const std::filesystem::path path) const;
@@ -35,9 +35,13 @@ public:
void setIconSize(const QSize& size); void setIconSize(const QSize& size);
protected: protected:
void paintEvent(QPaintEvent* event)override; void paintEvent(QPaintEvent* event) override;
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent*) override;
void enterEvent(QEnterEvent* event) override;
void leaveEvent(QEvent* event) override;
signals: signals:
void clicked( ); void clicked( );
void doubleClicked( );
}; };

View File

@@ -2,13 +2,12 @@
#include <QApplication> #include <QApplication>
#include <memory> #include <memory>
int main(int argc, char *argv[]) { int main(int argc, char* argv[]) {
QApplication app(argc, argv); QApplication app(argc, argv);
auto w = std::make_unique<MainWindow>(); auto w = std::make_unique<MainWindow>( );
w->setMinimumHeight(200); w->show( );
w->show();
return app.exec(); return app.exec( );
} }