From d826744f262b0f3cb769b7bc0309d7b2a80ebee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Sun, 27 Jul 2025 15:35:25 +0200 Subject: [PATCH] Add tabs to file manager --- CMakeLists.txt | 1 + src/filemanager.cpp | 244 +++++++++++++++++++++++++++++++++++++++----- src/filemanager.h | 42 ++++++++ src/filemanager.ui | 6 +- 4 files changed, 267 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6da84af..b2a953e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ set(TENMON_SRC src/delete.cpp src/filemanager.h src/filemanager.cpp src/filemanager.ui src/filesystemwidget.cpp src/filesystemwidget.h + src/fitskeyword.ui src/histogram.cpp src/histogram.h src/httpdownloader.h src/httpdownloader.cpp src/imageinfo.cpp src/imageinfo.h diff --git a/src/filemanager.cpp b/src/filemanager.cpp index b7143bb..a3dd165 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -1,50 +1,213 @@ #include "filemanager.h" #include "ui_filemanager.h" +#include "ui_fitskeyword.h" #include #include #include #include "loadimage.h" +PathTabBar::PathTabBar(const QStringList &tabs) : + _tabs(tabs) +{ + setTabsClosable(true); + setExpanding(false); + + for(auto &t : tabs) + { + QDir dir(t); + int i = addTab(dir.dirName()); + setTabToolTip(i, t); + } + + connect(this, &QTabBar::currentChanged, [this](int index){ + QString path = _tabs.at(index); + emit pathChanged(path); + }); + connect(this, &QTabBar::tabCloseRequested, [this](int index){ + if(_tabs.size() >= 2) + { + _tabs.remove(index); + removeTab(index); + } + }); + connect(this, &QTabBar::currentChanged, [this](int index){ + emit tabChanged(_tabs[index]); + }); +} + +QHBoxLayout *PathTabBar::createLayout() +{ + QHBoxLayout *hlayout = new QHBoxLayout(); + + hlayout->addWidget(this); + hlayout->addStretch(2); + QPushButton *addButton = new QPushButton("+"); + connect(addButton, &QPushButton::clicked, [this](){ + QString path = _tabs[currentIndex()]; + QDir dir(path); + _tabs.append(path); + int i = addTab(dir.dirName()); + setTabToolTip(i, path); + }); + hlayout->addWidget(addButton); + return hlayout; +} + +const QStringList &PathTabBar::tabPaths() const +{ + return _tabs; +} + +QString PathTabBar::currentTabPath() const +{ + int index = std::clamp(currentIndex(), 0, (int)_tabs.size()); + return _tabs[index]; +} + +void PathTabBar::pathChanged(const QString &path) +{ + QDir dir(path); + int index = currentIndex(); + setTabText(index, dir.dirName()); + setTabToolTip(index, path); + _tabs[index] = path; +} + +FITSSelection::FITSSelection(const QStringList &keywords, QWidget *parent) : QDialog(parent) + ,ui(new Ui::FITSKeyword) +{ + ui->setupUi(this); + connect(ui->addButton, &QPushButton::clicked, [this](){ + auto item = ui->keywordList->findItems(ui->keyword->text(), Qt::MatchFixedString | Qt::MatchCaseSensitive); + if(item.size())return; + ui->keywordList->addItem(ui->keyword->text()); + }); + connect(ui->removeButton, &QPushButton::clicked, [this](){ + auto items = ui->keywordList->selectedItems(); + for(auto item : items) + delete item; + }); + + ui->keywordList->addItems(keywords); +} + +FITSSelection::~FITSSelection() +{ + delete ui; +} + +QStringList FITSSelection::FITSKeywords() const +{ + QStringList keywords; + for(int i = 0; i < ui->keywordList->count(); i++) + keywords.append(ui->keywordList->item(i)->text()); + + return keywords; +} + FileManager::FileManager(const QSet &openFilter, QWidget *parent) : QMainWindow(parent) ,ui(new Ui::FileManager) { ui->setupUi(this); - ui->leftTab->setOpenFilter(openFilter); - ui->rightTab->setOpenFilter(openFilter); - - connect(ui->leftTab, &DirView::dirChanged, ui->leftPath, &QLineEdit::setText); - connect(ui->rightTab, &DirView::dirChanged, ui->rightPath, &QLineEdit::setText); - connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile); - connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile); - QStringList standardLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); QString picturesPath; if(standardLocations.size()) picturesPath = standardLocations.first(); QSettings settings; - ui->leftTab->setDir(settings.value("filemanager/leftTabPath", picturesPath).toString()); + QStringList leftTabs = settings.value("filemanager/leftTabPaths", picturesPath).toStringList(); + QStringList rightTabs = settings.value("filemanager/rightTabPaths", picturesPath).toStringList(); + if(leftTabs.empty())leftTabs.append(picturesPath); + if(rightTabs.empty())rightTabs.append(picturesPath); + + ui->leftTab->setOpenFilter(openFilter); + ui->rightTab->setOpenFilter(openFilter); + + _rightTabBar = new PathTabBar(rightTabs); + ui->rightLayout->insertLayout(0, _rightTabBar->createLayout()); + connect(_rightTabBar, &PathTabBar::tabChanged, ui->rightTab, &DirView::setDir); + + _leftTabBar = new PathTabBar(leftTabs); + ui->leftLayout->insertLayout(0, _leftTabBar->createLayout()); + connect(_leftTabBar, &PathTabBar::tabChanged, ui->leftTab, &DirView::setDir); + + connect(ui->leftTab, &DirView::dirChanged, ui->leftPath, &QLineEdit::setText); + connect(ui->leftTab, &DirView::dirChanged, _leftTabBar, &PathTabBar::pathChanged); + connect(ui->rightTab, &DirView::dirChanged, ui->rightPath, &QLineEdit::setText); + connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged); + connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile); + connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile); + connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords); + connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords); + + ui->leftTab->setDir(_leftTabBar->currentTabPath()); + ui->leftTab->setFITSKeywords(settings.value("filemanager/leftFitsKeywords", QStringList("OBJECT")).toStringList()); ui->leftTab->header()->restoreState(settings.value("filemanager/leftTabHeader").toByteArray()); - ui->rightTab->setDir(settings.value("filemanager/rightTabPath", picturesPath).toString()); + ui->rightTab->setDir(_rightTabBar->currentTabPath()); + ui->rightTab->setFITSKeywords(settings.value("filemanager/rightFitsKeywords", QStringList("OBJECT")).toStringList()); ui->rightTab->header()->restoreState(settings.value("filemanager/rightTabHeader").toByteArray()); + + ui->actionLoad_FITS_keywordsLeft->setChecked(settings.value("filemanager/leftLoadFitsKeywords", true).toBool()); + ui->actionLoad_FITS_keywordsRight->setChecked(settings.value("filemanager/rightLoadFitsKeywords", true).toBool()); restoreGeometry(settings.value("filemanager/geometry").toByteArray()); setAttribute(Qt::WA_DeleteOnClose); + + connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords); + connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords); + + QFileInfoList drives = QDir::drives(); + for(auto &drive : drives) + { + QString path = drive.absoluteFilePath(); + ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); }); + ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); }); + } } FileManager::~FileManager() { QSettings settings; - settings.setValue("filemanager/leftTabPath", ui->leftTab->dir()); + settings.setValue("filemanager/leftFitsKeywords", ui->leftTab->FITSKeywords()); + settings.setValue("filemanager/leftTabPaths", _leftTabBar->tabPaths()); settings.setValue("filemanager/leftTabHeader", ui->leftTab->header()->saveState()); - settings.setValue("filemanager/rightTabPath", ui->rightTab->dir()); + settings.setValue("filemanager/rightFitsKeywords", ui->rightTab->FITSKeywords()); + settings.setValue("filemanager/rightTabPaths", _rightTabBar->tabPaths()); settings.setValue("filemanager/rightTabHeader", ui->rightTab->header()->saveState()); + settings.setValue("filemanager/leftLoadFitsKeywords", ui->actionLoad_FITS_keywordsLeft->isChecked()); + settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked()); settings.setValue("filemanager/geometry", saveGeometry()); delete ui; } +void FileManager::selectFITSKeywords() +{ + QStringList columns; + if(sender() == ui->actionSelect_columnsLeft) + columns = ui->leftTab->FITSKeywords(); + if(sender() == ui->actionSelect_columnsRight) + columns = ui->rightTab->FITSKeywords(); + + FITSSelection selection(columns, this); + int ret = selection.exec(); + + if(ret == QDialog::Accepted) + { + if(sender() == ui->actionSelect_columnsLeft) + ui->leftTab->setFITSKeywords(selection.FITSKeywords()); + + if(sender() == ui->actionSelect_columnsRight) + ui->rightTab->setFITSKeywords(selection.FITSKeywords()); + } +} + +void FileManager::addTab() +{ + +} + QCache* DirFileSystemModel::getCacheInstance() { static bool init = true; @@ -61,7 +224,7 @@ DirFileSystemModel::DirFileSystemModel(QObject *parent) : QFileSystemModel(paren { _cache = getCacheInstance(); setFilter(QDir::AllEntries | QDir::NoDot); - _fitsKeywords = {"OBJECT", "RA", "DEC"}; + _fitsKeywords = {"OBJECT"}; } void DirFileSystemModel::setDir(const QString &path) @@ -74,6 +237,18 @@ QString DirFileSystemModel::dir() const return fileInfo(_dir).canonicalFilePath(); } +void DirFileSystemModel::setFITSKeywords(const QStringList &keywords) +{ + beginResetModel(); + _fitsKeywords = keywords; + endResetModel(); +} + +const QStringList &DirFileSystemModel::FITSKeywords() const +{ + return _fitsKeywords; +} + Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const { return QFileSystemModel::flags(index) & ~Qt::ItemIsEditable; @@ -91,30 +266,33 @@ QVariant DirFileSystemModel::data(const QModelIndex &index, int role) const QFileInfo info = fileInfo(index); QString path = info.canonicalFilePath(); QString suffix = info.suffix(); - ImageInfoData *infoData; + ImageInfoData *infoData = nullptr; if(_cache->contains(path)) { infoData = _cache->object(path); } else { - infoData = new ImageInfoData; if(_loadFitsKeywords) { + infoData = new ImageInfoData; if(isFITS(suffix)) readFITSHeader(path, *infoData); else if(isXISF(suffix)) readXISFHeader(path, *infoData); + _cache->insert(path, infoData); } - _cache->insert(path, infoData); } - int column = index.column() - QFileSystemModel::columnCount(); - if(column < _fitsKeywords.size()) + if(infoData) { - const QString &key = _fitsKeywords.at(column); - for(auto &record : infoData->fitsHeader) - if(record.key == key) - return record.value; + int column = index.column() - QFileSystemModel::columnCount(); + if(column < _fitsKeywords.size()) + { + const QString &key = _fitsKeywords.at(column); + for(auto &record : infoData->fitsHeader) + if(record.key == key) + return record.value; + } } return ""; } @@ -164,7 +342,7 @@ DirView::DirView(QWidget *parent) : QTreeView(parent) } else if(info.isFile()) { - if(_openFilter.contains(info.suffix())) + if(_openFilter.contains(info.suffix().toLower())) emit openFile(info.absoluteFilePath()); else QDesktopServices::openUrl(QUrl::fromLocalFile(info.absoluteFilePath())); @@ -177,10 +355,11 @@ DirView::DirView(QWidget *parent) : QTreeView(parent) void DirView::setDir(const QString &path) { + QString oldPath = _dirFileSystemModel->dir(); _dirFileSystemModel->setDir(path); setRootIndex(_dirFileSystemModel->index(path, 0)); clearSelection(); - emit dirChanged(path); + if(oldPath != path)emit dirChanged(path); } QString DirView::dir() const @@ -193,6 +372,18 @@ void DirView::setOpenFilter(const QSet &openFilter) _openFilter = openFilter; } +void DirView::setFITSKeywords(const QStringList &keywords) +{ + QString d = dir(); + _dirFileSystemModel->setFITSKeywords(keywords); + setDir(d); +} + +const QStringList &DirView::FITSKeywords() const +{ + return _dirFileSystemModel->FITSKeywords(); +} + void DirView::headerContextMenu(const QPoint &pos) { QHeaderView *head = header(); @@ -213,3 +404,8 @@ void DirView::headerContextMenu(const QPoint &pos) else head->hideSection(a->data().toInt()); } } + +void DirView::loadFitsKeywords(bool enable) +{ + _dirFileSystemModel->loadFitsKeywords(enable); +} diff --git a/src/filemanager.h b/src/filemanager.h index d5e1ac9..16457c7 100644 --- a/src/filemanager.h +++ b/src/filemanager.h @@ -5,22 +5,59 @@ #include #include #include +#include +#include +#include #include "imageinfodata.h" namespace Ui { class FileManager; +class FITSKeyword; } +class PathTabBar : public QTabBar +{ + Q_OBJECT +public: + explicit PathTabBar(const QStringList &tabs); + QHBoxLayout* createLayout(); + const QStringList& tabPaths() const; + QString currentTabPath() const; +public slots: + void pathChanged(const QString &path); +signals: + void tabChanged(const QString &path); +private: + QStringList _tabs; +}; + +class FITSSelection : public QDialog +{ + Q_OBJECT +public: + FITSSelection(const QStringList &keywords, QWidget *parent = nullptr); + ~FITSSelection(); + QStringList FITSKeywords() const; +private: + Ui::FITSKeyword *ui; +}; + class FileManager : public QMainWindow { Q_OBJECT public: explicit FileManager(const QSet &openFilter, QWidget *parent = nullptr); ~FileManager(); +public slots: + void selectFITSKeywords(); +protected slots: + void addTab(); signals: void openFile(const QString &path); private: Ui::FileManager *ui; + PathTabBar *_leftTabBar; + PathTabBar *_rightTabBar; }; class DirFileSystemModel : public QFileSystemModel @@ -35,6 +72,8 @@ public: explicit DirFileSystemModel(QObject *parent = nullptr); void setDir(const QString &path); QString dir() const; + void setFITSKeywords(const QStringList &keywords); + const QStringList& FITSKeywords() const; Qt::ItemFlags flags(const QModelIndex &index) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; @@ -54,8 +93,11 @@ public: void setDir(const QString &path); QString dir() const; void setOpenFilter(const QSet &openFilter); + void setFITSKeywords(const QStringList &keywords); + const QStringList& FITSKeywords() const; public slots: void headerContextMenu(const QPoint &pos); + void loadFitsKeywords(bool enable); signals: void dirChanged(const QString &path); void openFile(const QString &path); diff --git a/src/filemanager.ui b/src/filemanager.ui index 8316fe3..d711942 100644 --- a/src/filemanager.ui +++ b/src/filemanager.ui @@ -16,7 +16,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -60,6 +60,7 @@ + @@ -67,6 +68,7 @@ +