|
| 1 | +/**************************************** |
| 2 | + * |
| 3 | + * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE |
| 4 | + * Copyright (C) 2020 Victor Tran |
| 5 | + * |
| 6 | + * This program is free software: you can redistribute it and/or modify |
| 7 | + * it under the terms of the GNU General Public License as published by |
| 8 | + * the Free Software Foundation, either version 3 of the License, or |
| 9 | + * (at your option) any later version. |
| 10 | + * |
| 11 | + * This program is distributed in the hope that it will be useful, |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + * GNU General Public License for more details. |
| 15 | + * |
| 16 | + * You should have received a copy of the GNU General Public License |
| 17 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | + * |
| 19 | + * *************************************/ |
| 20 | +#include "filecolumn.h" |
| 21 | +#include "ui_filecolumn.h" |
| 22 | + |
| 23 | +#include <QDir> |
| 24 | +#include <QUrl> |
| 25 | +#include <QMenu> |
| 26 | +#include <QInputDialog> |
| 27 | +#include <QClipboard> |
| 28 | +#include <resourcemanager.h> |
| 29 | +#include <tlogger.h> |
| 30 | +#include "filemodel.h" |
| 31 | +#include <tjobmanager.h> |
| 32 | +#include <ttoast.h> |
| 33 | +#include <QMessageBox> |
| 34 | +#include "hiddenfilesproxymodel.h" |
| 35 | +#include "jobs/filetransferjob.h" |
| 36 | + |
| 37 | +struct FileColumnPrivate { |
| 38 | + QUrl url; |
| 39 | + FileModel* model; |
| 40 | + HiddenFilesProxyModel* proxy; |
| 41 | +}; |
| 42 | + |
| 43 | +FileColumn::FileColumn(QUrl url, QWidget* parent) : |
| 44 | + QWidget(parent), |
| 45 | + ui(new Ui::FileColumn) { |
| 46 | + ui->setupUi(this); |
| 47 | + |
| 48 | + d = new FileColumnPrivate(); |
| 49 | + d->url = url; |
| 50 | + |
| 51 | + d->proxy = new HiddenFilesProxyModel(); |
| 52 | + ui->folderView->setModel(d->proxy); |
| 53 | + |
| 54 | + ui->folderView->setItemDelegate(new FileDelegate()); |
| 55 | + |
| 56 | + reload(); |
| 57 | +} |
| 58 | + |
| 59 | +FileColumn::~FileColumn() { |
| 60 | + delete ui; |
| 61 | + delete d; |
| 62 | +} |
| 63 | + |
| 64 | +void FileColumn::setUrl(QUrl url) { |
| 65 | + d->url = url; |
| 66 | + |
| 67 | + reload(); |
| 68 | +} |
| 69 | + |
| 70 | +void FileColumn::setSelected(QUrl url) { |
| 71 | + if (url.isValid()) { |
| 72 | + for (int i = 0; i < ui->folderView->model()->rowCount(); i++) { |
| 73 | + QModelIndex index = ui->folderView->model()->index(i, 0); |
| 74 | + QUrl checkUrl = index.data(FileModel::UrlRole).toUrl(); |
| 75 | + if (url.scheme() == checkUrl.scheme() && url.host() == checkUrl.host() && QDir::cleanPath(url.path()) == QDir::cleanPath(checkUrl.path())) { |
| 76 | + ui->folderView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); |
| 77 | + } |
| 78 | + } |
| 79 | + } else { |
| 80 | + ui->folderView->clearSelection(); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +void FileColumn::copy() { |
| 85 | + QStringList clipboardData; |
| 86 | + clipboardData.append("x-special/nautilus-clipboard"); |
| 87 | + clipboardData.append("copy"); |
| 88 | + |
| 89 | + QModelIndexList sel = ui->folderView->selectionModel()->selectedIndexes(); |
| 90 | + QList<QUrl> urls; |
| 91 | + for (QModelIndex index : sel) { |
| 92 | + urls.append(index.data(FileModel::UrlRole).toUrl()); |
| 93 | + } |
| 94 | + clipboardData.append(QUrl::toStringList(urls)); |
| 95 | + |
| 96 | + QMimeData* mimeData = new QMimeData(); |
| 97 | + mimeData->setData("text/plain", clipboardData.join("\n").toUtf8()); |
| 98 | + mimeData->setData("COMPOUND_TEXT", clipboardData.join("\n").toUtf8()); |
| 99 | + mimeData->setData("text/plain;charset=utf-8", clipboardData.join("\n").toUtf8()); |
| 100 | + mimeData->setData("application/x-thesuite-thefile-clipboardoperation", "copy"); |
| 101 | + mimeData->setUrls(urls); |
| 102 | + QApplication::clipboard()->setMimeData(mimeData); |
| 103 | +} |
| 104 | + |
| 105 | +void FileColumn::paste() { |
| 106 | + const QMimeData* data = QApplication::clipboard()->mimeData(); |
| 107 | + if (data->hasUrls()) { |
| 108 | + //Prepare a copy job |
| 109 | + FileTransferJob* job = new FileTransferJob(FileTransferJob::Copy, data->urls(), d->url, this->window()); |
| 110 | + tJobManager::trackJobDelayed(job); |
| 111 | + } |
| 112 | + |
| 113 | + for (QString format : data->formats()) { |
| 114 | + tDebug("FileColumn") << format << " -> " << QString(data->data(format)); |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +void FileColumn::newFolder() { |
| 119 | + bool ok; |
| 120 | + QString folderName = QInputDialog::getText(this, tr("New Folder"), tr("Folder name"), QLineEdit::Normal, tr("New Folder"), &ok); |
| 121 | + if (ok) { |
| 122 | + ResourceManager::mkpath(d->url.resolved(folderName)); |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +void FileColumn::moveToTrash() { |
| 127 | + QModelIndexList sel = ui->folderView->selectionModel()->selectedIndexes(); |
| 128 | + for (QModelIndex index : sel) { |
| 129 | + ResourceManager::trash(index.data(FileModel::UrlRole).toUrl()); |
| 130 | + } |
| 131 | + |
| 132 | + tToast* toast = new tToast(this); |
| 133 | + toast->setTitle(tr("Trash")); |
| 134 | + toast->setText(tr("Moved %n items to the trash", nullptr, sel.count())); |
| 135 | + connect(toast, &tToast::dismissed, toast, &tToast::deleteLater); |
| 136 | + toast->show(this->window()); |
| 137 | +} |
| 138 | + |
| 139 | +void FileColumn::deleteFile() { |
| 140 | + QModelIndexList sel = ui->folderView->selectionModel()->selectedIndexes(); |
| 141 | + if (QMessageBox::warning(this, tr("Delete %n Files", nullptr, sel.count()), tr("Delete %n files from your device? This cannot be undone.", nullptr, sel.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { |
| 142 | + for (QModelIndex index : sel) { |
| 143 | + ResourceManager::deleteFile(index.data(FileModel::UrlRole).toUrl()); |
| 144 | + } |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +void FileColumn::rename() { |
| 149 | + QModelIndexList sel = ui->folderView->selectionModel()->selectedIndexes(); |
| 150 | + if (sel.count() == 1) { |
| 151 | + QModelIndex item = sel.first(); |
| 152 | + |
| 153 | + bool ok; |
| 154 | + QString newName = QInputDialog::getText(this, tr("Rename"), tr("Enter a new name"), QLineEdit::Normal, item.data(Qt::DisplayRole).toString(), &ok); |
| 155 | + if (ok) { |
| 156 | + QUrl oldUrl = item.data(FileModel::UrlRole).toUrl(); |
| 157 | + QUrl newUrl = oldUrl.resolved(QUrl("./" + newName)); |
| 158 | + ResourceManager::move(oldUrl, newUrl); |
| 159 | + } |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +void FileColumn::reload() { |
| 164 | + d->model = new FileModel(d->url); |
| 165 | + connect(d->model, &FileModel::modelReset, this, &FileColumn::updateItems); |
| 166 | + updateItems(); |
| 167 | + |
| 168 | + d->proxy->setSourceModel(d->model); |
| 169 | + if (d->url.path() == "/") { |
| 170 | + if (d->url.scheme() == "file") { |
| 171 | + ui->folderNameLabel->setText("/"); |
| 172 | + } else { |
| 173 | + ui->folderNameLabel->setText(d->url.scheme()); |
| 174 | + } |
| 175 | + } else { |
| 176 | + ui->folderNameLabel->setText(QFileInfo(QFileInfo(d->url.path()).canonicalFilePath()).fileName()); |
| 177 | + } |
| 178 | + connect(ui->folderView->selectionModel(), &QItemSelectionModel::currentChanged, this, [ = ] { |
| 179 | + if (ui->folderView->currentIndex().isValid()) { |
| 180 | + emit navigate(ui->folderView->currentIndex().data(FileModel::UrlRole).toUrl()); |
| 181 | + } else { |
| 182 | + emit navigate(d->url); |
| 183 | + } |
| 184 | + }); |
| 185 | +} |
| 186 | + |
| 187 | +void FileColumn::updateItems() { |
| 188 | + QString error = d->model->currentError(); |
| 189 | + if (error.isEmpty()) { |
| 190 | + ui->stackedWidget->setCurrentWidget(ui->folderPage); |
| 191 | + } else { |
| 192 | + QIcon icon; |
| 193 | + if (error == QStringLiteral("error.no-items")) { |
| 194 | + ui->folderErrorTitle->setText(tr("No items here!")); |
| 195 | + ui->folderErrorText->setText(tr("This folder is empty.")); |
| 196 | + icon = QIcon(":/icons/folder-empty.svg"); |
| 197 | + } else if (error == QStringLiteral("error.not-found")) { |
| 198 | + ui->folderErrorTitle->setText(tr("Not Found")); |
| 199 | + ui->folderErrorText->setText(tr("This folder doesn't exist.")); |
| 200 | + icon = QIcon(":/icons/folder-unavailable.svg"); |
| 201 | + } else if (error == QStringLiteral("error.permission-denied")) { |
| 202 | + ui->folderErrorTitle->setText(tr("Permission Denied")); |
| 203 | + ui->folderErrorText->setText(tr("Looks like you don't have permission to view this folder.")); |
| 204 | + icon = QIcon(":/icons/folder-unavailable.svg"); |
| 205 | + } else { |
| 206 | + ui->folderErrorTitle->setText(tr("Can't view this folder")); |
| 207 | + ui->folderErrorText->setText(tr("We can't show you the contents of this folder.")); |
| 208 | + icon = QIcon(":/icons/folder-unavailable.svg"); |
| 209 | + } |
| 210 | + QImage iconImage = icon.pixmap(SC_DPI_T(QSize(128, 128), QSize)).toImage(); |
| 211 | + theLibsGlobal::tintImage(iconImage, this->palette().color(QPalette::WindowText)); |
| 212 | + ui->folderErrorIcon->setPixmap(QPixmap::fromImage(iconImage)); |
| 213 | + ui->stackedWidget->setCurrentWidget(ui->folderErrorPage); |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +void FileColumn::on_folderView_customContextMenuRequested(const QPoint& pos) { |
| 218 | + QMenu* menu = new QMenu(this); |
| 219 | + |
| 220 | + QModelIndexList sel = ui->folderView->selectionModel()->selectedIndexes(); |
| 221 | + if (sel.count() > 0) { |
| 222 | + if (sel.count() == 1) { |
| 223 | + menu->addSection(tr("For %1").arg(QLocale().quoteString(menu->fontMetrics().elidedText(sel.first().data(Qt::DisplayRole).toString(), Qt::ElideRight, SC_DPI(300))))); |
| 224 | + } else if (sel.count() > 1) { |
| 225 | + menu->addSection(tr("For %n items", nullptr, sel.count())); |
| 226 | + } |
| 227 | + |
| 228 | + menu->addAction(QIcon::fromTheme("edit-copy"), tr("Copy"), this, &FileColumn::copy); |
| 229 | + QAction* deleteAction = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Move to Trash"), this, [ = ] { |
| 230 | + if (qApp->queryKeyboardModifiers() & Qt::ShiftModifier) { |
| 231 | + deleteFile(); |
| 232 | + } else { |
| 233 | + moveToTrash(); |
| 234 | + } |
| 235 | + }); |
| 236 | + menu->addAction(QIcon::fromTheme("edit-remane"), tr("Rename"), this, &FileColumn::rename); |
| 237 | + } |
| 238 | + |
| 239 | + menu->addSection(tr("For this folder")); |
| 240 | + menu->addAction(QIcon::fromTheme("folder-new"), tr("New Folder"), this, &FileColumn::newFolder); |
| 241 | + menu->addAction(QIcon::fromTheme("edit-paste"), tr("Paste"), this, &FileColumn::paste); |
| 242 | + |
| 243 | + menu->popup(ui->folderView->mapToGlobal(pos)); |
| 244 | + connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); |
| 245 | +} |
0 commit comments