Description: Support viewing (launching) current item By double-clicking it or through its context menu item if it's a file. . Also, remember the last dir on opening files in each session. . Also, set `Qt::AA_UseHighDpiPixmaps`. . Also, commented out `QDebug` messages to be able to see temporary ones ;) Author: Tsu Jan Origin: upstream Bug: https://github.com/lxqt/lxqt-archiver/pull/10 Last-Update: 2018-07-09 --- a/src/archiver.cpp +++ b/src/archiver.cpp @@ -338,7 +338,7 @@ void Archiver::rebuildDirTree() { std::string dirName = stripTrailingSlash(item->fullPath()); dirMap_[dirName] = item; } - + if(fileData->encrypted) { isEncrypted_ = true; } @@ -385,8 +385,8 @@ void Archiver::rebuildDirTree() { g_free(tmp); } - qDebug("op: %s, %s", fileData->original_path, item->originalPath()); - qDebug("fp: %s, %s", fileData->full_path, item->fullPath()); + //qDebug("op: %s, %s", fileData->original_path, item->originalPath()); + //qDebug("fp: %s, %s", fileData->full_path, item->fullPath()); fileData->name = g_path_get_basename(dirName.c_str()); fileData->dir = 1; file_data_update_content_type(fileData); @@ -419,9 +419,9 @@ void Archiver::rebuildDirTree() { } rootItem_ = dirMap_["/"]; - for(auto& kv: dirMap_) { + /*for(auto& kv: dirMap_) { qDebug("dir: %s: %d", kv.first.c_str(), kv.second->children().size()); - } + }*/ } void Archiver::stopCurrentAction() { @@ -519,14 +519,14 @@ const FileData* Archiver::fileDataByOrig // We use the workaround provided here: https://bugreports.qt.io/browse/QTBUG-18434 void Archiver::onStart(FrArchive*, FrAction action, Archiver* _this) { - qDebug("start"); + //qDebug("start"); _this->busy_ = true; QMetaObject::invokeMethod(_this, "start", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(FrAction, action)); } void Archiver::onDone(FrArchive*, FrAction action, FrProcError* error, Archiver* _this) { - qDebug("done: %s", error && error->gerror ? error->gerror->message : ""); + //qDebug("done: %s", error && error->gerror ? error->gerror->message : ""); // FIXME: error might become dangling pointer for queued connections. :-( switch(action) { @@ -546,11 +546,11 @@ void Archiver::onDone(FrArchive*, FrActi void Archiver::onProgress(FrArchive*, double fraction, Archiver* _this) { QMetaObject::invokeMethod(_this, "progress", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(double, fraction)); - qDebug("progress: %lf", fraction); + //qDebug("progress: %lf", fraction); } void Archiver::onMessage(FrArchive*, const char* msg, Archiver* _this) { - qDebug("message: %s", msg); + //qDebug("message: %s", msg); QMetaObject::invokeMethod(_this, "message", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(QString, QString::fromUtf8(msg))); } @@ -560,6 +560,6 @@ void Archiver::onStoppable(FrArchive*, g void Archiver::onWorkingArchive(FrCommand* comm, const char* filename, Archiver* _this) { // FIXME: why the first param is comm? - qDebug("working: %s", filename); + //qDebug("working: %s", filename); Q_EMIT _this->workingArchive(filename); } --- a/src/main.cpp +++ b/src/main.cpp @@ -334,6 +334,7 @@ int main(int argc, char** argv) { QApplication app(argc, argv); app.setApplicationVersion(LXQT_ARCHIVER_VERSION); app.setQuitOnLastWindowClosed(true); + app.setAttribute(Qt::AA_UseHighDpiPixmaps); // load translations // install the translations built-into Qt itself --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -41,6 +42,7 @@ #include #include #include +#include // #include #include @@ -82,6 +84,8 @@ MainWindow::MainWindow(QWidget* parent): popupMenu_ = new QMenu{this}; popupMenu_->addAction(ui_->actionExtract); popupMenu_->addAction(ui_->actionDelete); + popupMenu_->addSeparator(); + popupMenu_->addAction(ui_->actionView); // proxy model used to filter and sort the items proxyModel_ = new ArchiverProxyModel{this}; @@ -98,6 +102,7 @@ MainWindow::MainWindow(QWidget* parent): // show context menu ui_->fileListView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui_->fileListView, &QAbstractItemView::customContextMenuRequested, this, &MainWindow::onFileListContextMenu); + connect(ui_->fileListView, &QAbstractItemView::doubleClicked, this, &MainWindow::onFileListDoubleClicked); connect(archiver_.get(), &Archiver::invalidateContent, this, &MainWindow::onInvalidateContent); connect(archiver_.get(), &Archiver::start, this, &MainWindow::onActionStarted); @@ -115,9 +120,16 @@ MainWindow::MainWindow(QWidget* parent): ui_->actionPaste->deleteLater(); ui_->actionRename->deleteLater(); ui_->actionFind->deleteLater(); + + lasrDir_ = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); + + setAttribute(Qt::WA_DeleteOnClose, true); } MainWindow::~MainWindow() { + if(!tempDir_.isEmpty()) { // remove the temp dir if any + QDir(tempDir_).removeRecursively(); + } } void MainWindow::loadFile(const Fm::FilePath &file) { @@ -127,6 +139,18 @@ void MainWindow::loadFile(const Fm::File splitVolumes_ = false; volumeSize_ = 0; + // find the name of temporary extraction directory (used for viewing files) + if(!tempDir_.isEmpty()) { // remove the last temp dir + QDir(tempDir_).removeRecursively(); + } + QString tmp = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + if(!tmp.isEmpty()) { + if(QDir(tmp).exists()) { + tempDir_ = tmp + "/" + "lxqt-archiver-" + + QDateTime::currentDateTime().toString("yyyyMMddhhmmss"); + } + } + archiver_->openArchive(file.uri().get(), nullptr); } @@ -155,15 +179,17 @@ void MainWindow::on_actionCreateNew_trig } void MainWindow::on_actionOpen_triggered(bool /*checked*/) { - qDebug("open"); + //qDebug("open"); Fm::FileDialog dlg{this}; dlg.setFileMode(QFileDialog::ExistingFile); dlg.setNameFilters(Archiver::supportedOpenNameFilters() << tr("All files (*)")); - qDebug() << Archiver::supportedOpenMimeTypes(); + //qDebug() << Archiver::supportedOpenMimeTypes(); dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setDirectory(lasrDir_); if(dlg.exec() == QDialog::Accepted) { auto url = dlg.selectedFiles()[0]; if(!url.isEmpty()) { + lasrDir_ = dlg.directory(); loadFile(Fm::FilePath::fromUri(url.toEncoded())); } } @@ -187,6 +213,7 @@ void MainWindow::on_actionAddFiles_trigg dlg.setFileMode(QFileDialog::ExistingFiles); dlg.setNameFilters(QStringList{} << tr("All files (*)")); dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setDirectory(lasrDir_); // only add the files if they are newer auto onlyIfNewerCheckbox = new QCheckBox{tr("Add only if &newer"), &dlg}; @@ -199,8 +226,9 @@ void MainWindow::on_actionAddFiles_trigg return; auto fileUrls = dlg.selectedFiles(); - qDebug() << "selected:" << fileUrls; + //qDebug() << "selected:" << fileUrls; if(!fileUrls.isEmpty()) { + lasrDir_ = dlg.directory(); auto srcPaths = Fm::pathListFromQUrls(fileUrls); archiver_->addFiles(srcPaths, currentDirPath_.c_str(), @@ -218,6 +246,7 @@ void MainWindow::on_actionAddFolder_trig dlg.setFileMode(QFileDialog::Directory); dlg.setNameFilters(QStringList{} << tr("All files (*)")); dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setDirectory(lasrDir_); // only add the files if they are newer auto onlyIfNewerCheckbox = new QCheckBox{tr("Add only if &newer"), &dlg}; @@ -232,6 +261,7 @@ void MainWindow::on_actionAddFolder_trig QUrl dirUrl = dlg.selectedFiles()[0]; if(!dirUrl.isEmpty()) { + lasrDir_ = dlg.directory(); auto path = Fm::FilePath::fromUri(dirUrl.toEncoded().constData()); archiver_->addDirectory(path, currentDirPath_.c_str(), @@ -247,7 +277,7 @@ void MainWindow::on_actionDelete_trigger if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete selected files?"), QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes) { return; } - qDebug("delete"); + //qDebug("delete"); auto files = selectedFiles(true); if(!files.empty()) { archiver_->removeFiles(files, FR_COMPRESSION_NORMAL); @@ -259,7 +289,7 @@ void MainWindow::on_actionSelectAll_trig } void MainWindow::on_actionExtract_triggered(bool /*checked*/) { - qDebug("extract"); + //qDebug("extract"); ExtractFileDialog dlg{this}; auto files = selectedFiles(true); @@ -312,6 +342,62 @@ void MainWindow::on_actionExtract_trigge } } +void MainWindow::tempExtractCurFile(bool launch) { + launchPath_.clear(); + if(tempDir_.isEmpty()) { + return; + } + if(auto selModel = ui_->fileListView->selectionModel()) { + QModelIndex idx = selModel->currentIndex(); + auto item = itemFromIndex(idx); + if(item && !item->isDir()) { + const QString fileName = tempDir_ + item->fullPath(); + if(QFile::exists(fileName)) { // already extracted under tmp + if(launch) { + Fm::FilePathList paths; + paths.push_back(Fm::FilePath::fromLocalPath(fileName.toLocal8Bit().constData())); + Fm::FileLauncher().launchPaths(nullptr, std::move(paths)); + } + return; + } + + if (launch) { + launchPath_ = fileName; + } + + QString dest = tempDir_; + QDir dir(tempDir_); + const QString curDirPath = QString::fromStdString(currentDirPath_); + if(curDirPath.contains("/")) { + dest = tempDir_ + "/" + curDirPath.section("/", 0, -2); + dir.mkpath(dest); // also creates "dir" if needed + } + else if(!dir.exists()) { + dir.mkpath(tempDir_); + } + + if(archiver_->isEncrypted() && password_.empty()) { + password_ = PasswordDialog::askPassword(this).toStdString(); + } + auto destDir = Fm::FilePath::fromLocalPath(dest.toLocal8Bit().constData()); + std::vector files; + files.emplace_back(item->data()); + archiver_->extractFiles(files, + destDir, + currentDirPath_.c_str(), + false, + false, + false, + password_.empty() ? nullptr : password_.c_str() + ); + } + } +} + +void MainWindow::on_actionView_triggered(bool /*checked*/) { + tempExtractCurFile(true); +} + void MainWindow::on_actionTest_triggered(bool /*checked*/) { if(archiver_->isLoaded()) { archiver_->testArchiveIntegrity(nullptr); @@ -379,11 +465,20 @@ void MainWindow::onFileListSelectionChan } void MainWindow::onFileListContextMenu(const QPoint &pos) { + if(auto selModel = ui_->fileListView->selectionModel()) { + QModelIndex idx = selModel->currentIndex(); + auto item = itemFromIndex(idx); + ui_->actionView->setVisible(item && !item->isDir()); + } // QAbstractScrollArea and its subclasses map the context menu event to coordinates of the viewport(). auto globalPos = ui_->fileListView->viewport()->mapToGlobal(pos); popupMenu_->popup(globalPos); } +void MainWindow::onFileListDoubleClicked(const QModelIndex & /*index*/) { + tempExtractCurFile(true); +} + void MainWindow::onFileListActivated(const QModelIndex &index) { auto item = itemFromIndex(index); if(item && item->isDir()) { @@ -408,11 +503,11 @@ void MainWindow::onActionStarted(FrActio progressBar_->show(); progressBar_->setFormat(tr("%p %")); - qDebug("action start: %d", action); + //qDebug("action start: %d", action); switch(action) { case FR_ACTION_CREATING_NEW_ARCHIVE: - qDebug("new archive"); + //qDebug("new archive"); setFileName(archiver_->archiveDisplayName()); break; case FR_ACTION_LOADING_ARCHIVE: /* loading the archive from a remote location */ @@ -463,16 +558,16 @@ void MainWindow::onActionFinished(FrActi setBusyState(false); progressBar_->hide(); - qDebug("action finished: %d", action); + //qDebug("action finished: %d", action); switch(action) { case FR_ACTION_LOADING_ARCHIVE: /* loading the archive from a remote location */ - qDebug("finish! %d", action); + //qDebug("finish! %d", action); break; case FR_ACTION_CREATING_NEW_ARCHIVE: // same as listing empty content case FR_ACTION_CREATING_ARCHIVE: /* creating a local archive */ case FR_ACTION_LISTING_CONTENT: /* listing the content of the archive */ - qDebug("content listed"); + //qDebug("content listed"); // content dir list of the archive is fully loaded updateDirTree(); @@ -504,6 +599,14 @@ void MainWindow::onActionFinished(FrActi archiver_->reloadArchive(nullptr); break; case FR_ACTION_EXTRACTING_FILES: /* extracting files */ + if(!launchPath_.isEmpty()) { + if(!err.hasError() && QFile::exists(launchPath_)) { + Fm::FilePathList paths; + paths.push_back(Fm::FilePath::fromLocalPath(launchPath_.toLocal8Bit().constData())); + Fm::FileLauncher().launchPaths(this, std::move(paths)); + } + launchPath_.clear(); + } break; case FR_ACTION_COPYING_FILES_TO_REMOTE: /* copying extracted files to a remote location */ break; @@ -613,7 +716,7 @@ void MainWindow::showFileList(const std: if(currentDirItem_) { auto parent = archiver_->parentDir(currentDirItem_); if(parent) { - qDebug("parent: %s", parent ? parent->fullPath() : "null"); + //qDebug("parent: %s", parent ? parent->fullPath() : "null"); auto parentRow = createFileListRow(parent); parentRow[0]->setText(".."); model->appendRow(parentRow); @@ -711,7 +814,7 @@ std::vector MainWindow: // FIXME: the old code uses FileData here. Later we should all use ArchiveItem instead. for(auto& item: items) { if(item->data()) { - qDebug("SEL: %s", item->fullPath()); + //qDebug("SEL: %s", item->fullPath()); results.emplace_back(item->data()); } } --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -72,10 +72,12 @@ private Q_SLOTS: void on_actionExtract_triggered(bool checked); + void on_actionView_triggered(bool checked); + void on_actionTest_triggered(bool checked); void on_actionPassword_triggered(bool checked); - + void on_actionDirTree_toggled(bool checked); void on_actionDirTreeMode_toggled(bool checked); @@ -94,6 +96,8 @@ private Q_SLOTS: void onFileListContextMenu(const QPoint &pos); + void onFileListDoubleClicked(const QModelIndex &index); + void onFileListActivated(const QModelIndex &index); private Q_SLOTS: @@ -137,7 +141,9 @@ private: const ArchiverItem* itemFromIndex(const QModelIndex& index); QModelIndex indexFromItem(const QModelIndex& parent, const ArchiverItem* item); - + + void tempExtractCurFile(bool launch); + private: std::unique_ptr ui_; std::shared_ptr archiver_; @@ -153,6 +159,10 @@ private: bool encryptHeader_; bool splitVolumes_; unsigned int volumeSize_; + + QString tempDir_; + QString launchPath_; + QUrl lasrDir_; }; #endif // MAINWINDOW_H --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -410,6 +410,11 @@ Filename &Encoding + + + &View Current Item + + --- a/src/progressdialog.cpp +++ b/src/progressdialog.cpp @@ -45,7 +45,7 @@ void ProgressDialog::reject() { } void ProgressDialog::onProgress(double fraction) { - qDebug("progress: %lf", fraction); + //qDebug("progress: %lf", fraction); if(fraction < 0.0) { // negative progress indicates that progress is unknown ui_->progressBar->setRange(0, 0); // set it to undertermined state @@ -60,7 +60,7 @@ void ProgressDialog::onFinished(FrAction } void ProgressDialog::onMessage(QString msg) { - qDebug("progress: %s", msg.toUtf8().constData()); + //qDebug("progress: %s", msg.toUtf8().constData()); ui_->message->setText(msg); } @@ -69,7 +69,7 @@ void ProgressDialog::onStoppableChanged( } void ProgressDialog::onWorkingArchive(QString filename) { - qDebug("progress: %s", filename.toUtf8().constData()); + //qDebug("progress: %s", filename.toUtf8().constData()); ui_->currentFile->setText(filename); }