Logo Search packages:      
Sourcecode: qbittorrent version File versions  Download package

arborescence.h

/*
 * Bittorrent Client using Qt4 and libtorrent.
 * Copyright (C) 2006  Christophe Dumez
 *
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Contact : chris@qbittorrent.org
 */

#ifndef ARBORESCENCE_H
#define ARBORESCENCE_H

#include <QFileInfo>
#include <QStringList>
#include <QDir>
#include "misc.h"

class torrent_file {
  private:
    torrent_file *parent;
    bool is_dir;
    QString rel_path;
    QList<torrent_file*> children;
    size_type size;
    float progress;
    int priority;
    int index; // Index in torrent_info

  public:
    torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){
      qDebug("created a file with index %d", index);
      rel_path = QDir::cleanPath(path);
      if(parent) {
        parent->updateProgress();
        parent->updatePriority(priority);
      }
    }

    ~torrent_file() {
      qDeleteAll(children);
    }

    QString path() const {
      return rel_path;
    }

    QString name() const {
      return rel_path.split(QDir::separator()).last();
    }

    void updateProgress() {
      Q_ASSERT(is_dir);
      if(children.isEmpty()) {
        progress = 0.;
        return;
      }
      float wanted = 0.;
      float done = 0.;
      torrent_file *child;
      foreach(child, children) {
        wanted += child->getSize();
        done += child->getSize()*child->getProgress();
      }
      progress = done / wanted;
      Q_ASSERT(progress >= 0.);
      Q_ASSERT(progress <= 1.);
    }

    void updatePriority(int prio) {
      Q_ASSERT(is_dir);
      torrent_file *child;
      foreach(child, children) {
        if(child->getPriority() != prio) return;
      }
      priority = prio;
    }

    int getPriority() const {
      return priority;
    }

    size_type getSize() const {
      return size;
    }

    float getProgress() const {
      return progress;
    }

    int getIndex() const {
      return index;
    }

    bool isDir() const {
      return is_dir;
    }

    bool hasChildren() const {
      return (!children.isEmpty());
    }

    QList<torrent_file*> getChildren() const {
      return children;
    }

    torrent_file* getChild(QString fileName) const {
      Q_ASSERT(is_dir);
      torrent_file* f;
      foreach(f, children) {
        if(f->name() == fileName) return f;
      }
      return 0;
    }

    void addBytes(size_type b) {
      size += b;
      if(parent)
        parent->addBytes(b);
    }

    torrent_file* addChild(QString fileName, bool dir, size_type size=0, int index = -1, float progress=0., int priority=1) {
      Q_ASSERT(is_dir);
      qDebug("Adding a new child of size: %ld", (long)size);
      torrent_file *f = new torrent_file(this, QDir::cleanPath(rel_path+QDir::separator()+fileName), dir, size, index, progress, priority);
      children << f;
      if(size) {
        addBytes(size);
      }
      return f;
    }

    bool removeFromFS(QString saveDir) {
      QString full_path = saveDir + QDir::separator() + rel_path;
      if(!QFile::exists(full_path)) {
        qDebug("%s does not exist, no need to remove it", full_path.toUtf8().data());
        return true;
      }
      bool success = true;
      torrent_file *f;
      qDebug("We have %d children", children.size());
      foreach(f, children) {
        bool s = f->removeFromFS(saveDir);
        success = s && success;
      }
      if(is_dir) {
        qDebug("trying to remove directory: %s", full_path.toUtf8().data());
        QDir dir(full_path);
        dir.rmdir(full_path);
      } else {
        qDebug("trying to remove file: %s", full_path.toUtf8().data());
        bool s = QFile::remove(full_path);
        success = s && success;
      }
      return success;
    }
};

class arborescence {
  private:
    torrent_file *root;

  public:
    arborescence(torrent_info t) {
      torrent_info::file_iterator fi = t.begin_files();
      if(t.num_files() > 1) {
        root = new torrent_file(0, misc::toQString(t.name()), true);
      } else {
        // XXX: Will crash if there is no file in torrent
        root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0);
        return;
      }
      int i = 0;
      while(fi != t.end_files()) {
        QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
        addFile(path, fi->size, i);
        fi++;
        ++i;
      }
      qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
      Q_ASSERT(root->getSize() == t.total_size());
    }

    arborescence(torrent_info t, std::vector<float> fp, int *prioritiesTab) {
      torrent_info::file_iterator fi = t.begin_files();
      if(t.num_files() > 1) {
        qDebug("More than one file in the torrent, setting a folder as root");
        root = new torrent_file(0, misc::toQString(t.name()), true);
      } else {
        // XXX: Will crash if there is no file in torrent
        qDebug("one file in the torrent, setting it as root with index 0");
        root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, fp[0], prioritiesTab[0]);
        return;
      }
      int i = 0;
      while(fi != t.end_files()) {
        QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
        addFile(path, fi->size, i, fp[i], prioritiesTab[i]);
        fi++;
        ++i;
      }
      qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
      Q_ASSERT(root->getSize() == t.total_size());
    }

    ~arborescence() {
      delete root;
    }

    torrent_file* getRoot() const {
      return root;
    }

    bool removeFromFS(QString saveDir) {
      if(!QFile::exists(saveDir+QDir::separator()+root->path())) return true;
      bool success = root->removeFromFS(saveDir);
      QDir root_dir(root->path());
      root_dir.rmdir(saveDir+QDir::separator()+root->path());
      return success;
    }

  protected:
    void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) {
      Q_ASSERT(root->isDir());
      path = QDir::cleanPath(path);
      //Q_ASSERT(path.startsWith(root->path()));
      QString relative_path = path.remove(0, root->path().size());
      if(relative_path.at(0) ==QDir::separator())
        relative_path.remove(0, 1);
      QStringList fileNames = relative_path.split(QDir::separator());
      QString fileName;
      torrent_file *dad = root;
      unsigned int nb_i = 0;
      unsigned int size = fileNames.size();
      foreach(fileName, fileNames) {
        ++nb_i;
        if(fileName == ".") continue;
        torrent_file* child = dad->getChild(fileName);
        if(!child) {
          if(nb_i != size) {
            // Folder
            child = dad->addChild(fileName, true);
          } else {
            // File
            child = dad->addChild(fileName, false, file_size, index, progress, priority);
          }
        }
        dad = child;
      }
    }
};

#endif

Generated by  Doxygen 1.6.0   Back to index