Skip to content

Commit c302b98

Browse files
committed
Initial Commit
0 parents  commit c302b98

40 files changed

+4096
-0
lines changed

application/application.pro

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
QT += core gui thelib concurrent frisbee
2+
TARGET = thefile
3+
4+
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
5+
6+
CONFIG += c++11
7+
8+
# You can make your code fail to compile if it uses deprecated APIs.
9+
# In order to do so, uncomment the following line.
10+
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
11+
12+
SOURCES += \
13+
filecolumn.cpp \
14+
filemodel.cpp \
15+
filetab.cpp \
16+
hiddenfilesproxymodel.cpp \
17+
jobs/filetransferjob.cpp \
18+
jobs/widgets/filetransferjobwidget.cpp \
19+
main.cpp \
20+
mainwindow.cpp \
21+
sidebar/devicesmodel.cpp \
22+
sidebar/sidebar.cpp
23+
24+
HEADERS += \
25+
filecolumn.h \
26+
filemodel.h \
27+
filetab.h \
28+
hiddenfilesproxymodel.h \
29+
jobs/filetransferjob.h \
30+
jobs/widgets/filetransferjobwidget.h \
31+
mainwindow.h \
32+
sidebar/devicesmodel.h \
33+
sidebar/sidebar.h
34+
35+
FORMS += \
36+
filecolumn.ui \
37+
filetab.ui \
38+
jobs/widgets/filetransferjobwidget.ui \
39+
mainwindow.ui \
40+
sidebar/sidebar.ui
41+
42+
# Default rules for deployment.
43+
qnx: target.path = /tmp/$${TARGET}/bin
44+
else: unix:!android: target.path = /opt/$${TARGET}/bin
45+
!isEmpty(target.path): INSTALLS += target
46+
47+
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../libthefile/release/ -llibthefile
48+
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../libthefile/debug/ -llibthefile
49+
else:unix: LIBS += -L$$OUT_PWD/../libthefile/ -llibthefile
50+
51+
INCLUDEPATH += $$PWD/../libthefile
52+
DEPENDPATH += $$PWD/../libthefile
53+
54+
DISTFILES += \
55+
defaults.conf
56+
57+
RESOURCES += \
58+
resources.qrc

application/defaults.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[View]
2+
HiddenFiles=false

application/filecolumn.cpp

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
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+
}

application/filecolumn.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
#ifndef FILECOLUMN_H
21+
#define FILECOLUMN_H
22+
23+
#include <QWidget>
24+
#include <QUrl>
25+
26+
namespace Ui {
27+
class FileColumn;
28+
}
29+
30+
struct FileColumnPrivate;
31+
class FileColumn : public QWidget {
32+
Q_OBJECT
33+
34+
public:
35+
explicit FileColumn(QUrl url, QWidget* parent = nullptr);
36+
~FileColumn();
37+
38+
void setUrl(QUrl url);
39+
void setSelected(QUrl url);
40+
41+
void copy();
42+
void paste();
43+
void newFolder();
44+
void moveToTrash();
45+
void deleteFile();
46+
void rename();
47+
48+
signals:
49+
void navigate(QUrl url);
50+
51+
private slots:
52+
void on_folderView_customContextMenuRequested(const QPoint& pos);
53+
54+
private:
55+
Ui::FileColumn* ui;
56+
FileColumnPrivate* d;
57+
58+
void reload();
59+
void updateItems();
60+
};
61+
62+
#endif // FILECOLUMN_H

0 commit comments

Comments
 (0)