767 lines
24 KiB
C++
767 lines
24 KiB
C++
#include "filemanager.h"
|
|
#include "ui_filemanager.h"
|
|
#include "ui_fitskeyword.h"
|
|
|
|
#include <QSettings>
|
|
#include <QStandardPaths>
|
|
#include <QDesktopServices>
|
|
#include <QMimeData>
|
|
#include <QClipboard>
|
|
#include <QThread>
|
|
#include <QDirIterator>
|
|
#include "loadimage.h"
|
|
|
|
class FileTimes
|
|
{
|
|
public:
|
|
explicit FileTimes(const QString &path)
|
|
{
|
|
QFile file(path);
|
|
#ifndef Q_OS_WIN
|
|
birthTime = file.fileTime(QFileDevice::FileBirthTime);
|
|
#endif
|
|
modificationTime = file.fileTime(QFileDevice::FileModificationTime);
|
|
accessTime = file.fileTime(QFileDevice::FileAccessTime);
|
|
}
|
|
void apply(const QString &path)
|
|
{
|
|
QFile file(path);
|
|
if(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::ExistingOnly))
|
|
{
|
|
#ifndef Q_OS_WIN // Only windows allow changing birth time
|
|
file.setFileTime(birthTime, QFileDevice::FileBirthTime);
|
|
#endif
|
|
file.setFileTime(accessTime, QFileDevice::FileAccessTime);
|
|
file.setFileTime(modificationTime, QFileDevice::FileModificationTime);
|
|
}
|
|
}
|
|
private:
|
|
QDateTime birthTime;
|
|
QDateTime modificationTime;
|
|
QDateTime accessTime;
|
|
};
|
|
|
|
FileTransfer::FileTransfer(FileManager *fm) :
|
|
_fm(fm)
|
|
{
|
|
}
|
|
|
|
FileTransfer::~FileTransfer()
|
|
{
|
|
_run = false;
|
|
}
|
|
|
|
void FileTransfer::copy(const QStringList &src, const QString &dst)
|
|
{
|
|
_run = true;
|
|
perform(src, dst, true);
|
|
emit finished();
|
|
}
|
|
|
|
void FileTransfer::move(const QStringList &src, const QString &dst)
|
|
{
|
|
_run = true;
|
|
perform(src, dst, false);
|
|
emit finished();
|
|
}
|
|
|
|
void FileTransfer::cancel()
|
|
{
|
|
_run = false;
|
|
}
|
|
|
|
void FileTransfer::perform(const QStringList &src, const QString &dst, bool copy)
|
|
{
|
|
QDir dstDir(dst);
|
|
if(!dstDir.exists())
|
|
{
|
|
emit error(tr("Error"), tr("Destination directory %1 doesn't exists").arg(dstDir.absolutePath()));
|
|
return;
|
|
}
|
|
|
|
QList<Action> actions;
|
|
QStringList dirs;
|
|
|
|
emit progress(0);
|
|
|
|
for(const QString &i : src)
|
|
{
|
|
QFileInfo srcInfo(i);
|
|
if(srcInfo.absolutePath() == dst || dst.startsWith(srcInfo.absoluteFilePath()))
|
|
return;
|
|
|
|
if(srcInfo.isDir())
|
|
{
|
|
QDir srcDir(i);
|
|
//qDebug() << "dir" << srcInfo.absoluteFilePath() << srcInfo.fileName();
|
|
if(!copy && !dstDir.exists(srcInfo.fileName()))
|
|
{
|
|
if(QFile::rename(srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())))
|
|
continue;
|
|
}
|
|
actions.append({srcInfo.absoluteFilePath(), srcInfo.fileName(), true});
|
|
if(!copy)dirs.prepend(srcInfo.absoluteFilePath());
|
|
QDirIterator it(i, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
|
while(it.hasNext())
|
|
{
|
|
QFileInfo info = it.nextFileInfo();
|
|
if(info.fileName() == "." || info.fileName() == "..")
|
|
continue;
|
|
|
|
QString relativePath = srcDir.dirName() + "/" + srcDir.relativeFilePath(info.absoluteFilePath());
|
|
if(info.isDir())
|
|
{
|
|
actions.append({"", relativePath, true});
|
|
if(!copy)dirs.prepend(info.absoluteFilePath());
|
|
//qDebug() << "dir" << info.absoluteFilePath() << relativePath;
|
|
}
|
|
else
|
|
{
|
|
actions.append({info.absoluteFilePath(), dstDir.absoluteFilePath(relativePath), false});
|
|
//qDebug() << "file" << info.absoluteFilePath() << dstDir.absoluteFilePath(relativePath);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
actions.append({srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())});
|
|
//qDebug() << "file" << srcInfo.absoluteFilePath() << dstDir.absoluteFilePath(srcInfo.fileName());
|
|
}
|
|
}
|
|
|
|
bool overwriteAll = false;
|
|
bool skipAll = false;
|
|
int total = actions.size();
|
|
int i = 0;
|
|
for(auto &a : actions)
|
|
{
|
|
if(!_run)
|
|
return;
|
|
|
|
if(a.dir)
|
|
{
|
|
dstDir.mkpath(a.dst);
|
|
}
|
|
else
|
|
{
|
|
QFileInfo dstInfo(a.dst);
|
|
if(dstInfo.exists())
|
|
{
|
|
if(overwriteAll)
|
|
{
|
|
QFile::remove(dstInfo.absoluteFilePath());
|
|
}
|
|
else if(skipAll)
|
|
{
|
|
emit progress(i++ * 100 / total);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::StandardButton ret;
|
|
QMetaObject::invokeMethod(_fm, "overwrite", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QMessageBox::StandardButton, ret), Q_ARG(QString, dstInfo.fileName()));
|
|
switch(ret)
|
|
{
|
|
case QMessageBox::YesToAll:
|
|
overwriteAll = true;//break; is intentionally missing
|
|
case QMessageBox::Yes:
|
|
QFile::remove(dstInfo.absoluteFilePath());
|
|
break;
|
|
case QMessageBox::NoToAll:
|
|
skipAll = true;//break; is intentionally missing
|
|
case QMessageBox::No:
|
|
emit progress(i++ * 100 / total);
|
|
continue;
|
|
break;
|
|
case QMessageBox::Cancel:
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FileTimes t(a.src);
|
|
if(copy)
|
|
{
|
|
if(!QFile::copy(a.src, a.dst))
|
|
{
|
|
emit error(tr("Copy failed"), tr("Failed to copy file %1 to %2").arg(a.src).arg(a.dst));
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!QFile::rename(a.src, a.dst))
|
|
{
|
|
emit error(tr("Move failed"), tr("Failed to move file %1 to %2").arg(a.src).arg(a.dst));
|
|
return;
|
|
}
|
|
}
|
|
t.apply(a.dst);
|
|
}
|
|
emit progress(i++ * 100 / total);
|
|
}
|
|
|
|
if(!copy)
|
|
{
|
|
for(const QString &d : dirs)
|
|
{
|
|
QDir dir(d);
|
|
if(dir.isEmpty())
|
|
dir.removeRecursively();
|
|
}
|
|
}
|
|
}
|
|
|
|
PathTabBar::PathTabBar(const QStringList &tabs) :
|
|
_tabs(tabs)
|
|
{
|
|
setTabsClosable(true);
|
|
setExpanding(false);
|
|
|
|
for(auto &t : _tabs)
|
|
{
|
|
QDir dir(t);
|
|
int i = addTab(tabName(t));
|
|
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()];
|
|
_tabs.append(path);
|
|
int i = addTab(tabName(path));
|
|
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, tabName(path));
|
|
setTabToolTip(index, path);
|
|
_tabs[index] = path;
|
|
}
|
|
|
|
QString PathTabBar::tabName(const QString &path)
|
|
{
|
|
QDir dir(path);
|
|
if(dir.dirName().isEmpty())
|
|
return path;
|
|
else
|
|
return dir.dirName();
|
|
}
|
|
|
|
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<QString> &openFilter, QWidget *parent) : QMainWindow(parent)
|
|
,ui(new Ui::FileManager)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
QStringList standardLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
|
|
QString picturesPath;
|
|
if(standardLocations.size())
|
|
picturesPath = standardLocations.first();
|
|
|
|
QSettings settings;
|
|
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->leftTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
|
|
connect(ui->rightTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
|
|
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(_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);
|
|
connect(ui->actionCopySelectedFilesPathsLeft, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
|
|
connect(ui->actionCopySelectedFilesPathsRight, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
|
|
connect(ui->leftPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
|
|
connect(ui->rightPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
|
|
|
|
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); });
|
|
}
|
|
|
|
ui->progressBar->hide();
|
|
ui->cancelButton->hide();
|
|
|
|
_thread = new QThread(this);
|
|
_thread->start();
|
|
_fileTransfer = new FileTransfer(this);
|
|
_fileTransfer->moveToThread(_thread);
|
|
connect(_fileTransfer, &FileTransfer::progress, ui->progressBar, &QProgressBar::setValue);
|
|
connect(_fileTransfer, &FileTransfer::error, this, &FileManager::errorMessage);
|
|
connect(_fileTransfer, &FileTransfer::finished, [this](){
|
|
ui->leftTab->setDragEnabled(true);
|
|
ui->rightTab->setDragEnabled(true);
|
|
ui->progressBar->hide();
|
|
ui->cancelButton->hide();
|
|
});
|
|
connect(this, &FileManager::copy, _fileTransfer, &FileTransfer::copy);
|
|
connect(this, &FileManager::move, _fileTransfer, &FileTransfer::move);
|
|
connect(ui->cancelButton, &QPushButton::clicked, [this](){ _fileTransfer->cancel(); });
|
|
}
|
|
|
|
FileManager::~FileManager()
|
|
{
|
|
QSettings settings;
|
|
settings.setValue("filemanager/leftFitsKeywords", ui->leftTab->FITSKeywords());
|
|
settings.setValue("filemanager/leftTabPaths", _leftTabBar->tabPaths());
|
|
settings.setValue("filemanager/leftTabHeader", ui->leftTab->header()->saveState());
|
|
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;
|
|
|
|
_fileTransfer->cancel();
|
|
_thread->quit();
|
|
_thread->wait();
|
|
|
|
delete _fileTransfer;
|
|
}
|
|
|
|
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::copySelectedFilesPaths()
|
|
{
|
|
if(sender() == ui->actionCopySelectedFilesPathsLeft)
|
|
ui->leftTab->copySelectedFilesPathsToClipboard();
|
|
if(sender() == ui->actionCopySelectedFilesPathsRight)
|
|
ui->rightTab->copySelectedFilesPathsToClipboard();
|
|
}
|
|
|
|
void FileManager::pathEdited()
|
|
{
|
|
if(sender() == ui->leftPath)
|
|
{
|
|
QDir dir(ui->leftPath->text());
|
|
if(dir.exists())
|
|
ui->leftTab->setDir(dir.absolutePath());
|
|
}
|
|
if(sender() == ui->rightPath)
|
|
{
|
|
QDir dir(ui->rightPath->text());
|
|
if(dir.exists())
|
|
ui->rightTab->setDir(dir.absolutePath());
|
|
}
|
|
}
|
|
|
|
void FileManager::copyMoveFiles(Qt::DropAction action, const QStringList &src, const QString &dst)
|
|
{
|
|
ui->leftTab->setDragEnabled(false);
|
|
ui->rightTab->setDragEnabled(false);
|
|
ui->progressBar->show();
|
|
ui->cancelButton->show();
|
|
|
|
switch(action)
|
|
{
|
|
case Qt::CopyAction:
|
|
emit copy(src, dst);
|
|
break;
|
|
case Qt::MoveAction:
|
|
emit move(src, dst);
|
|
break;
|
|
case Qt::LinkAction:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
QMessageBox::StandardButton FileManager::overwrite(const QString &dst)
|
|
{
|
|
QMessageBox::StandardButton button = QMessageBox::question(this, tr("Overwrite file?"), tr("Destination file %1 already exists. Overwrite?").arg(dst),
|
|
QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel);
|
|
|
|
return button;
|
|
}
|
|
|
|
void FileManager::errorMessage(const QString &title, const QString &text)
|
|
{
|
|
QMessageBox::critical(this, title, text);
|
|
}
|
|
|
|
QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
|
|
{
|
|
static bool init = true;
|
|
static QCache<QString, ImageInfoData> cache;
|
|
if(!init)
|
|
{
|
|
cache.setMaxCost(10000);
|
|
init = false;
|
|
}
|
|
return &cache;
|
|
}
|
|
|
|
DirFileSystemModel::DirFileSystemModel(QWidget *parentWidget) : QFileSystemModel(parentWidget)
|
|
,_parentWidget(parentWidget)
|
|
{
|
|
_cache = getCacheInstance();
|
|
setFilter(QDir::AllEntries | QDir::NoDot);
|
|
_fitsKeywords = {"OBJECT"};
|
|
}
|
|
|
|
void DirFileSystemModel::setDir(const QString &path)
|
|
{
|
|
_dir = index(path);
|
|
}
|
|
|
|
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
|
|
{
|
|
Qt::ItemFlags ret = QFileSystemModel::flags(index) & ~Qt::ItemIsEditable;
|
|
if(index.row() == 0)ret &= ~Qt::ItemIsDragEnabled;
|
|
return ret;
|
|
}
|
|
|
|
int DirFileSystemModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
return QFileSystemModel::columnCount(parent) + _fitsKeywords.size();
|
|
}
|
|
|
|
QVariant DirFileSystemModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if(index.column() >= QFileSystemModel::columnCount() && role == Qt::DisplayRole)
|
|
{
|
|
QFileInfo info = fileInfo(index);
|
|
QString path = info.canonicalFilePath();
|
|
QString suffix = info.suffix();
|
|
ImageInfoData *infoData = nullptr;
|
|
if(_cache->contains(path))
|
|
{
|
|
infoData = _cache->object(path);
|
|
}
|
|
else
|
|
{
|
|
if(_loadFitsKeywords)
|
|
{
|
|
infoData = new ImageInfoData;
|
|
if(isFITS(suffix))
|
|
readFITSHeader(path, *infoData);
|
|
else if(isXISF(suffix))
|
|
readXISFHeader(path, *infoData);
|
|
_cache->insert(path, infoData);
|
|
}
|
|
}
|
|
if(infoData)
|
|
{
|
|
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 "";
|
|
}
|
|
return QFileSystemModel::data(index, role);
|
|
}
|
|
|
|
QVariant DirFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if(orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= QFileSystemModel::columnCount())
|
|
return _fitsKeywords.at(section - QFileSystemModel::columnCount());
|
|
|
|
return QFileSystemModel::headerData(section, orientation, role);
|
|
}
|
|
|
|
bool DirFileSystemModel::hasChildren(const QModelIndex &parent) const
|
|
{
|
|
if(parent.parent() == _dir)return false;
|
|
|
|
return QFileSystemModel::hasChildren(parent);
|
|
}
|
|
|
|
bool DirFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
|
{
|
|
Q_UNUSED(row);
|
|
Q_UNUSED(column);
|
|
if(data->hasUrls())
|
|
{
|
|
QStringList srcPaths;
|
|
for(auto &url : data->urls())
|
|
srcPaths.append(url.toLocalFile());
|
|
emit filesAction(action, srcPaths, filePath(parent));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DirFileSystemModel::loadFitsKeywords(bool enable)
|
|
{
|
|
_loadFitsKeywords = enable;
|
|
}
|
|
|
|
DirView::DirView(QWidget *parent) : QTreeView(parent)
|
|
{
|
|
_dirFileSystemModel = new DirFileSystemModel(this);
|
|
_dirFileSystemModel->setRootPath(QDir::drives().first().path());
|
|
_dirFileSystemModel->setReadOnly(false);
|
|
setDragEnabled(true);
|
|
setAcceptDrops(true);
|
|
|
|
connect(_dirFileSystemModel, &DirFileSystemModel::filesAction, this, &DirView::filesAction);
|
|
|
|
setModel(_dirFileSystemModel);
|
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
|
|
connect(this, &QTreeView::doubleClicked, [this](const QModelIndex &index){
|
|
QFileInfo info = _dirFileSystemModel->fileInfo(index);
|
|
if(_dirFileSystemModel->isDir(index))
|
|
{
|
|
setDir(info.canonicalFilePath());
|
|
}
|
|
else if(info.isFile())
|
|
{
|
|
if(_openFilter.contains(info.suffix().toLower()))
|
|
emit openFile(info.absoluteFilePath());
|
|
else
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(info.absoluteFilePath()));
|
|
}
|
|
});
|
|
|
|
header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
connect(header(), &QHeaderView::customContextMenuRequested, this, &DirView::headerContextMenu);
|
|
}
|
|
|
|
void DirView::setDir(const QString &path)
|
|
{
|
|
QString oldPath = _dirFileSystemModel->dir();
|
|
#ifdef Q_OS_WINDOWS
|
|
const int ROOT_LEN = 3;
|
|
#else
|
|
const int ROOT_LEN = 1;
|
|
#endif
|
|
|
|
if(oldPath.left(ROOT_LEN) != path.left(ROOT_LEN))
|
|
_dirFileSystemModel->setRootPath(path.left(ROOT_LEN));
|
|
|
|
QString newPath = path;
|
|
if(!QFileInfo::exists(path))
|
|
{
|
|
QDir dir(path);
|
|
do
|
|
{
|
|
dir.setPath(QDir::cleanPath(dir.filePath("..")));
|
|
}while(!dir.exists() && !dir.isRoot());
|
|
newPath = dir.path();
|
|
}
|
|
|
|
_dirFileSystemModel->setDir(newPath);
|
|
setRootIndex(_dirFileSystemModel->index(newPath, 0));
|
|
clearSelection();
|
|
if(oldPath != newPath)emit dirChanged(newPath);
|
|
}
|
|
|
|
QString DirView::dir() const
|
|
{
|
|
return _dirFileSystemModel->dir();
|
|
}
|
|
|
|
void DirView::setOpenFilter(const QSet<QString> &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();
|
|
QMenu menu;
|
|
int count = head->count();
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
QAction *a = menu.addAction(head->model()->headerData(i, Qt::Horizontal).toString());
|
|
a->setCheckable(true);
|
|
a->setChecked(!head->isSectionHidden(i));
|
|
a->setData(i);
|
|
}
|
|
|
|
QAction *a = menu.exec(mapToGlobal(pos));
|
|
if(a)
|
|
{
|
|
if(a->isChecked())head->showSection(a->data().toInt());
|
|
else head->hideSection(a->data().toInt());
|
|
}
|
|
}
|
|
|
|
void DirView::loadFitsKeywords(bool enable)
|
|
{
|
|
_dirFileSystemModel->loadFitsKeywords(enable);
|
|
}
|
|
|
|
void DirView::copySelectedFilesPathsToClipboard() const
|
|
{
|
|
QList<QUrl> urls;
|
|
QString text;
|
|
auto selected = selectionModel()->selectedRows();
|
|
for(auto &item : selected)
|
|
{
|
|
if(item.column() == 0)
|
|
{
|
|
QString path = _dirFileSystemModel->filePath(item);
|
|
text.append(path); text.append('\n');
|
|
urls.append(QUrl::fromLocalFile(path));
|
|
}
|
|
}
|
|
QClipboard *clipboard = QApplication::clipboard();
|
|
QMimeData *mimeData = new QMimeData();
|
|
mimeData->setUrls(urls);
|
|
mimeData->setText(text);
|
|
clipboard->setMimeData(mimeData);
|
|
}
|