Correction after hatstand's review

This commit is contained in:
Chocobozzz 2014-06-04 17:58:28 +02:00
parent 1fc95cb7ed
commit e484306631
11 changed files with 535 additions and 520 deletions

View File

@ -1,48 +1,23 @@
CREATE TABLE seafile_songs(
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
composer TEXT,
track INTEGER,
disc INTEGER,
bpm REAL,
year INTEGER,
genre TEXT,
comment TEXT,
compilation INTEGER,
length INTEGER,
bitrate INTEGER,
samplerate INTEGER,
directory INTEGER NOT NULL,
filename TEXT NOT NULL,
mtime INTEGER NOT NULL,
ctime INTEGER NOT NULL,
filesize INTEGER NOT NULL,
sampler INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER,
rating INTEGER,
forced_compilation_on INTEGER NOT NULL DEFAULT 0,
forced_compilation_off INTEGER NOT NULL DEFAULT 0,
effective_compilation NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
score INTEGER NOT NULL DEFAULT 0,
beginning INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
unavailable INTEGER DEFAULT 0,
effective_albumartist TEXT,
etag TEXT
);
CREATE VIRTUAL TABLE seafile_songs_fts USING fts3 (
CREATE VIRTUAL TABLE playlist_items_fts USING fts3(
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsgenre, ftscomment,
tokenize=unicode
);
DELETE FROM %allsongstables_fts;
DROP TABLE %allsongstables_fts;
ALTER TABLE %allsongstables ADD COLUMN performer TEXT;
ALTER TABLE %allsongstables ADD COLUMN grouping TEXT;
CREATE VIRTUAL TABLE %allsongstables_fts USING fts3(
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
tokenize=unicode
);
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment
FROM %allsongstables;
UPDATE schema_version SET version=45;

View File

@ -1,24 +1,3 @@
CREATE VIRTUAL TABLE playlist_items_fts USING fts3(
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsgenre, ftscomment,
tokenize=unicode
);
DELETE FROM %allsongstables_fts;
DROP TABLE %allsongstables_fts;
ALTER TABLE %allsongstables ADD COLUMN performer TEXT;
ALTER TABLE %allsongstables ADD COLUMN grouping TEXT;
CREATE VIRTUAL TABLE %allsongstables_fts USING fts3(
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
tokenize=unicode
);
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment
FROM %allsongstables;
ALTER TABLE playlists ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0;
UPDATE schema_version SET version=46;

View File

@ -1,3 +1,50 @@
ALTER TABLE playlists ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0;
CREATE TABLE seafile_songs(
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
composer TEXT,
track INTEGER,
disc INTEGER,
bpm REAL,
year INTEGER,
genre TEXT,
comment TEXT,
compilation INTEGER,
length INTEGER,
bitrate INTEGER,
samplerate INTEGER,
directory INTEGER NOT NULL,
filename TEXT NOT NULL,
mtime INTEGER NOT NULL,
ctime INTEGER NOT NULL,
filesize INTEGER NOT NULL,
sampler INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER,
rating INTEGER,
forced_compilation_on INTEGER NOT NULL DEFAULT 0,
forced_compilation_off INTEGER NOT NULL DEFAULT 0,
effective_compilation NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
score INTEGER NOT NULL DEFAULT 0,
beginning INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
unavailable INTEGER DEFAULT 0,
effective_albumartist TEXT,
etag TEXT,
performer TEXT,
grouping TEXT
);
CREATE VIRTUAL TABLE seafile_songs_fts USING fts3 (
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
tokenize=unicode
);
UPDATE schema_version SET version=47;

View File

@ -36,11 +36,11 @@
#cmakedefine HAVE_LIBPULSE
#cmakedefine HAVE_MOODBAR
#cmakedefine HAVE_QCA
#cmakedefine HAVE_SEAFILE
#cmakedefine HAVE_SKYDRIVE
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_SPOTIFY_DOWNLOADER
#cmakedefine HAVE_VK
#cmakedefine HAVE_SEAFILE
#cmakedefine HAVE_WIIMOTEDEV
#cmakedefine TAGLIB_HAS_OPUS
#cmakedefine USE_INSTALL_PREFIX

View File

@ -57,7 +57,6 @@
#include "seafileservice.h"
#endif
using smart_playlists::Generator;
using smart_playlists::GeneratorMimeData;
using smart_playlists::GeneratorPtr;
@ -99,15 +98,15 @@ InternetModel::InternetModel(Application* app, QObject* parent)
#ifdef HAVE_GOOGLE_DRIVE
AddService(new GoogleDriveService(app, this));
#endif
#ifdef HAVE_SEAFILE
AddService(new SeafileService(app, this));
#endif
#ifdef HAVE_SKYDRIVE
AddService(new SkydriveService(app, this));
#endif
#ifdef HAVE_VK
AddService(new VkService(app, this));
#endif
#ifdef HAVE_SEAFILE
AddService(new SeafileService(app, this));
#endif
invisibleRootItem()->sortChildren(0, Qt::AscendingOrder);
}
@ -230,8 +229,9 @@ QStringList InternetModel::mimeTypes() const {
QMimeData* InternetModel::mimeData(const QModelIndexList& indexes) const {
// Special case for when the user double clicked on a special item.
if (indexes.count() == 1 && indexes[0].data(Role_PlayBehaviour).toInt() ==
PlayBehaviour_DoubleClickAction) {
if (indexes.count() == 1 &&
indexes[0].data(Role_PlayBehaviour).toInt() ==
PlayBehaviour_DoubleClickAction) {
InternetModel::ServiceForIndex(indexes[0])
->ItemDoubleClicked(itemFromIndex(indexes[0]));
return nullptr;

View File

@ -10,25 +10,24 @@
#include "library/librarybackend.h"
#include "internet/oauthenticator.h"
const char* SeafileService::kServiceName = "Seafile";
const char* SeafileService::kSettingsGroup = "Seafile";
namespace {
static const char* kAuthToken = "/api2/auth-token/";
static const char* kAuthTokenUrl = "/api2/auth-token/";
static const char* kFolderItems = "/api2/repos/%1/dir/";
static const char* kListRepos = "/api2/repos/";
static const char* kFolderItemsUrl = "/api2/repos/%1/dir/";
static const char* kListReposUrl = "/api2/repos/";
static const char* kFileUrl = "/api2/repos/%1/file/";
static const char* kFileContent = "/api2/repos/%1/file/detail/";
static const char* kFileContentUrl = "/api2/repos/%1/file/detail/";
}
SeafileService::SeafileService(Application* app, InternetModel* parent)
: CloudFileService(app, parent, kServiceName, kSettingsGroup,
QIcon(":/providers/seafile.png"), SettingsDialog::Page_Seafile) {
: CloudFileService(app, parent, kServiceName, kSettingsGroup,
QIcon(":/providers/seafile.png"),
SettingsDialog::Page_Seafile) {
QSettings s;
s.beginGroup(kSettingsGroup);
access_token_ = s.value("access_token").toString();
@ -36,19 +35,19 @@ SeafileService::SeafileService(Application* app, InternetModel* parent)
QByteArray tree_bytes = s.value("tree").toByteArray();
if(!tree_bytes.isEmpty()) {
if (!tree_bytes.isEmpty()) {
QDataStream stream(&tree_bytes, QIODevice::ReadOnly);
stream >> tree_;
}
app->player()->RegisterUrlHandler(new SeafileUrlHandler(this, this));
connect(&tree_, SIGNAL(ToAdd(QString, QString, SeafileTree::Entry)), this, SLOT(AddEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToDelete(QString, QString, SeafileTree::Entry)), this, SLOT(DeleteEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToUpdate(QString, QString, SeafileTree::Entry)), this, SLOT(UpdateEntry(QString, QString, SeafileTree::Entry)));
library_updated_ = QString::null;
connect(&tree_, SIGNAL(ToAdd(QString, QString, SeafileTree::Entry)), this,
SLOT(AddEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToDelete(QString, QString, SeafileTree::Entry)), this,
SLOT(DeleteEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToUpdate(QString, QString, SeafileTree::Entry)), this,
SLOT(UpdateEntry(QString, QString, SeafileTree::Entry)));
}
bool SeafileService::has_credentials() const {
@ -67,7 +66,8 @@ QString SeafileService::access_token() const {
}
void SeafileService::AddAuthorizationHeader(QNetworkRequest* request) const {
request->setRawHeader("Authorization", QString(QString("Token ") + QString(access_token_)).toAscii());
request->setRawHeader("Authorization",
QString("Token %1").arg(access_token_).toAscii());
}
void SeafileService::ForgetCredentials() {
@ -82,8 +82,9 @@ void SeafileService::ForgetCredentials() {
server_.clear();
}
bool SeafileService::GetToken(const QString &mail, const QString &password, const QString &server) {
QUrl url(server + kAuthToken);
bool SeafileService::GetToken(const QString& mail, const QString& password,
const QString& server) {
QUrl url(server + kAuthTokenUrl);
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
@ -91,10 +92,9 @@ bool SeafileService::GetToken(const QString &mail, const QString &password, cons
url.addQueryItem("password", password);
QNetworkReply* reply = network_->post(request, url.encodedQuery());
reply->ignoreSslErrors();
WaitForSignal(reply, SIGNAL(finished()));
if(!CheckReply(&reply)) {
if (!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (GetToken)";
return false;
}
@ -107,7 +107,7 @@ bool SeafileService::GetToken(const QString &mail, const QString &password, cons
// Because the server responds "token"
access_token_ = response["token"].toString().replace("\"", "");
if(access_token_.isEmpty()) {
if (access_token_.isEmpty()) {
return false;
}
@ -122,19 +122,18 @@ bool SeafileService::GetToken(const QString &mail, const QString &password, cons
return true;
}
void SeafileService::GetLibraries() {
QUrl url(server_ + kListRepos);
QUrl url(server_ + kListReposUrl);
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
QNetworkReply *reply = network_->get(request);
reply->ignoreSslErrors();
QNetworkReply* reply = network_->get(request);
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetLibrariesFinished(QNetworkReply*)), reply);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(GetLibrariesFinished(QNetworkReply*)), reply);
}
void SeafileService::GetLibrariesFinished(QNetworkReply *reply) {
if(!CheckReply(&reply)) {
void SeafileService::GetLibrariesFinished(QNetworkReply* reply) {
if (!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (GetLibraries)";
return;
}
@ -147,13 +146,14 @@ void SeafileService::GetLibrariesFinished(QNetworkReply *reply) {
QJson::Parser parser;
QList<QVariant> repos = parser.parse(data).toList();
for (int i=0; i<repos.size(); ++i) {
for (int i = 0; i < repos.size(); ++i) {
QVariantMap repo = repos.at(i).toMap();
QString repo_name = repo["name"].toString(),
repo_id = repo["id"].toString();
repo_id = repo["id"].toString();
// One library can appear several times and we don't add encrypted libraries (not supported yet)
if(!libraries.contains(repo_id) && !repo["encrypted"].toBool()) {
// One library can appear several times and we don't add encrypted libraries
// (not supported yet)
if (!libraries.contains(repo_id) && !repo["encrypted"].toBool()) {
libraries.insert(repo_id, repo_name);
}
}
@ -161,43 +161,38 @@ void SeafileService::GetLibrariesFinished(QNetworkReply *reply) {
emit GetLibrariesFinishedSignal(libraries);
}
void SeafileService::ChangeLibrary(const QString &new_library) {
void SeafileService::ChangeLibrary(const QString& new_library) {
// Every other libraries have to be destroyed from the tree
if(new_library != "all") {
for (SeafileTree::TreeItem *library : tree_.libraries()) {
if (new_library != "all") {
for (SeafileTree::TreeItem* library : tree_.libraries()) {
if (new_library != library->entry().id()) {
DeleteEntry(library->entry().id(), "/", library->entry());
}
}
}
UpdateLibraries();
}
void SeafileService::Connect() {
if (is_authenticated()) {
UpdateLibraries();
}
else {
} else {
ShowSettingsDialog();
}
}
void SeafileService::UpdateLibraries() {
connect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString,QString>)), this,
SLOT(UpdateLibrariesInProgress(QMap<QString,QString>)));
connect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString, QString>)),
this, SLOT(UpdateLibrariesInProgress(QMap<QString, QString>)));
GetLibraries();
}
void SeafileService::UpdateLibrariesInProgress(const QMap<QString, QString> &libraries) {
disconnect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString,QString>)), this,
SLOT(UpdateLibrariesInProgress(QMap<QString,QString>)));
void SeafileService::UpdateLibrariesInProgress(
const QMap<QString, QString>& libraries) {
disconnect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString, QString>)),
this, SLOT(UpdateLibrariesInProgress(QMap<QString, QString>)));
QSettings s;
s.beginGroup(kSettingsGroup);
@ -210,7 +205,7 @@ void SeafileService::UpdateLibrariesInProgress(const QMap<QString, QString> &lib
library_updated_ = library_to_update;
if(library_to_update == "none") {
if (library_to_update == "none") {
return;
}
@ -220,43 +215,49 @@ void SeafileService::UpdateLibrariesInProgress(const QMap<QString, QString> &lib
// Need to check this library ?
if (library_to_update == "all" || library.key() == library_to_update) {
FetchAndCheckFolderItems(
SeafileTree::Entry(library.value(), library.key(), SeafileTree::Entry::LIBRARY), "/");
SeafileTree::Entry(library.value(), library.key(),
SeafileTree::Entry::LIBRARY),
"/");
}
// If not, we can destroy the library from the tree
else {
// If the library was not in the tree, it's not a problem because DeleteEntry won't do anything
// If the library was not in the tree, it's not a problem because
// DeleteEntry won't do anything
DeleteEntry(library.key(), "/",
SeafileTree::Entry(library.value(), library.key(), SeafileTree::Entry::LIBRARY));
SeafileTree::Entry(library.value(), library.key(),
SeafileTree::Entry::LIBRARY));
}
}
}
QNetworkReply* SeafileService::PrepareFetchFolderItems(const QString &library, const QString &path) {
QUrl url(server_ + QString(kFolderItems).arg(library));
QNetworkReply* SeafileService::PrepareFetchFolderItems(const QString& library,
const QString& path) {
QUrl url(server_ + QString(kFolderItemsUrl).arg(library));
url.addQueryItem("p", path);
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
QNetworkReply* reply = network_->get(request);
reply->ignoreSslErrors();
return reply;
}
void SeafileService::FetchAndCheckFolderItems(const SeafileTree::Entry &library, const QString &path) {
QNetworkReply *reply = PrepareFetchFolderItems(library.id(), path);
void SeafileService::FetchAndCheckFolderItems(const SeafileTree::Entry& library,
const QString& path) {
QNetworkReply* reply = PrepareFetchFolderItems(library.id(), path);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(FetchAndCheckFolderItemsFinished(QNetworkReply*,SeafileTree::Entry,QString)),
SLOT(FetchAndCheckFolderItemsFinished(
QNetworkReply*, SeafileTree::Entry, QString)),
reply, library, path);
}
void SeafileService::FetchAndCheckFolderItemsFinished(
QNetworkReply *reply, const SeafileTree::Entry &library, const QString &path) {
if(!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (FetchFolderItemsToList)";
QNetworkReply* reply, const SeafileTree::Entry& library,
const QString& path) {
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (FetchFolderItemsToList)";
return;
}
@ -268,33 +269,40 @@ void SeafileService::FetchAndCheckFolderItemsFinished(
QList<QVariant> variant_entries = parser.parse(data).toList();
SeafileTree::Entries entries;
for (const QVariant & e: variant_entries) {
for (const QVariant& e : variant_entries) {
QVariantMap entry = e.toMap();
SeafileTree::Entry::Type entry_type = SeafileTree::Entry::StringToType(entry["type"].toString());
SeafileTree::Entry::Type entry_type =
SeafileTree::Entry::StringToType(entry["type"].toString());
QString entry_name = entry["name"].toString();
// We just want libraries/directories and files which could be songs.
if (entry_type == SeafileTree::Entry::NONE) {
qLog(Warning) << "Type entry unknown for this entry";
}
else if (entry_type == SeafileTree::Entry::FILE && GuessMimeTypeForFile(entry_name).isNull()) {
} else if (entry_type == SeafileTree::Entry::FILE &&
GuessMimeTypeForFile(entry_name).isNull()) {
continue;
}
entries.append(SeafileTree::Entry(entry_name, entry["id"].toString(), entry_type));
entries.append(
SeafileTree::Entry(entry_name, entry["id"].toString(), entry_type));
}
tree_.CheckEntries(entries, library, path);
}
void SeafileService::AddRecursivelyFolderItems(const QString &library, const QString &path) {
QNetworkReply *reply = PrepareFetchFolderItems(library, path);
NewClosure(reply, SIGNAL(finished()), this, SLOT(AddRecursivelyFolderItemsFinished(QNetworkReply*,QString,QString)), reply, library, path);
void SeafileService::AddRecursivelyFolderItems(const QString& library,
const QString& path) {
QNetworkReply* reply = PrepareFetchFolderItems(library, path);
NewClosure(
reply, SIGNAL(finished()), this,
SLOT(AddRecursivelyFolderItemsFinished(QNetworkReply*, QString, QString)),
reply, library, path);
}
void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply, const QString &library, const QString &path) {
if(!CheckReply(&reply)) {
void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply,
const QString& library,
const QString& path) {
if (!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (FetchFolderItems)";
return;
}
@ -307,36 +315,39 @@ void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply, con
for (const QVariant& e : entries) {
QVariantMap entry_map = e.toMap();
SeafileTree::Entry::Type entry_type = SeafileTree::Entry::StringToType(entry_map["type"].toString());
SeafileTree::Entry::Type entry_type =
SeafileTree::Entry::StringToType(entry_map["type"].toString());
QString entry_name = entry_map["name"].toString();
// We just want libraries/directories and files which could be songs.
if (entry_type == SeafileTree::Entry::NONE) {
qLog(Warning) << "Type entry unknown for this entry";
}
else if (entry_type == SeafileTree::Entry::FILE && GuessMimeTypeForFile(entry_name).isNull()) {
} else if (entry_type == SeafileTree::Entry::FILE &&
GuessMimeTypeForFile(entry_name).isNull()) {
continue;
}
SeafileTree::Entry entry(entry_name, entry_map["id"].toString(), entry_type);
SeafileTree::Entry entry(entry_name, entry_map["id"].toString(),
entry_type);
// If AddEntry was not successful we stop
// It could happen when the user changes the library to update while an update was in progress
if(!tree_.AddEntry(library, path, entry)) {
// It could happen when the user changes the library to update while an
// update was in progress
if (!tree_.AddEntry(library, path, entry)) {
return;
}
if (entry.is_dir()) {
AddRecursivelyFolderItems(library, path + entry.name() + "/");
}
else {
} else {
MaybeAddFileEntry(entry.name(), library, path);
}
}
}
QNetworkReply *SeafileService::PrepareFetchContentForFile(const QString &library, const QString &filepath) {
QUrl content_url(server_ + QString(kFileContent).arg(library));
QNetworkReply* SeafileService::PrepareFetchContentForFile(
const QString& library, const QString& filepath) {
QUrl content_url(server_ + QString(kFileContentUrl).arg(library));
content_url.addQueryItem("p", filepath);
QNetworkRequest request(content_url);
@ -346,24 +357,26 @@ QNetworkReply *SeafileService::PrepareFetchContentForFile(const QString &library
return reply;
}
void SeafileService::MaybeAddFileEntry(const QString &entry_name, const QString &library, const QString &path) {
void SeafileService::MaybeAddFileEntry(const QString& entry_name,
const QString& library,
const QString& path) {
QString mime_type = GuessMimeTypeForFile(entry_name);
if(mime_type.isNull())
return;
if (mime_type.isNull()) return;
// Get the details of the entry
QNetworkReply *reply = PrepareFetchContentForFile(library, path + entry_name);
QNetworkReply* reply = PrepareFetchContentForFile(library, path + entry_name);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(MaybeAddFileEntryInProgress(QNetworkReply*,QString,QString,QString)),
SLOT(MaybeAddFileEntryInProgress(QNetworkReply*, QString, QString,
QString)),
reply, library, path, mime_type);
}
void SeafileService::MaybeAddFileEntryInProgress(
QNetworkReply *reply, const QString &library, const QString &path, const QString &mime_type) {
if(!CheckReply(&reply)) {
void SeafileService::MaybeAddFileEntryInProgress(QNetworkReply* reply,
const QString& library,
const QString& path,
const QString& mime_type) {
if (!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (MaybeAddFileEntry)";
return;
}
@ -387,12 +400,16 @@ void SeafileService::MaybeAddFileEntryInProgress(
song.set_title(entry_detail_map["name"].toString());
// Get the download url of the entry
reply = PrepareFetchContentUrlForFile(library, path + entry_detail_map["name"].toString());
NewClosure(reply, SIGNAL(finished()), this, SLOT(FetchContentUrlForFileFinished(QNetworkReply*, Song, QString)), reply, song, mime_type);
reply = PrepareFetchContentUrlForFile(
library, path + entry_detail_map["name"].toString());
NewClosure(
reply, SIGNAL(finished()), this,
SLOT(FetchContentUrlForFileFinished(QNetworkReply*, Song, QString)),
reply, song, mime_type);
}
QNetworkReply* SeafileService::PrepareFetchContentUrlForFile(const QString &library, const QString &filepath) {
QNetworkReply* SeafileService::PrepareFetchContentUrlForFile(
const QString& library, const QString& filepath) {
QUrl content_url(server_ + QString(kFileUrl).arg(library));
content_url.addQueryItem("p", filepath);
@ -403,10 +420,12 @@ QNetworkReply* SeafileService::PrepareFetchContentUrlForFile(const QString &libr
return reply;
}
void SeafileService::FetchContentUrlForFileFinished(QNetworkReply* reply, const Song &song, const QString &mime_type) {
if(!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (FetchContentUrlForFile)";
void SeafileService::FetchContentUrlForFileFinished(QNetworkReply* reply,
const Song& song,
const QString& mime_type) {
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (FetchContentUrlForFile)";
return;
}
@ -415,17 +434,18 @@ void SeafileService::FetchContentUrlForFileFinished(QNetworkReply* reply, const
// Because server response is "http://..."
QString real_url = QString(reply->readAll()).replace("\"", "");
MaybeAddFileToDatabase(song, mime_type, QUrl(real_url), QString("Token %1").arg(access_token_));
MaybeAddFileToDatabase(song, mime_type, QUrl(real_url),
QString("Token %1").arg(access_token_));
}
QUrl SeafileService::GetStreamingUrlFromSongId(const QString &library, const QString &filepath) {
QUrl SeafileService::GetStreamingUrlFromSongId(const QString& library,
const QString& filepath) {
QNetworkReply* reply = PrepareFetchContentUrlForFile(library, filepath);
reply->ignoreSslErrors();
WaitForSignal(reply, SIGNAL(finished()));
if(!CheckReply(&reply)) {
qLog(Warning) << "Something wrong with the reply... (GetStreamingUrlFromSongId)";
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (GetStreamingUrlFromSongId)";
return QUrl("");
}
reply->deleteLater();
@ -435,115 +455,120 @@ QUrl SeafileService::GetStreamingUrlFromSongId(const QString &library, const QSt
return QUrl(response);
}
void SeafileService::AddEntry(const QString &library, const QString &path, const SeafileTree::Entry &entry) {
void SeafileService::AddEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
if (entry.is_library()) {
tree_.AddLibrary(entry.name(), entry.id());
AddRecursivelyFolderItems(library, "/");
}
else {
} else {
// If AddEntry was not successful we stop
// It could happen when the user changes the library to update while an update was in progress
if(!tree_.AddEntry(library, path, entry)) {
// It could happen when the user changes the library to update while an
// update was in progress
if (!tree_.AddEntry(library, path, entry)) {
return;
}
if (entry.is_file()) {
MaybeAddFileEntry(entry.name(), library, path);
}
else {
AddRecursivelyFolderItems(library, path + entry.name() + "/");
} else {
AddRecursivelyFolderItems(library, path + entry.name() + "/");
}
}
}
void SeafileService::UpdateEntry(const QString & library, const QString &path, const SeafileTree::Entry &entry) {
void SeafileService::UpdateEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
if (entry.is_file()) {
DeleteEntry(library, path, entry);
AddEntry(library, path, entry);
}
else {
} else {
QString entry_path = path;
if(entry.is_dir()) {
if (entry.is_dir()) {
entry_path += entry.name() + "/";
}
FetchAndCheckFolderItems(SeafileTree::Entry("", library, SeafileTree::Entry::LIBRARY),
entry_path);
FetchAndCheckFolderItems(
SeafileTree::Entry("", library, SeafileTree::Entry::LIBRARY),
entry_path);
}
}
void SeafileService::DeleteEntry(const QString &library, const QString &path, const SeafileTree::Entry &entry) {
void SeafileService::DeleteEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
// For the QPair -> 1 : path, 2 : entry
QList<QPair<QString, SeafileTree::Entry>> files_to_delete;
if(entry.is_library()) {
SeafileTree::TreeItem *item = tree_.FindLibrary(library);
if (entry.is_library()) {
SeafileTree::TreeItem* item = tree_.FindLibrary(library);
files_to_delete = tree_.GetRecursiveFilesOfDir("/", item);
tree_.DeleteLibrary(library);
}
else {
if(entry.is_dir()) {
SeafileTree::TreeItem *item = tree_.FindFromAbsolutePath(library, path + entry.name() + "/");
files_to_delete = tree_.GetRecursiveFilesOfDir(path + entry.name() + "/", item);
}
else {
} else {
if (entry.is_dir()) {
SeafileTree::TreeItem* item =
tree_.FindFromAbsolutePath(library, path + entry.name() + "/");
files_to_delete =
tree_.GetRecursiveFilesOfDir(path + entry.name() + "/", item);
} else {
files_to_delete.append(qMakePair(path, entry));
}
if(!tree_.DeleteEntry(library, path, entry)) {
if (!tree_.DeleteEntry(library, path, entry)) {
return;
}
}
// Delete songs from the library of Clementine
for (const QPair<QString, SeafileTree::Entry> &file_to_delete : files_to_delete) {
if(!GuessMimeTypeForFile(file_to_delete.second.name())
.isEmpty()) {
QUrl song_url("seafile:/" + library + file_to_delete.first + file_to_delete.second.name());
for (const QPair<QString, SeafileTree::Entry>& file_to_delete :
files_to_delete) {
if (!GuessMimeTypeForFile(file_to_delete.second.name()).isEmpty()) {
QUrl song_url("seafile:/" + library + file_to_delete.first +
file_to_delete.second.name());
Song song = library_backend_->GetSongByUrl(song_url);
if (song.is_valid()) {
library_backend_->DeleteSongs(SongList() << song);
}
else {
qLog(Warning) << "Can't delete song from the Clementine's library : " << song_url;
} else {
qLog(Warning) << "Can't delete song from the Clementine's library : "
<< song_url;
}
}
}
}
bool SeafileService::CheckReply(QNetworkReply **reply) {
if (!(*reply)) {
bool SeafileService::CheckReply(QNetworkReply** reply, int tries) {
if (!(*reply) || tries > 10) {
return false;
}
QVariant status_code_variant = (*reply)->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant status_code_variant =
(*reply)->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (status_code_variant.isValid()) {
int status_code = status_code_variant.toInt();
if (status_code == NO_ERROR) {
return true;
}
else if (status_code == TOO_MANY_REQUESTS) {
} else if (status_code == TOO_MANY_REQUESTS) {
qLog(Debug) << "Too many requests, wait...";
// If there are too many requests, we just wait
int seconds_to_wait;
if ((*reply)->hasRawHeader("X-Throttle-Wait-Seconds")) {
seconds_to_wait =
((*reply)->rawHeader("X-Throttle-Wait-Seconds").toInt() + 1) * 1000;
} else {
seconds_to_wait = pow(tries, 2) * 1000;
}
QTimer timer;
timer.start(10000);
timer.start(seconds_to_wait);
WaitForSignal(&timer, SIGNAL(timeout()));
(*reply)->deleteLater();
// And we execute the reply again
// We execute the reply again
*reply = network_->get((*reply)->request());
WaitForSignal(*reply, SIGNAL(finished()));
return CheckReply(reply);
return CheckReply(reply, ++tries);
}
}
@ -552,7 +577,6 @@ bool SeafileService::CheckReply(QNetworkReply **reply) {
return false;
}
SeafileService::~SeafileService() {
// Save the tree !
QSettings s;
@ -563,6 +587,4 @@ SeafileService::~SeafileService() {
stream << tree_;
s.setValue("tree", tree_byte);
}

View File

@ -3,18 +3,23 @@
*
* Help :
* - The "path" variable has to end with "/".
* If we want to specify a filepath, the name of the variable has to be... filepath :)
* - Seafile stores files in libraries (or repositories) so variable with the name "library" corresponds to the
* If we want to specify a filepath, the name of the variable has to be...
*filepath :)
* - Seafile stores files in libraries (or repositories) so variable with the
*name "library" corresponds to the
* Seafile library, not to the Clementine library
* - The authentification of Seafile's API is simply a token (REST API)
* - Seafile stores a hash for each entry. This hash changes when the entry is modified.
* This is the reason why we just have to compare the local hash with the server
* - Seafile stores a hash for each entry. This hash changes when the entry is
*modified.
* This is the reason why we just have to compare the local hash with the
*server
* hash of a directory (for example) to know if the directory was modified.
* Libraries are an exception : Seafile stores a hash that never changes.
* This hash is called "id".
*
* Todo :
* - Add ssl certificate exception (for people who generate their own certificate on their Seafile server
* - Add ssl certificate exception (for people who generate their own
*certificate on their Seafile server
* - Stop Tagreader when user changes the library
*/
@ -22,24 +27,20 @@
#define SEAFILESERVICE_H
#include "cloudfileservice.h"
#include "seafiletree.h"
#include <QDateTime>
#include <QMutex>
#include "seafiletree.h"
class QNetworkReply;
class QNetworkRequest;
// Interface between the seafile server and Clementine
class SeafileService : public CloudFileService {
Q_OBJECT
Q_OBJECT
public:
enum ApiError {
NO_ERROR = 200,
NOT_FOUND = 404,
TOO_MANY_REQUESTS = 429
};
enum ApiError { NO_ERROR = 200, NOT_FOUND = 404, TOO_MANY_REQUESTS = 429 };
SeafileService(Application* app, InternetModel* parent);
~SeafileService();
@ -48,12 +49,14 @@ class SeafileService : public CloudFileService {
static const char* kSettingsGroup;
virtual bool has_credentials() const;
QUrl GetStreamingUrlFromSongId(const QString &library, const QString &filepath);
QUrl GetStreamingUrlFromSongId(const QString& library,
const QString& filepath);
// Get the token for an user (simple rest api)
bool GetToken(const QString &mail, const QString &password, const QString &server);
bool GetToken(const QString& mail, const QString& password,
const QString& server);
// Get all the libraries available for the user. Will emit a signal
void GetLibraries();
void ChangeLibrary(const QString &new_library);
void ChangeLibrary(const QString& new_library);
public slots:
void Connect();
@ -66,25 +69,35 @@ signals:
private slots:
// Will emit the signal
void GetLibrariesFinished(QNetworkReply *reply);
void GetLibrariesFinished(QNetworkReply* reply);
void FetchAndCheckFolderItemsFinished(QNetworkReply *reply, const SeafileTree::Entry &library, const QString &path);
void FetchAndCheckFolderItemsFinished(QNetworkReply* reply,
const SeafileTree::Entry& library,
const QString& path);
// Add recursively the content of a folder from a library
void AddRecursivelyFolderItemsFinished(QNetworkReply *reply, const QString &library, const QString &path);
void AddRecursivelyFolderItemsFinished(QNetworkReply* reply,
const QString& library,
const QString& path);
// Get the url and try to add the file to the database
void FetchContentUrlForFileFinished(QNetworkReply* reply, const Song &song, const QString &mime_type);
void FetchContentUrlForFileFinished(QNetworkReply* reply, const Song& song,
const QString& mime_type);
// Add the entry to the tree and maybe add this entry to the database
void AddEntry(const QString &library, const QString &path, const SeafileTree::Entry &entry);
void AddEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
// Update the entry or check recursively the directories
void UpdateEntry(const QString &library, const QString &path, const SeafileTree::Entry &entry);
// Delete the entry (eventually the files of its subdir) of the tree and the database
void DeleteEntry(const QString &library, const QString &path, const SeafileTree::Entry &entry);
void UpdateEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
// Delete the entry (eventually the files of its subdir) of the tree and the
// database
void DeleteEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
void UpdateLibrariesInProgress(const QMap<QString, QString> &libraries);
void UpdateLibrariesInProgress(const QMap<QString, QString>& libraries);
void MaybeAddFileEntryInProgress(QNetworkReply *reply, const QString &library,
const QString &path, const QString &mime_type);
void MaybeAddFileEntryInProgress(QNetworkReply* reply, const QString& library,
const QString& path,
const QString& mime_type);
private:
QString access_token() const;
@ -94,19 +107,24 @@ signals:
void UpdateLibraries();
void FetchAndCheckFolderItems(const SeafileTree::Entry &library, const QString &path);
void AddRecursivelyFolderItems(const QString &library, const QString &path);
void FetchAndCheckFolderItems(const SeafileTree::Entry& library,
const QString& path);
void AddRecursivelyFolderItems(const QString& library, const QString& path);
QNetworkReply* PrepareFetchFolderItems(const QString &library, const QString &path);
QNetworkReply* PrepareFetchContentForFile(const QString &library, const QString &filepath);
QNetworkReply* PrepareFetchContentUrlForFile(const QString &library, const QString &filepath);
QNetworkReply* PrepareFetchFolderItems(const QString& library,
const QString& path);
QNetworkReply* PrepareFetchContentForFile(const QString& library,
const QString& filepath);
QNetworkReply* PrepareFetchContentUrlForFile(const QString& library,
const QString& filepath);
void MaybeAddFileEntry(const QString &entry_name, const QString &library, const QString &path);
void MaybeAddFileEntry(const QString& entry_name, const QString& library,
const QString& path);
// False if not 200 or 429
// If 429 (too many requests), re execute the request and put the reply in the argument
bool CheckReply(QNetworkReply **reply);
// If 429 (too many requests), re execute the request and put the reply in the
// argument
bool CheckReply(QNetworkReply** reply, int tries = 1);
SeafileTree tree_;
QString access_token_;

View File

@ -15,13 +15,7 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "seafileservice.h"
#include "seafilesettingspage.h"
#include "internetmodel.h"
#include "core/logging.h"
#include "core/network.h"
#include "ui_seafilesettingspage.h"
#include "ui/iconloader.h"
#include <QMessageBox>
#include <QNetworkReply>
@ -29,10 +23,17 @@
#include <QSettings>
#include <QtDebug>
#include "seafileservice.h"
#include "internetmodel.h"
#include "core/logging.h"
#include "core/network.h"
#include "ui_seafilesettingspage.h"
#include "ui/iconloader.h"
SeafileSettingsPage::SeafileSettingsPage(SettingsDialog* dialog)
: SettingsPage(dialog),
ui_(new Ui_SeafileSettingsPage),
service_(InternetModel::Service<SeafileService>()) {
: SettingsPage(dialog),
ui_(new Ui_SeafileSettingsPage),
service_(InternetModel::Service<SeafileService>()) {
ui_->setupUi(this);
setWindowIcon(QIcon(":/providers/seafile.png"));
@ -47,12 +48,11 @@ SeafileSettingsPage::SeafileSettingsPage(SettingsDialog* dialog)
ui_->library_box->addItem("None", "none");
connect(service_, SIGNAL(GetLibrariesFinishedSignal(QMap<QString,QString>)), this,
SLOT(GetLibrariesFinished(QMap<QString,QString>)));
connect(service_, SIGNAL(GetLibrariesFinishedSignal(QMap<QString, QString>)),
this, SLOT(GetLibrariesFinished(QMap<QString, QString>)));
}
SeafileSettingsPage::~SeafileSettingsPage() { delete ui_; }
SeafileSettingsPage::~SeafileSettingsPage() {}
void SeafileSettingsPage::Load() {
QSettings s;
@ -62,23 +62,26 @@ void SeafileSettingsPage::Load() {
ui_->mail->setText(s.value("mail").toString());
if (!ui_->server->text().isEmpty() && !ui_->mail->text().isEmpty()) {
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn, ui_->mail->text());
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn,
ui_->mail->text());
// If there is more than "none" library, that means that we already got the libraries
if(ui_->library_box->count() <= 1) {
service_->GetLibraries();
// If there is more than "none" library, that means that we already got the
// libraries
if (ui_->library_box->count() <= 1) {
service_->GetLibraries();
}
}
}
void SeafileSettingsPage::GetLibrariesFinished(QMap<QString, QString> libraries) {
void SeafileSettingsPage::GetLibrariesFinished(
const QMap<QString, QString>& libraries) {
ui_->library_box->clear();
ui_->library_box->addItem("None", "none");
ui_->library_box->addItem("All (could be slow)", "all");
// key : library's id, value : library's name
QMapIterator <QString, QString> library(libraries);
while(library.hasNext()) {
QMapIterator<QString, QString> library(libraries);
while (library.hasNext()) {
library.next();
ui_->library_box->addItem(library.value(), library.key());
}
@ -93,9 +96,9 @@ void SeafileSettingsPage::GetLibrariesFinished(QMap<QString, QString> libraries)
}
}
void SeafileSettingsPage::Save() {
QString id = ui_->library_box->itemData(ui_->library_box->currentIndex()).toString();
QString id =
ui_->library_box->itemData(ui_->library_box->currentIndex()).toString();
QSettings s;
s.beginGroup(SeafileService::kSettingsGroup);
@ -108,21 +111,21 @@ void SeafileSettingsPage::Save() {
service_->ChangeLibrary(id);
}
void SeafileSettingsPage::Login() {
ui_->login_button->setEnabled(false);
if(service_->GetToken(ui_->mail->text(), ui_->password->text(), ui_->server->text())) {
if (service_->GetToken(ui_->mail->text(), ui_->password->text(),
ui_->server->text())) {
Save();
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn, ui_->mail->text());
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn,
ui_->mail->text());
service_->GetLibraries();
}
else {
} else {
ui_->login_button->setEnabled(true);
QMessageBox::warning(this, tr("Unable to connect"), tr("Unable to connect"));
QMessageBox::warning(this, tr("Unable to connect"),
tr("Unable to connect"));
}
}
@ -145,6 +148,4 @@ void SeafileSettingsPage::Logout() {
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedOut);
ui_->login_button->setEnabled(true);
}

View File

@ -40,12 +40,11 @@ class SeafileSettingsPage : public SettingsPage {
void Login();
void Logout();
// Map -> key : library's id, value : library's name
void GetLibrariesFinished(QMap<QString, QString> libraries);
void GetLibrariesFinished(const QMap<QString, QString>& libraries);
private:
Ui_SeafileSettingsPage* ui_;
std::unique_ptr<Ui_SeafileSettingsPage> ui_;
SeafileService* service_;
};
#endif // SEAFILESETTINGSPAGE_H

View File

@ -3,32 +3,32 @@
#include <QStringList>
#include <QRegExp>
#include <QDir>
#include "core/logging.h"
/* ############################## SeafileTree ############################## */
SeafileTree::SeafileTree() {}
SeafileTree::SeafileTree() { }
SeafileTree::SeafileTree(const SeafileTree& copy) : SeafileTree() {
libraries_ = copy.libraries();
}
SeafileTree::SeafileTree(const SeafileTree &copy) : SeafileTree()
{ libraries_ = copy.libraries(); }
QList<SeafileTree::TreeItem*> SeafileTree::libraries() const { return libraries_; }
QList<SeafileTree::TreeItem*> SeafileTree::libraries() const {
return libraries_;
}
void SeafileTree::Print() const {
qLog(Debug) << "library count : " << libraries_.count();
for (TreeItem *item : libraries_) {
for (TreeItem* item : libraries_) {
qLog(Debug) << "library : " << item->ToString(1);
}
}
void SeafileTree::AddLibrary(const QString &name, const QString &id) {
libraries_.append(
new TreeItem(
Entry(name, id, Entry::Type::LIBRARY)));
void SeafileTree::AddLibrary(const QString& name, const QString& id) {
libraries_.append(new TreeItem(Entry(name, id, Entry::Type::LIBRARY)));
}
void SeafileTree::DeleteLibrary(const QString &id) {
void SeafileTree::DeleteLibrary(const QString& id) {
for (int i = 0; i < libraries_.size(); ++i) {
if (libraries_.at(i)->entry().id() == id) {
libraries_.removeAt(i);
@ -37,17 +37,17 @@ void SeafileTree::DeleteLibrary(const QString &id) {
}
}
bool SeafileTree::AddEntry(const QString& library, const QString& path,
const Entry& entry) {
TreeItem* dir_node = FindFromAbsolutePath(library, path);
bool SeafileTree::AddEntry(const QString& library, const QString &path, const Entry &entry) {
TreeItem *dir_node = FindFromAbsolutePath(library, path);
if(!dir_node) {
if (!dir_node) {
qLog(Warning) << "Can't find the path...";
return false;
}
// If it is not a dir or a library we can't add an entry...
if(!dir_node->entry().is_dir() && !dir_node->entry().is_library()) {
if (!dir_node->entry().is_dir() && !dir_node->entry().is_library()) {
qLog(Warning) << "This is not a dir or a file...";
return false;
}
@ -57,27 +57,28 @@ bool SeafileTree::AddEntry(const QString& library, const QString &path, const En
return true;
}
void SeafileTree::CheckEntries(const Entries &server_entries, const Entry &library, const QString &path) {
TreeItem *local_item = FindFromAbsolutePath(library.id(), path);
void SeafileTree::CheckEntries(const Entries& server_entries,
const Entry& library, const QString& path) {
TreeItem* local_item = FindFromAbsolutePath(library.id(), path);
// Don't know the path
// Have to add all entries
if(!local_item) {
if (!local_item) {
emit ToAdd(library.id(), path, library);
return;
}
Entries local_entries = local_item->childs_entry();
Entries local_entries = local_item->children_entries();
for (const Entry &server_entry : server_entries) {
for (const Entry& server_entry : server_entries) {
bool is_in_tree = false;
for (int i=0; i<local_entries.size(); ++i) {
for (int i = 0; i < local_entries.size(); ++i) {
Entry local_entry = local_entries.at(i);
// We found the entry in the tree
if (local_entry.name() == server_entry.name() && local_entry.type() == server_entry.type()) {
if (local_entry.name() == server_entry.name() &&
local_entry.type() == server_entry.type()) {
is_in_tree = true;
// Need to update
@ -97,29 +98,29 @@ void SeafileTree::CheckEntries(const Entries &server_entries, const Entry &libra
}
// Need to add the entry
if (!is_in_tree){
if (!is_in_tree) {
emit ToAdd(library.id(), path, server_entry);
}
}
// Each entry in this list corresponds to an entry that we didn't proceed
// So if the entry is in the tree but not on the server : we have to delete it
for (const Entry &local_entry : local_entries) {
for (const Entry& local_entry : local_entries) {
emit ToDelete(library.id(), path, local_entry);
}
}
SeafileTree::TreeItem* SeafileTree::FindLibrary(const QString &library) {
for (TreeItem *item : libraries_) {
if (item->entry().id() == library)
return item;
SeafileTree::TreeItem* SeafileTree::FindLibrary(const QString& library) {
for (TreeItem* item : libraries_) {
if (item->entry().id() == library) return item;
}
return nullptr;
}
SeafileTree::TreeItem* SeafileTree::FindFromAbsolutePath(const QString &library, const QString &path) {
TreeItem *node_item = FindLibrary(library);
SeafileTree::TreeItem* SeafileTree::FindFromAbsolutePath(const QString& library,
const QString& path) {
TreeItem* node_item = FindLibrary(library);
if (!node_item) {
return nullptr;
@ -127,10 +128,10 @@ SeafileTree::TreeItem* SeafileTree::FindFromAbsolutePath(const QString &library,
QStringList path_parts = path.split("/", QString::SkipEmptyParts);
for (const QString &part : path_parts) {
for (const QString& part : path_parts) {
node_item = node_item->FindChild(part);
if(!node_item) {
if (!node_item) {
break;
}
}
@ -138,25 +139,27 @@ SeafileTree::TreeItem* SeafileTree::FindFromAbsolutePath(const QString &library,
return node_item;
}
bool SeafileTree::DeleteEntry(const QString &library, const QString &path, const Entry &entry) {
TreeItem *item_parent = FindFromAbsolutePath(library, path);
bool SeafileTree::DeleteEntry(const QString& library, const QString& path,
const Entry& entry) {
TreeItem* item_parent = FindFromAbsolutePath(library, path);
if(!item_parent) {
qLog(Debug) << "Unable to delete " << library + path + entry.name()
if (!item_parent) {
qLog(Debug) << "Unable to delete " << library + path + entry.name()
<< " : path " << path << " not found";
return false;
}
TreeItem *item_entry = item_parent->FindChild(entry.name());
TreeItem* item_entry = item_parent->FindChild(entry.name());
if(!item_entry) {
qLog(Debug) << "Unable to delete " << library + path + entry.name()
if (!item_entry) {
qLog(Debug) << "Unable to delete " << library + path + entry.name()
<< " : entry " << entry.name() << " from path not found";
return false;
}
if(!item_parent->RemoveChild(item_entry)) {
qLog(Debug) << "Can't remove " << item_entry->entry().name() << " from parent";
if (!item_parent->RemoveChild(item_entry)) {
qLog(Debug) << "Can't remove " << item_entry->entry().name()
<< " from parent";
return false;
}
@ -170,25 +173,24 @@ void SeafileTree::Clear() {
libraries_.clear();
}
QList<QPair<QString, SeafileTree::Entry>> SeafileTree::GetRecursiveFilesOfDir(const QString &path, const TreeItem *item) {
QList<QPair<QString, SeafileTree::Entry>> SeafileTree::GetRecursiveFilesOfDir(
const QString& path, const TreeItem* item) {
// key = path, value = entry
QList<QPair<QString, Entry>> files;
if(!item) {
if (!item) {
return files;
}
if(item->entry().is_file()) {
if (item->entry().is_file()) {
files.append(qMakePair(path, item->entry()));
}
// Get files of the dir
else {
for (TreeItem *child_item : item->childs()) {
if(child_item->entry().is_file()) {
for (TreeItem* child_item : item->children()) {
if (child_item->entry().is_file()) {
files.append(qMakePair(path, child_item->entry()));
}
else {
} else {
QString name = child_item->entry().name() + "/";
files.append(GetRecursiveFilesOfDir(path + name, child_item));
}
@ -200,38 +202,25 @@ QList<QPair<QString, SeafileTree::Entry>> SeafileTree::GetRecursiveFilesOfDir(co
SeafileTree::~SeafileTree() {}
/* ################################# Entry ################################# */
SeafileTree::Entry::Entry()
: Entry("", "", Type::FILE) {}
SeafileTree::Entry::Entry(const SeafileTree::Entry &entry)
: Entry(entry.name(), entry.id(), entry.type()) {}
SeafileTree::Entry::Entry(const QString& name, const QString& id, const Type& type) {
name_ = name;
id_ = id;
type_ = type;
}
QString SeafileTree::Entry::name() const { return name_; }
QString SeafileTree::Entry::id() const { return id_; }
SeafileTree::Entry::Type SeafileTree::Entry::type() const { return type_; }
bool SeafileTree::Entry::is_dir() const { return (type_ == Entry::DIR); }
bool SeafileTree::Entry::is_file() const { return (type_ == Entry::FILE); }
bool SeafileTree::Entry::is_library() const { return (type_ == Entry::LIBRARY); }
void SeafileTree::Entry::set_name(const QString &name) { name_ = name; }
void SeafileTree::Entry::set_id(const QString &id) { id_ = id; }
void SeafileTree::Entry::set_type(const Type &type) { type_ = type; }
bool SeafileTree::Entry::is_library() const {
return (type_ == Entry::LIBRARY);
}
void SeafileTree::Entry::set_name(const QString& name) { name_ = name; }
void SeafileTree::Entry::set_id(const QString& id) { id_ = id; }
void SeafileTree::Entry::set_type(const Type& type) { type_ = type; }
QString SeafileTree::Entry::ToString() const {
return "name : " + name_ + " id : " + id_ + " type : " + TypeToString(type_);
}
SeafileTree::Entry& SeafileTree::Entry::operator =(const Entry &entry) {
SeafileTree::Entry& SeafileTree::Entry::operator=(const Entry& entry) {
name_ = entry.name();
id_ = entry.id();
type_ = entry.type();
@ -239,90 +228,81 @@ SeafileTree::Entry& SeafileTree::Entry::operator =(const Entry &entry) {
return *this;
}
bool SeafileTree::Entry::operator ==(const Entry &a) const {
if(a.name() == name() && a.id() == id() && a.type() == type())
return true;
return false;
bool SeafileTree::Entry::operator==(const Entry& a) const {
return a.name() == name() && a.id() == id() && a.type() == type();
}
bool SeafileTree::Entry::operator !=(const Entry &a) const {
return !(operator ==(a));
bool SeafileTree::Entry::operator!=(const Entry& a) const {
return !(operator==(a));
}
SeafileTree::Entry::~Entry() {}
QString SeafileTree::Entry::TypeToString(const Type &type) {
if (type == DIR) {
return "dir";
QString SeafileTree::Entry::TypeToString(const Type& type) {
switch (type) {
case DIR:
return "dir";
case FILE:
return "file";
case LIBRARY:
return "library";
default:
return QString::null;
}
else if (type == FILE) {
return "file";
}
else if (type == LIBRARY) {
return "library";
}
return QString::null;
}
SeafileTree::Entry::Type SeafileTree::Entry::StringToType(const QString &type) {
if (type == "dir") {
return DIR;
}
else if (type == "file") {
return FILE;
}
else if (type == "library") {
return LIBRARY;
}
SeafileTree::Entry::Type SeafileTree::Entry::StringToType(const QString& type) {
if (type == "dir") {
return DIR;
} else if (type == "file") {
return FILE;
} else if (type == "library") {
return LIBRARY;
}
return NONE;
return NONE;
}
/* ############################### TreeItem ############################### */
SeafileTree::TreeItem::TreeItem() { entry_ = Entry(); }
SeafileTree::TreeItem::TreeItem(const TreeItem &copy) { entry_ = copy.entry(); }
SeafileTree::TreeItem::TreeItem(const Entry &entry) { entry_ = entry; }
SeafileTree::TreeItem::TreeItem(const Entry &entry, QList<TreeItem *> *childs) {
entry_ = entry;
childs_ = *childs;
}
SeafileTree::Entries SeafileTree::TreeItem::childs_entry() const {
SeafileTree::Entries SeafileTree::TreeItem::children_entries() const {
Entries entries;
for (TreeItem *item : childs_) {
for (TreeItem* item : children_) {
entries.append(Entry(item->entry()));
}
return entries;
}
SeafileTree::TreeItem* SeafileTree::TreeItem::child(int i) const { return childs_.at(i); }
QList<SeafileTree::TreeItem*> SeafileTree::TreeItem::childs() const { return childs_; }
SeafileTree::TreeItem* SeafileTree::TreeItem::child(int i) const {
return children_.at(i);
}
QList<SeafileTree::TreeItem*> SeafileTree::TreeItem::children() const {
return children_;
}
SeafileTree::Entry SeafileTree::TreeItem::entry() const { return entry_; }
void SeafileTree::TreeItem::set_entry(const Entry &entry) { entry_ = entry;}
void SeafileTree::TreeItem::set_childs(QList<TreeItem *> *childs) { childs_ = *childs; }
void SeafileTree::TreeItem::AppendChild(TreeItem *child) { childs_.append(child); }
void SeafileTree::TreeItem::AppendChild(const Entry &entry) {
childs_.append(new TreeItem(entry));
void SeafileTree::TreeItem::set_entry(const Entry& entry) { entry_ = entry; }
void SeafileTree::TreeItem::set_children(const QList<TreeItem*>& children) {
children_ = children;
}
bool SeafileTree::TreeItem::RemoveChild(TreeItem *child) { return childs_.removeOne(child); }
void SeafileTree::TreeItem::AppendChild(TreeItem* child) {
children_.append(child);
}
SeafileTree::TreeItem* SeafileTree::TreeItem::FindChild(const QString &name) const {
for (TreeItem *item : childs_) {
if (item->entry().name() == name)
return item;
void SeafileTree::TreeItem::AppendChild(const Entry& entry) {
children_.append(new TreeItem(entry));
}
bool SeafileTree::TreeItem::RemoveChild(TreeItem* child) {
return children_.removeOne(child);
}
SeafileTree::TreeItem* SeafileTree::TreeItem::FindChild(
const QString& name) const {
for (TreeItem* item : children_) {
if (item->entry().name() == name) return item;
}
return nullptr;
@ -337,31 +317,25 @@ QString SeafileTree::TreeItem::ToString(int i) const {
res += entry_.ToString() + "\n";
for (TreeItem *item : childs_) {
res += item->ToString( i+1 );
for (TreeItem* item : children_) {
res += item->ToString(i + 1);
}
return res;
}
SeafileTree::TreeItem::~TreeItem() {
// We need to delete childs
for (TreeItem *item : childs_) {
delete item;
}
// We need to delete children
qDeleteAll(children_);
}
QDataStream & operator << (QDataStream &out, const SeafileTree::Entry &entry) {
out << entry.name_
<< entry.id_
<< static_cast<quint8>(entry.type_);
QDataStream& operator<<(QDataStream& out, const SeafileTree::Entry& entry) {
out << entry.name_ << entry.id_ << static_cast<quint8>(entry.type_);
return out;
}
QDataStream & operator >> (QDataStream &in, SeafileTree::Entry &entry) {
QDataStream& operator>>(QDataStream& in, SeafileTree::Entry& entry) {
quint8 temp;
in >> entry.name_;
@ -372,34 +346,31 @@ QDataStream & operator >> (QDataStream &in, SeafileTree::Entry &entry) {
return in;
}
QDataStream & operator << (QDataStream &out, SeafileTree::TreeItem *item) {
out << item->entry_
<< item->childs_;
QDataStream& operator<<(QDataStream& out, SeafileTree::TreeItem* item) {
out << item->entry_ << item->children_;
return out;
}
QDataStream& operator>>(QDataStream& in, SeafileTree::TreeItem*& item) {
SeafileTree::Entry entry;
QList<SeafileTree::TreeItem*> children;
QDataStream & operator >> (QDataStream &in, SeafileTree::TreeItem *&item) {
SeafileTree::Entry *entry = new SeafileTree::Entry();
QList<SeafileTree::TreeItem*> *childs = new QList<SeafileTree::TreeItem*>;
in >> entry;
in >> children;
in >> *entry;
in >> *childs;
item = new SeafileTree::TreeItem(*entry, childs);
item = new SeafileTree::TreeItem(entry, children);
return in;
}
QDataStream & operator << (QDataStream &out, const SeafileTree &tree) {
QDataStream& operator<<(QDataStream& out, const SeafileTree& tree) {
out << tree.libraries_;
return out;
}
QDataStream & operator >> (QDataStream &in, SeafileTree &tree) {
QDataStream& operator>>(QDataStream& in, SeafileTree& tree) {
in >> tree.libraries_;
return in;

View File

@ -17,54 +17,48 @@
class SeafileTree : public QObject {
Q_OBJECT
public:
public:
SeafileTree();
SeafileTree(const SeafileTree &copy);
SeafileTree(const SeafileTree& copy);
~SeafileTree();
class Entry {
public:
enum Type { DIR = 0, FILE = 1, LIBRARY = 2, NONE = 3 };
public:
enum Type {
DIR = 0,
FILE = 1,
LIBRARY = 2,
NONE = 3
};
Entry();
Entry(const Entry &entry);
Entry(const QString &name, const QString &id, const Type &type);
Entry(const QString& name = QString(), const QString& id = QString(),
const Type& type = NONE)
: name_(name), id_(id), type_(type) {}
Entry(const Entry& entry) : Entry(entry.name(), entry.id(), entry.type()) {}
~Entry();
QString name() const;
void set_name(const QString &name);
void set_name(const QString& name);
QString id() const;
void set_id(const QString &id);
void set_id(const QString& id);
Type type() const;
void set_type(const Type &type);
void set_type(const Type& type);
bool is_dir() const;
bool is_file() const;
bool is_library() const;
Entry& operator =(const Entry &entry);
bool operator ==(const Entry &a) const;
bool operator !=(const Entry &a) const;
Entry& operator=(const Entry& entry);
bool operator==(const Entry& a) const;
bool operator!=(const Entry& a) const;
QString ToString() const;
static QString TypeToString(const Type &type);
static Type StringToType(const QString &type);
static QString TypeToString(const Type& type);
static Type StringToType(const QString& type);
private:
private:
QString name_, id_;
Type type_;
friend QDataStream & operator << (QDataStream &out, const SeafileTree::Entry &entry);
friend QDataStream & operator >> (QDataStream &in, SeafileTree::Entry &entry);
friend QDataStream& operator<<(QDataStream& out,
const SeafileTree::Entry& entry);
friend QDataStream& operator>>(QDataStream& in, SeafileTree::Entry& entry);
};
typedef QList<Entry> Entries;
@ -72,61 +66,68 @@ public:
// Node of the tree
// Contains an entry
class TreeItem {
public:
TreeItem();
TreeItem(const TreeItem &copy);
TreeItem(const Entry &entry);
TreeItem(const Entry &entry, QList<TreeItem *> *childs);
public:
TreeItem(const Entry& entry = Entry(),
const QList<TreeItem*>& children = QList<TreeItem*>())
: entry_(entry), children_(children) {}
TreeItem(const TreeItem& copy) : TreeItem(copy.entry()) {}
~TreeItem();
TreeItem* child(int i) const;
QList<TreeItem*> childs() const;
QList<TreeItem*> children() const;
// List of each child's entry
Entries childs_entry() const;
Entries children_entries() const;
void set_childs(QList<TreeItem*> *childs);
void set_children(const QList<TreeItem*>& children);
Entry entry() const;
void set_entry(const Entry &entry);
void set_entry(const Entry& entry);
void AppendChild(TreeItem *child);
void AppendChild(const Entry &entry);
void AppendChild(TreeItem* child);
void AppendChild(const Entry& entry);
// True if child is removed
bool RemoveChild(TreeItem *child);
bool RemoveChild(TreeItem* child);
// nullptr if we didn't find a child entry with the given name
TreeItem* FindChild(const QString &name) const;
TreeItem* FindChild(const QString& name) const;
// Convert the node in QString (for debug)
QString ToString(int i) const;
private:
private:
Entry entry_;
QList<TreeItem*> childs_;
QList<TreeItem*> children_;
friend QDataStream & operator << (QDataStream &out, SeafileTree::TreeItem *item);
friend QDataStream & operator >> (QDataStream &in, SeafileTree::TreeItem *&item);
friend QDataStream& operator<<(QDataStream& out,
SeafileTree::TreeItem* item);
friend QDataStream& operator>>(QDataStream& in,
SeafileTree::TreeItem*& item);
};
QList<TreeItem*> libraries() const;
void AddLibrary(const QString &name, const QString &id);
void DeleteLibrary(const QString &id);
bool AddEntry(const QString &library, const QString &path, const Entry &entry);
bool DeleteEntry(const QString &library, const QString &path, const Entry &entry);
void AddLibrary(const QString& name, const QString& id);
void DeleteLibrary(const QString& id);
bool AddEntry(const QString& library, const QString& path,
const Entry& entry);
bool DeleteEntry(const QString& library, const QString& path,
const Entry& entry);
// Get a list of pair (path, entry) corresponding to the subfiles (and recursively to the subsubfiles...) of the given item
QList<QPair<QString, SeafileTree::Entry>> GetRecursiveFilesOfDir(const QString &path, const TreeItem *item);
// Get a list of pair (path, entry) corresponding to the subfiles (and
// recursively to the subsubfiles...) of the given item
QList<QPair<QString, SeafileTree::Entry>> GetRecursiveFilesOfDir(
const QString& path, const TreeItem* item);
// nullptr if we didn't find the library with the given id
TreeItem* FindLibrary(const QString &library);
TreeItem* FindLibrary(const QString& library);
// nullptr if we didn't find the item
TreeItem* FindFromAbsolutePath(const QString &library, const QString &path);
TreeItem* FindFromAbsolutePath(const QString& library, const QString& path);
// Compare the server entries with the tree
// Emit signals (ToDelete, ToAdd, ToUpdate)
void CheckEntries(const Entries &server_entries, const Entry &library, const QString &path);
void CheckEntries(const Entries& server_entries, const Entry& library,
const QString& path);
// Destroy the tree
void Clear();
@ -136,27 +137,29 @@ public:
signals:
// Entry to delete in the tree
void ToDelete(const QString &library, const QString &path, const SeafileTree::Entry &entry);
void ToDelete(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
// Entry to add in the tree
void ToAdd(const QString &library, const QString &path, const SeafileTree::Entry &entry);
void ToAdd(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
// Entry to update in the tree
void ToUpdate(const QString &library, const QString &path, const SeafileTree::Entry &entry);
void ToUpdate(const QString& library, const QString& path,
const SeafileTree::Entry& entry);
private:
private:
QList<TreeItem*> libraries_;
friend QDataStream & operator << (QDataStream &out, const SeafileTree &tree);
friend QDataStream & operator >> (QDataStream &in, SeafileTree &tree);
friend QDataStream& operator<<(QDataStream& out, const SeafileTree& tree);
friend QDataStream& operator>>(QDataStream& in, SeafileTree& tree);
};
QDataStream & operator << (QDataStream &out, const SeafileTree &tree);
QDataStream & operator >> (QDataStream &in, SeafileTree &tree);
QDataStream& operator<<(QDataStream& out, const SeafileTree& tree);
QDataStream& operator>>(QDataStream& in, SeafileTree& tree);
QDataStream & operator << (QDataStream &out, const SeafileTree::Entry &entry);
QDataStream & operator >> (QDataStream &in, SeafileTree::Entry &entry);
QDataStream & operator << (QDataStream &out, SeafileTree::TreeItem *item);
QDataStream & operator >> (QDataStream &in, SeafileTree::TreeItem *&item);
QDataStream& operator<<(QDataStream& out, const SeafileTree::Entry& entry);
QDataStream& operator>>(QDataStream& in, SeafileTree::Entry& entry);
QDataStream& operator<<(QDataStream& out, SeafileTree::TreeItem* item);
QDataStream& operator>>(QDataStream& in, SeafileTree::TreeItem*& item);
#endif // SEAFILETREE_H