* fix a lot of compiler warnings
[kdenetwork.git] / kget / transfer-plugins / bittorrent / torrentfiletreemodel.cpp
blob81c19c640290faf5bca883e705f248a81f8cf3a3
1 /** IMPORTANT: please keep this file in sync with ktorrent! ****************/
3 /***************************************************************************
4 * Copyright (C) 2007 by Joris Guisson and Ivan Vasic *
5 * joris.guisson@gmail.com *
6 * ivasic@gmail.com *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************/
23 #include <klocale.h>
24 #include <kicon.h>
25 #include <kmimetype.h>
26 #include <QTreeView>
27 #include <bcodec/bdecoder.h>
28 #include <bcodec/bencoder.h>
29 #include <bcodec/bnode.h>
30 #include <interfaces/torrentinterface.h>
31 #include <interfaces/torrentfileinterface.h>
32 #include <util/functions.h>
33 #include <util/log.h>
34 #include "torrentfiletreemodel.h"
36 using namespace bt;
38 namespace kt
41 TorrentFileTreeModel::Node::Node(Node* parent,bt::TorrentFileInterface* file,const QString & name)
42 : parent(parent),file(file),name(name),size(0)
45 TorrentFileTreeModel::Node::Node(Node* parent,const QString & name)
46 : parent(parent),file(0),name(name),size(0)
50 TorrentFileTreeModel::Node::~Node()
52 qDeleteAll(children);
55 void TorrentFileTreeModel::Node::insert(const QString & path,bt::TorrentFileInterface* file)
57 int p = path.indexOf(bt::DirSeparator());
58 if (p == -1)
60 // the file is part of this directory
61 children.append(new Node(this,file,path));
63 else
65 QString subdir = path.left(p);
66 foreach (Node* n,children)
68 if (n->name == subdir)
70 n->insert(path.mid(p+1),file);
71 return;
75 Node* n = new Node(this,subdir);
76 children.append(n);
77 n->insert(path.mid(p+1),file);
81 int TorrentFileTreeModel::Node::row()
83 if (parent)
84 return parent->children.indexOf(this);
85 else
86 return 0;
89 bt::Uint64 TorrentFileTreeModel::Node::fileSize(const bt::TorrentInterface* tc)
91 if (size > 0)
92 return size;
94 if (!file)
96 // directory
97 foreach (Node* n,children)
98 size += n->fileSize(tc);
100 else
102 size = file->getSize();
104 return size;
107 bt::Uint64 TorrentFileTreeModel::Node::bytesToDownload(const bt::TorrentInterface* tc)
109 bt::Uint64 s = 0;
111 if (!file)
113 // directory
114 foreach (Node* n,children)
115 s += n->bytesToDownload(tc);
117 else
119 if (!file->doNotDownload())
120 s = file->getSize();
122 return s;
125 Qt::CheckState TorrentFileTreeModel::Node::checkState(const bt::TorrentInterface* tc) const
127 if (!file)
129 bool found_checked = false;
130 bool found_unchecked = false;
131 // directory
132 foreach (Node* n,children)
134 Qt::CheckState s = n->checkState(tc);
135 if (s == Qt::PartiallyChecked)
136 return s;
137 else if (s == Qt::Checked)
138 found_checked = true;
139 else
140 found_unchecked = true;
142 if (found_checked && found_unchecked)
143 return Qt::PartiallyChecked;
146 return found_checked ? Qt::Checked : Qt::Unchecked;
148 else
150 return file->doNotDownload() || file->getPriority() == ONLY_SEED_PRIORITY ? Qt::Unchecked : Qt::Checked;
154 void TorrentFileTreeModel::Node::saveExpandedState(const QModelIndex & index,QTreeView* tv,BEncoder* enc)
156 if (file)
157 return;
159 enc->write("expanded");
160 enc->write((Uint32)(tv->isExpanded(index) ? 1 : 0));
162 int idx = 0;
163 foreach (Node* n,children)
165 if (!n->file)
167 enc->write(n->name);
168 enc->beginDict();
169 n->saveExpandedState(index.child(idx,0),tv,enc);
170 enc->end();
172 idx++;
176 void TorrentFileTreeModel::Node::loadExpandedState(const QModelIndex & index,QTreeView* tv,BNode* n)
178 if (file)
179 return;
181 BDictNode* dict = dynamic_cast<BDictNode*>(n);
182 if (!dict)
183 return;
185 BValueNode* v = dict->getValue("expanded");
186 if (v)
187 tv->setExpanded(index,v->data().toInt() == 1);
189 int idx = 0;
190 foreach (Node* n,children)
192 if (!n->file)
194 BDictNode* d = dict->getDict(n->name);
195 if (d)
196 n->loadExpandedState(index.child(idx,0),tv,d);
198 idx++;
202 TorrentFileTreeModel::TorrentFileTreeModel(bt::TorrentInterface* tc,DeselectMode mode,QObject* parent)
203 : TorrentFileModel(tc,mode,parent),root(0),emit_check_state_change(true)
205 if (tc->getStats().multi_file_torrent)
206 constructTree();
207 else
208 root = new Node(0,tc->getStats().torrent_name);
212 TorrentFileTreeModel::~TorrentFileTreeModel()
215 void TorrentFileTreeModel::constructTree()
217 if (!root)
218 root = new Node(0,tc->getStats().torrent_name);
220 for (Uint32 i = 0;i < tc->getNumFiles();i++)
222 bt::TorrentFileInterface & tf = tc->getTorrentFile(i);
223 root->insert(tf.getPath(),&tf);
227 int TorrentFileTreeModel::rowCount(const QModelIndex & parent) const
229 if (!parent.isValid())
231 return 1;
233 else
235 Node* n = (Node*)parent.internalPointer();
236 return n->children.count();
240 int TorrentFileTreeModel::columnCount(const QModelIndex & parent) const
242 if (!parent.isValid())
243 return 2;
244 else
245 return 2;
248 QVariant TorrentFileTreeModel::headerData(int section, Qt::Orientation orientation,int role) const
250 if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
251 return QVariant();
253 switch (section)
255 case 0: return i18n("File");
256 case 1: return i18n("Size");
257 default:
258 return QVariant();
262 QVariant TorrentFileTreeModel::data(const QModelIndex & index, int role) const
264 if (!index.isValid())
265 return QVariant();
267 Node* n = (Node*)index.internalPointer();
268 if (!n)
269 return QVariant();
271 if (role == Qt::DisplayRole)
273 switch (index.column())
275 case 0: return n->name;
276 case 1:
277 if (tc->getStats().multi_file_torrent)
278 return BytesToString(n->fileSize(tc));
279 else
280 return BytesToString(tc->getStats().total_bytes);
281 default: return QVariant();
284 else if (role == Qt::DecorationRole && index.column() == 0)
286 // if this is an empty folder then we are in the single file case
287 if (!n->file)
288 return n->children.count() > 0 ?
289 KIcon("folder") : KIcon(KMimeType::findByPath(tc->getStats().torrent_name)->iconName());
290 else
291 return KIcon(KMimeType::findByPath(n->file->getPath())->iconName());
293 else if (role == Qt::CheckStateRole && index.column() == 0)
295 if (tc->getStats().multi_file_torrent)
296 return n->checkState(tc);
299 return QVariant();
302 QModelIndex TorrentFileTreeModel::parent(const QModelIndex & index) const
304 if (!index.isValid())
305 return QModelIndex();
307 Node* child = static_cast<Node*>(index.internalPointer());
308 if (!child)
309 return QModelIndex();
311 Node* parent = child->parent;
312 if (!parent)
313 return QModelIndex();
314 else
315 return createIndex(parent->row(), 0, parent);
318 QModelIndex TorrentFileTreeModel::index(int row,int column,const QModelIndex & parent) const
320 if (!hasIndex(row, column, parent))
321 return QModelIndex();
323 Node* p = 0;
325 if (!parent.isValid())
326 return createIndex(row,column,root);
327 else
329 p = static_cast<Node*>(parent.internalPointer());
331 if (row >= 0 && row < p->children.count())
332 return createIndex(row,column,p->children.at(row));
333 else
334 return QModelIndex();
338 Qt::ItemFlags TorrentFileTreeModel::flags(const QModelIndex & index) const
340 if (!index.isValid())
341 return 0;
342 else if (tc->getStats().multi_file_torrent)
343 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
344 else
345 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
348 bool TorrentFileTreeModel::setData(const QModelIndex & index, const QVariant & value, int role)
350 if (!index.isValid() || role != Qt::CheckStateRole)
351 return false;
353 Node* n = static_cast<Node*>(index.internalPointer());
354 if (!n)
355 return false;
357 Qt::CheckState newState = static_cast<Qt::CheckState>(value.toInt());
358 if (!n->file)
360 bool reenable = false;
361 if (emit_check_state_change)
363 reenable = true;
364 emit_check_state_change = false;
367 for (Uint32 i = 0;i < n->children.count();i++)
369 // recurse down the tree
370 setData(index.child(i,0),value,role);
373 if (reenable)
374 emit_check_state_change = true;
376 else
378 bt::TorrentFileInterface* file = n->file;
379 if (newState == Qt::Checked)
381 if (file->getPriority() == ONLY_SEED_PRIORITY)
382 file->setPriority(NORMAL_PRIORITY);
383 else
384 file->setDoNotDownload(false);
386 else
388 if (mode == KEEP_FILES)
389 file->setPriority(ONLY_SEED_PRIORITY);
390 else
391 file->setDoNotDownload(true);
393 dataChanged(createIndex(index.row(),0),createIndex(index.row(),columnCount(index) - 1));
395 QModelIndex parent = index.parent();
396 if (parent.isValid())
397 dataChanged(parent,parent); // parent needs to be updated to
400 if (emit_check_state_change)
401 checkStateChanged();
402 return true;
405 void TorrentFileTreeModel::checkAll()
407 if (tc->getStats().multi_file_torrent)
408 setData(index(0,0,QModelIndex()),Qt::Checked,Qt::CheckStateRole);
411 void TorrentFileTreeModel::uncheckAll()
413 if (tc->getStats().multi_file_torrent)
414 setData(index(0,0,QModelIndex()),Qt::Unchecked,Qt::CheckStateRole);
417 void TorrentFileTreeModel::invertCheck()
419 if (!tc->getStats().multi_file_torrent)
420 return;
422 invertCheck(index(0,0,QModelIndex()));
425 void TorrentFileTreeModel::invertCheck(const QModelIndex & idx)
427 Node* n = static_cast<Node*>(idx.internalPointer());
428 if (!n)
429 return;
431 if (!n->file)
433 for (Uint32 i = 0;i < n->children.count();i++)
435 // recurse down the tree
436 invertCheck(idx.child(i,0));
439 else
441 if (n->file->doNotDownload())
442 setData(idx,Qt::Checked,Qt::CheckStateRole);
443 else
444 setData(idx,Qt::Unchecked,Qt::CheckStateRole);
448 bt::Uint64 TorrentFileTreeModel::bytesToDownload()
450 if (tc->getStats().multi_file_torrent)
451 return root->bytesToDownload(tc);
452 else
453 return tc->getStats().total_bytes;
456 QByteArray TorrentFileTreeModel::saveExpandedState(QTreeView* tv)
458 if (!tc->getStats().multi_file_torrent)
459 return QByteArray();
461 QByteArray data;
462 BEncoder enc(new BEncoderBufferOutput(data));
463 enc.beginDict();
464 root->saveExpandedState(index(0,0,QModelIndex()),tv,&enc);
465 enc.end();
466 return data;
470 void TorrentFileTreeModel::loadExpandedState(QTreeView* tv,const QByteArray & state)
472 if (!tc->getStats().multi_file_torrent)
473 return;
475 BDecoder dec(state,false,0);
476 BNode* n = dec.decode();
477 if (n && n->getType() == BNode::DICT)
479 n->printDebugInfo();
480 root->loadExpandedState(index(0,0,QModelIndex()),tv,n);
482 delete n;
485 bt::TorrentFileInterface* TorrentFileTreeModel::indexToFile(const QModelIndex & idx)
487 if (!idx.isValid())
488 return 0;
490 Node* n = (Node*)idx.internalPointer();
491 if (!n)
492 return 0;
494 return n->file;
497 QString TorrentFileTreeModel::dirPath(const QModelIndex & idx)
499 if (!idx.isValid())
500 return QString::null;
502 Node* n = (Node*)idx.internalPointer();
503 if (!n || n == root)
504 return QString::null;
506 QString ret = n->name;
509 n = n->parent;
510 if (n && n->parent)
511 ret = n->name + bt::DirSeparator() + ret;
512 }while (n);
514 return ret;
517 void TorrentFileTreeModel::changePriority(const QModelIndexList & indexes,bt::Priority newpriority)
519 foreach (QModelIndex idx,indexes)
521 Node* n = (Node*)idx.internalPointer();
522 if (!n)
523 continue;
525 setData(idx,newpriority,Qt::UserRole);
530 #include "torrentfiletreemodel.moc"