2014-12-17 19:02:21 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2014, Chocobozzz <djidane14ff@hotmail.fr>
|
|
|
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2014-06-03 14:33:07 +02:00
|
|
|
#include "seafiletree.h"
|
|
|
|
|
|
|
|
#include <QDir>
|
2020-09-18 16:15:19 +02:00
|
|
|
#include <QRegExp>
|
|
|
|
#include <QStringList>
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
#include "core/logging.h"
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2020-01-04 23:18:59 +01:00
|
|
|
SeafileTree::SeafileTree(QObject* parent) : QObject(parent) {}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2020-01-04 23:18:59 +01:00
|
|
|
SeafileTree::SeafileTree(const SeafileTree& copy, QObject* parent)
|
|
|
|
: QObject(parent) {
|
2014-06-04 17:58:28 +02:00
|
|
|
libraries_ = copy.libraries();
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QList<SeafileTree::TreeItem*> SeafileTree::libraries() const {
|
|
|
|
return libraries_;
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
void SeafileTree::Print() const {
|
|
|
|
qLog(Debug) << "library count : " << libraries_.count();
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (TreeItem* item : libraries_) {
|
2014-06-03 14:33:07 +02:00
|
|
|
qLog(Debug) << "library : " << item->ToString(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::AddLibrary(const QString& name, const QString& id) {
|
|
|
|
libraries_.append(new TreeItem(Entry(name, id, Entry::Type::LIBRARY)));
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::DeleteLibrary(const QString& id) {
|
2014-06-03 14:33:07 +02:00
|
|
|
for (int i = 0; i < libraries_.size(); ++i) {
|
|
|
|
if (libraries_.at(i)->entry().id() == id) {
|
|
|
|
libraries_.removeAt(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
bool SeafileTree::AddEntry(const QString& library, const QString& path,
|
|
|
|
const Entry& entry) {
|
|
|
|
TreeItem* dir_node = FindFromAbsolutePath(library, path);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!dir_node) {
|
2014-06-03 14:33:07 +02:00
|
|
|
qLog(Warning) << "Can't find the path...";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it is not a dir or a library we can't add an entry...
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!dir_node->entry().is_dir() && !dir_node->entry().is_library()) {
|
2014-06-03 14:33:07 +02:00
|
|
|
qLog(Warning) << "This is not a dir or a file...";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_node->AppendChild(entry);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::CheckEntries(const Entries& server_entries,
|
|
|
|
const Entry& library, const QString& path) {
|
|
|
|
TreeItem* local_item = FindFromAbsolutePath(library.id(), path);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
// Don't know the path
|
|
|
|
// Have to add all entries
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!local_item) {
|
2014-06-03 14:33:07 +02:00
|
|
|
emit ToAdd(library.id(), path, library);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
Entries local_entries = local_item->children_entries();
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (const Entry& server_entry : server_entries) {
|
2014-06-03 14:33:07 +02:00
|
|
|
bool is_in_tree = false;
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (int i = 0; i < local_entries.size(); ++i) {
|
2014-06-03 14:33:07 +02:00
|
|
|
Entry local_entry = local_entries.at(i);
|
|
|
|
|
|
|
|
// We found the entry in the tree
|
2014-06-04 17:58:28 +02:00
|
|
|
if (local_entry.name() == server_entry.name() &&
|
|
|
|
local_entry.type() == server_entry.type()) {
|
2014-06-03 14:33:07 +02:00
|
|
|
is_in_tree = true;
|
|
|
|
|
|
|
|
// Need to update
|
|
|
|
if (local_entry.id() != server_entry.id()) {
|
|
|
|
emit ToUpdate(library.id(), path, server_entry);
|
|
|
|
|
|
|
|
// Set the new id to the local entry
|
|
|
|
local_entry.set_id(server_entry.id());
|
|
|
|
}
|
|
|
|
|
|
|
|
// local_entries could be named "local_entries_to_proceed"
|
|
|
|
// So we delete from the list the entry we just proceeded
|
|
|
|
local_entries.removeAt(i);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to add the entry
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!is_in_tree) {
|
2014-06-03 14:33:07 +02:00
|
|
|
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
|
2014-06-04 17:58:28 +02:00
|
|
|
for (const Entry& local_entry : local_entries) {
|
2014-06-03 14:33:07 +02:00
|
|
|
emit ToDelete(library.id(), path, local_entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::TreeItem* SeafileTree::FindLibrary(const QString& library) {
|
|
|
|
for (TreeItem* item : libraries_) {
|
|
|
|
if (item->entry().id() == library) return item;
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::TreeItem* SeafileTree::FindFromAbsolutePath(const QString& library,
|
|
|
|
const QString& path) {
|
|
|
|
TreeItem* node_item = FindLibrary(library);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
if (!node_item) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList path_parts = path.split("/", QString::SkipEmptyParts);
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (const QString& part : path_parts) {
|
2014-06-03 14:33:07 +02:00
|
|
|
node_item = node_item->FindChild(part);
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!node_item) {
|
2014-06-03 14:33:07 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return node_item;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
bool SeafileTree::DeleteEntry(const QString& library, const QString& path,
|
|
|
|
const Entry& entry) {
|
|
|
|
TreeItem* item_parent = FindFromAbsolutePath(library, path);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!item_parent) {
|
|
|
|
qLog(Debug) << "Unable to delete " << library + path + entry.name()
|
2014-06-03 14:33:07 +02:00
|
|
|
<< " : path " << path << " not found";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
TreeItem* item_entry = item_parent->FindChild(entry.name());
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!item_entry) {
|
|
|
|
qLog(Debug) << "Unable to delete " << library + path + entry.name()
|
2014-06-03 14:33:07 +02:00
|
|
|
<< " : entry " << entry.name() << " from path not found";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!item_parent->RemoveChild(item_entry)) {
|
|
|
|
qLog(Debug) << "Can't remove " << item_entry->entry().name()
|
|
|
|
<< " from parent";
|
2014-06-03 14:33:07 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete item_entry;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SeafileTree::Clear() {
|
|
|
|
qDeleteAll(libraries_);
|
|
|
|
libraries_.clear();
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QList<QPair<QString, SeafileTree::Entry>> SeafileTree::GetRecursiveFilesOfDir(
|
|
|
|
const QString& path, const TreeItem* item) {
|
2014-06-03 14:33:07 +02:00
|
|
|
// key = path, value = entry
|
|
|
|
QList<QPair<QString, Entry>> files;
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (!item) {
|
2014-06-03 14:33:07 +02:00
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
if (item->entry().is_file()) {
|
2014-06-03 14:33:07 +02:00
|
|
|
files.append(qMakePair(path, item->entry()));
|
2020-09-18 16:15:19 +02:00
|
|
|
// Get files of the dir
|
2014-12-17 19:02:21 +01:00
|
|
|
} else {
|
2014-06-04 17:58:28 +02:00
|
|
|
for (TreeItem* child_item : item->children()) {
|
|
|
|
if (child_item->entry().is_file()) {
|
2014-06-03 14:33:07 +02:00
|
|
|
files.append(qMakePair(path, child_item->entry()));
|
2014-06-04 17:58:28 +02:00
|
|
|
} else {
|
2014-06-03 14:33:07 +02:00
|
|
|
QString name = child_item->entry().name() + "/";
|
|
|
|
files.append(GetRecursiveFilesOfDir(path + name, child_item));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeafileTree::~SeafileTree() {}
|
|
|
|
|
|
|
|
/* ################################# Entry ################################# */
|
|
|
|
|
|
|
|
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); }
|
2014-06-04 17:58:28 +02:00
|
|
|
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; }
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
QString SeafileTree::Entry::ToString() const {
|
|
|
|
return "name : " + name_ + " id : " + id_ + " type : " + TypeToString(type_);
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::Entry& SeafileTree::Entry::operator=(const Entry& entry) {
|
2014-06-03 14:33:07 +02:00
|
|
|
name_ = entry.name();
|
|
|
|
id_ = entry.id();
|
|
|
|
type_ = entry.type();
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
bool SeafileTree::Entry::operator==(const Entry& a) const {
|
|
|
|
return a.name() == name() && a.id() == id() && a.type() == type();
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
bool SeafileTree::Entry::operator!=(const Entry& a) const {
|
|
|
|
return !(operator==(a));
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SeafileTree::Entry::~Entry() {}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QString SeafileTree::Entry::TypeToString(const Type& type) {
|
|
|
|
switch (type) {
|
|
|
|
case DIR:
|
|
|
|
return "dir";
|
|
|
|
case FILE:
|
|
|
|
return "file";
|
|
|
|
case LIBRARY:
|
|
|
|
return "library";
|
|
|
|
default:
|
2019-11-09 23:45:28 +01:00
|
|
|
return QString();
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
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;
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
return NONE;
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ############################### TreeItem ############################### */
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::Entries SeafileTree::TreeItem::children_entries() const {
|
2014-06-03 14:33:07 +02:00
|
|
|
Entries entries;
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (TreeItem* item : children_) {
|
2014-06-03 14:33:07 +02:00
|
|
|
entries.append(Entry(item->entry()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::TreeItem* SeafileTree::TreeItem::child(int i) const {
|
|
|
|
return children_.at(i);
|
|
|
|
}
|
|
|
|
QList<SeafileTree::TreeItem*> SeafileTree::TreeItem::children() const {
|
|
|
|
return children_;
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
SeafileTree::Entry SeafileTree::TreeItem::entry() const { return entry_; }
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::TreeItem::set_entry(const Entry& entry) { entry_ = entry; }
|
|
|
|
void SeafileTree::TreeItem::set_children(const QList<TreeItem*>& children) {
|
|
|
|
children_ = children;
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::TreeItem::AppendChild(TreeItem* child) {
|
|
|
|
children_.append(child);
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
void SeafileTree::TreeItem::AppendChild(const Entry& entry) {
|
|
|
|
children_.append(new TreeItem(entry));
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
bool SeafileTree::TreeItem::RemoveChild(TreeItem* child) {
|
|
|
|
return children_.removeOne(child);
|
|
|
|
}
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
SeafileTree::TreeItem* SeafileTree::TreeItem::FindChild(
|
|
|
|
const QString& name) const {
|
|
|
|
for (TreeItem* item : children_) {
|
|
|
|
if (item->entry().name() == name) return item;
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SeafileTree::TreeItem::ToString(int i) const {
|
|
|
|
QString res = "";
|
|
|
|
|
|
|
|
for (int j = 0; j < i; ++j) {
|
|
|
|
res += " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
res += entry_.ToString() + "\n";
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
for (TreeItem* item : children_) {
|
|
|
|
res += item->ToString(i + 1);
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeafileTree::TreeItem::~TreeItem() {
|
2014-06-04 17:58:28 +02:00
|
|
|
// We need to delete children
|
|
|
|
qDeleteAll(children_);
|
2014-06-03 14:33:07 +02:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator<<(QDataStream& out, const SeafileTree::Entry& entry) {
|
|
|
|
out << entry.name_ << entry.id_ << static_cast<quint8>(entry.type_);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator>>(QDataStream& in, SeafileTree::Entry& entry) {
|
2014-06-03 14:33:07 +02:00
|
|
|
quint8 temp;
|
|
|
|
|
|
|
|
in >> entry.name_;
|
|
|
|
in >> entry.id_;
|
|
|
|
in >> temp;
|
|
|
|
entry.type_ = SeafileTree::Entry::Type(temp);
|
|
|
|
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator<<(QDataStream& out, SeafileTree::TreeItem* item) {
|
|
|
|
out << item->entry_ << item->children_;
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator>>(QDataStream& in, SeafileTree::TreeItem*& item) {
|
|
|
|
SeafileTree::Entry entry;
|
|
|
|
QList<SeafileTree::TreeItem*> children;
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
in >> entry;
|
|
|
|
in >> children;
|
2014-06-03 14:33:07 +02:00
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
item = new SeafileTree::TreeItem(entry, children);
|
2014-06-03 14:33:07 +02:00
|
|
|
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator<<(QDataStream& out, const SeafileTree& tree) {
|
2014-06-03 14:33:07 +02:00
|
|
|
out << tree.libraries_;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:58:28 +02:00
|
|
|
QDataStream& operator>>(QDataStream& in, SeafileTree& tree) {
|
2014-06-03 14:33:07 +02:00
|
|
|
in >> tree.libraries_;
|
|
|
|
|
|
|
|
return in;
|
|
|
|
}
|