File indexing completed on 2024-05-19 16:49:47

0001 // SPDX-FileCopyrightText: 2020 Simon Persson <simon.persson@mykolab.com>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "filedigger.h"
0006 #include "mergedvfsmodel.h"
0007 #include "restoredialog.h"
0008 #include "versionlistmodel.h"
0009 #include "versionlistdelegate.h"
0010 
0011 #include <KDirOperator>
0012 #include <KFilePlacesView>
0013 #include <KFilePlacesModel>
0014 #include <KGuiItem>
0015 #include <KIO/OpenUrlJob>
0016 #include <KIO/JobUiDelegate>
0017 #include <KIO/JobUiDelegateFactory>
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 #include <KStandardAction>
0021 #include <KToolBar>
0022 
0023 #include <QGuiApplication>
0024 #include <QLabel>
0025 #include <QListView>
0026 #include <QPushButton>
0027 #include <QSplitter>
0028 #include <QTimer>
0029 #include <QTreeView>
0030 #include <QVBoxLayout>
0031 #include <utility>
0032 #include <kio_version.h>
0033 
0034 FileDigger::FileDigger(QString pRepoPath, QString pBranchName, QWidget *pParent)
0035     : KMainWindow(pParent), mRepoPath(std::move(pRepoPath)), mBranchName(std::move(pBranchName)), mDirOperator(nullptr)
0036 {
0037     setWindowIcon(QIcon::fromTheme(QStringLiteral("kup")));
0038     KToolBar *lAppToolBar = toolBar();
0039     lAppToolBar->addAction(KStandardAction::quit(this, SLOT(close()), this));
0040     QTimer::singleShot(0, this, [this]{repoPathAvailable();});
0041 }
0042 
0043 QSize FileDigger::sizeHint() const {
0044     return {800, 600};
0045 }
0046 
0047 void FileDigger::updateVersionModel(const QModelIndex &pCurrent, const QModelIndex &pPrevious) {
0048     Q_UNUSED(pPrevious)
0049     mVersionModel->setNode(MergedVfsModel::node(pCurrent));
0050     mVersionView->selectionModel()->setCurrentIndex(mVersionModel->index(0,0),
0051                                                     QItemSelectionModel::Select);
0052 }
0053 
0054 void FileDigger::open(const QModelIndex &pIndex) {
0055 
0056     auto *job = new KIO::OpenUrlJob(pIndex.data(VersionBupUrlRole).toUrl(),
0057                  pIndex.data(VersionMimeTypeRole).toString());
0058 #if KIO_VERSION > QT_VERSION_CHECK(5, 98, 0)
0059     auto *delegate = KIO::createDefaultJobUiDelegate(KIO::JobUiDelegate::AutoHandlingEnabled, this);
0060 #else
0061     auto *delegate = new KIO::JobUiDelegate(KIO::JobUiDelegate::AutoHandlingEnabled, this);
0062 #endif
0063     job->setUiDelegate(delegate);
0064     job->start();
0065 }
0066 
0067 void FileDigger::restore(const QModelIndex &pIndex) {
0068     auto lDialog = new RestoreDialog(pIndex.data(VersionSourceInfoRole).value<BupSourceInfo>(), this);
0069     lDialog->setAttribute(Qt::WA_DeleteOnClose);
0070     lDialog->show();
0071 }
0072 
0073 void FileDigger::repoPathAvailable() {
0074     if(mRepoPath.isEmpty()) {
0075         createSelectionView();
0076     } else {
0077         QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0078         MergedRepository *lRepository = createRepo();
0079         if(lRepository != nullptr) {
0080             createRepoView(lRepository);
0081         }
0082         QGuiApplication::restoreOverrideCursor();
0083     }
0084 }
0085 
0086 void FileDigger::checkFileWidgetPath() {
0087     KFileItemList lList = mDirOperator->selectedItems();
0088     if(lList.isEmpty()) {
0089         mRepoPath = mDirOperator->url().toLocalFile();
0090     } else {
0091         mRepoPath = lList.first().url().toLocalFile();
0092     }
0093     mBranchName = QStringLiteral("kup");
0094     repoPathAvailable();
0095 }
0096 
0097 void FileDigger::enterUrl(const QUrl &pUrl) {
0098     mDirOperator->setUrl(pUrl, true);
0099 }
0100 
0101 MergedRepository *FileDigger::createRepo() {
0102     auto lRepository = new MergedRepository(nullptr, mRepoPath, mBranchName);
0103     if(!lRepository->open()) {
0104         KMessageBox::error(nullptr, xi18nc("@info messagebox, %1 is a folder path",
0105                                        "The backup archive <filename>%1</filename> could not be opened. "
0106                                        "Check if the backups really are located there.",
0107                                        mRepoPath));
0108         return nullptr;
0109     }
0110     if(!lRepository->readBranch()) {
0111         if(!lRepository->permissionsOk()) {
0112             KMessageBox::error(nullptr, xi18nc("@info messagebox",
0113                                            "You do not have permission needed to read this backup archive."));
0114         } else {
0115             MergedRepository::askForIntegrityCheck();
0116         }
0117         return nullptr;
0118     }
0119     return lRepository;
0120 }
0121 
0122 void FileDigger::createRepoView(MergedRepository *pRepository) {
0123     auto lSplitter = new QSplitter();
0124     mMergedVfsModel = new MergedVfsModel(pRepository, this);
0125     mMergedVfsView = new QTreeView();
0126     mMergedVfsView->setHeaderHidden(true);
0127     mMergedVfsView->setSelectionMode(QAbstractItemView::SingleSelection);
0128     mMergedVfsView->setModel(mMergedVfsModel);
0129     lSplitter->addWidget(mMergedVfsView);
0130     connect(mMergedVfsView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
0131             this, SLOT(updateVersionModel(QModelIndex,QModelIndex)));
0132 
0133     mVersionView = new QListView();
0134     mVersionView->setSelectionMode(QAbstractItemView::SingleSelection);
0135     mVersionModel = new VersionListModel(this);
0136     mVersionView->setModel(mVersionModel);
0137     auto lVersionDelegate = new VersionListDelegate(mVersionView,this);
0138     mVersionView->setItemDelegate(lVersionDelegate);
0139     lSplitter->addWidget(mVersionView);
0140     connect(lVersionDelegate, SIGNAL(openRequested(QModelIndex)), SLOT(open(QModelIndex)));
0141     connect(lVersionDelegate, SIGNAL(restoreRequested(QModelIndex)), SLOT(restore(QModelIndex)));
0142     mMergedVfsView->setFocus();
0143 
0144     //expand all levels from the top until the node has more than one child
0145     QModelIndex lIndex;
0146     forever {
0147         mMergedVfsView->expand(lIndex);
0148         if(mMergedVfsModel->rowCount(lIndex) == 1) {
0149             lIndex = mMergedVfsModel->index(0, 0, lIndex);
0150         } else {
0151             break;
0152         }
0153     }
0154     mMergedVfsView->selectionModel()->setCurrentIndex(mMergedVfsModel->index(0, 0, lIndex), QItemSelectionModel::Select);
0155     setCentralWidget(lSplitter);
0156 }
0157 
0158 void FileDigger::createSelectionView() {
0159     if(mDirOperator != nullptr) {
0160         return;
0161     }
0162     auto lLabel = new QLabel(i18n("Select location of backup archive to open."));
0163 
0164     auto lPlaces = new KFilePlacesView;
0165     lPlaces->setModel(new KFilePlacesModel);
0166 
0167     mDirOperator = new KDirOperator();
0168 #if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0)
0169     mDirOperator->setView(KFile::Tree);
0170 #else
0171     mDirOperator->setViewMode(KFile::Tree);
0172 #endif
0173     mDirOperator->setMode(KFile::Directory);
0174     mDirOperator->setEnableDirHighlighting(true);
0175     mDirOperator->setShowHiddenFiles(true);
0176 
0177     connect(lPlaces, &KFilePlacesView::urlChanged, this, &FileDigger::enterUrl);
0178 
0179     auto lOkButton = new QPushButton(this);
0180     KGuiItem::assign(lOkButton, KStandardGuiItem::ok());
0181     connect(lOkButton, &QPushButton::pressed, this, &FileDigger::checkFileWidgetPath);
0182 
0183 
0184     auto lSelectionView = new QWidget;
0185     auto lVLayout1 = new QVBoxLayout;
0186     auto lSplitter = new QSplitter;
0187 
0188     lVLayout1->addWidget(lLabel);
0189     lSplitter->addWidget(lPlaces);
0190     lSplitter->addWidget(mDirOperator);
0191     lVLayout1->addWidget(lSplitter, 1);
0192     lVLayout1->addWidget(lOkButton);
0193     lSelectionView->setLayout(lVLayout1);
0194     setCentralWidget(lSelectionView);
0195 }