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 *
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. *
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. *
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 ***************************************************************************/
25 #include <kmimetype.h>
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>
34 #include "torrentfiletreemodel.h"
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()
55 void TorrentFileTreeModel::Node::insert(const QString
& path
,bt::TorrentFileInterface
* file
)
57 int p
= path
.indexOf(bt::DirSeparator());
60 // the file is part of this directory
61 children
.append(new Node(this,file
,path
));
65 QString subdir
= path
.left(p
);
66 foreach (Node
* n
,children
)
68 if (n
->name
== subdir
)
70 n
->insert(path
.mid(p
+1),file
);
75 Node
* n
= new Node(this,subdir
);
77 n
->insert(path
.mid(p
+1),file
);
81 int TorrentFileTreeModel::Node::row()
84 return parent
->children
.indexOf(this);
89 bt::Uint64
TorrentFileTreeModel::Node::fileSize(const bt::TorrentInterface
* tc
)
97 foreach (Node
* n
,children
)
98 size
+= n
->fileSize(tc
);
102 size
= file
->getSize();
107 bt::Uint64
TorrentFileTreeModel::Node::bytesToDownload(const bt::TorrentInterface
* tc
)
114 foreach (Node
* n
,children
)
115 s
+= n
->bytesToDownload(tc
);
119 if (!file
->doNotDownload())
125 Qt::CheckState
TorrentFileTreeModel::Node::checkState(const bt::TorrentInterface
* tc
) const
129 bool found_checked
= false;
130 bool found_unchecked
= false;
132 foreach (Node
* n
,children
)
134 Qt::CheckState s
= n
->checkState(tc
);
135 if (s
== Qt::PartiallyChecked
)
137 else if (s
== Qt::Checked
)
138 found_checked
= true;
140 found_unchecked
= true;
142 if (found_checked
&& found_unchecked
)
143 return Qt::PartiallyChecked
;
146 return found_checked
? Qt::Checked
: Qt::Unchecked
;
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
)
159 enc
->write("expanded");
160 enc
->write((Uint32
)(tv
->isExpanded(index
) ? 1 : 0));
163 foreach (Node
* n
,children
)
169 n
->saveExpandedState(index
.child(idx
,0),tv
,enc
);
176 void TorrentFileTreeModel::Node::loadExpandedState(const QModelIndex
& index
,QTreeView
* tv
,BNode
* n
)
181 BDictNode
* dict
= dynamic_cast<BDictNode
*>(n
);
185 BValueNode
* v
= dict
->getValue("expanded");
187 tv
->setExpanded(index
,v
->data().toInt() == 1);
190 foreach (Node
* n
,children
)
194 BDictNode
* d
= dict
->getDict(n
->name
);
196 n
->loadExpandedState(index
.child(idx
,0),tv
,d
);
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
)
208 root
= new Node(0,tc
->getStats().torrent_name
);
212 TorrentFileTreeModel::~TorrentFileTreeModel()
215 void TorrentFileTreeModel::constructTree()
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())
235 Node
* n
= (Node
*)parent
.internalPointer();
236 return n
->children
.count();
240 int TorrentFileTreeModel::columnCount(const QModelIndex
& parent
) const
242 if (!parent
.isValid())
248 QVariant
TorrentFileTreeModel::headerData(int section
, Qt::Orientation orientation
,int role
) const
250 if (role
!= Qt::DisplayRole
|| orientation
!= Qt::Horizontal
)
255 case 0: return i18n("File");
256 case 1: return i18n("Size");
262 QVariant
TorrentFileTreeModel::data(const QModelIndex
& index
, int role
) const
264 if (!index
.isValid())
267 Node
* n
= (Node
*)index
.internalPointer();
271 if (role
== Qt::DisplayRole
)
273 switch (index
.column())
275 case 0: return n
->name
;
277 if (tc
->getStats().multi_file_torrent
)
278 return BytesToString(n
->fileSize(tc
));
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
288 return n
->children
.count() > 0 ?
289 KIcon("folder") : KIcon(KMimeType::findByPath(tc
->getStats().torrent_name
)->iconName());
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
);
302 QModelIndex
TorrentFileTreeModel::parent(const QModelIndex
& index
) const
304 if (!index
.isValid())
305 return QModelIndex();
307 Node
* child
= static_cast<Node
*>(index
.internalPointer());
309 return QModelIndex();
311 Node
* parent
= child
->parent
;
313 return QModelIndex();
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();
325 if (!parent
.isValid())
326 return createIndex(row
,column
,root
);
329 p
= static_cast<Node
*>(parent
.internalPointer());
331 if (row
>= 0 && row
< p
->children
.count())
332 return createIndex(row
,column
,p
->children
.at(row
));
334 return QModelIndex();
338 Qt::ItemFlags
TorrentFileTreeModel::flags(const QModelIndex
& index
) const
340 if (!index
.isValid())
342 else if (tc
->getStats().multi_file_torrent
)
343 return Qt::ItemIsSelectable
| Qt::ItemIsEnabled
| Qt::ItemIsUserCheckable
;
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
)
353 Node
* n
= static_cast<Node
*>(index
.internalPointer());
357 Qt::CheckState newState
= static_cast<Qt::CheckState
>(value
.toInt());
360 bool reenable
= false;
361 if (emit_check_state_change
)
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
);
374 emit_check_state_change
= true;
378 bt::TorrentFileInterface
* file
= n
->file
;
379 if (newState
== Qt::Checked
)
381 if (file
->getPriority() == ONLY_SEED_PRIORITY
)
382 file
->setPriority(NORMAL_PRIORITY
);
384 file
->setDoNotDownload(false);
388 if (mode
== KEEP_FILES
)
389 file
->setPriority(ONLY_SEED_PRIORITY
);
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
)
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
)
422 invertCheck(index(0,0,QModelIndex()));
425 void TorrentFileTreeModel::invertCheck(const QModelIndex
& idx
)
427 Node
* n
= static_cast<Node
*>(idx
.internalPointer());
433 for (Uint32 i
= 0;i
< n
->children
.count();i
++)
435 // recurse down the tree
436 invertCheck(idx
.child(i
,0));
441 if (n
->file
->doNotDownload())
442 setData(idx
,Qt::Checked
,Qt::CheckStateRole
);
444 setData(idx
,Qt::Unchecked
,Qt::CheckStateRole
);
448 bt::Uint64
TorrentFileTreeModel::bytesToDownload()
450 if (tc
->getStats().multi_file_torrent
)
451 return root
->bytesToDownload(tc
);
453 return tc
->getStats().total_bytes
;
456 QByteArray
TorrentFileTreeModel::saveExpandedState(QTreeView
* tv
)
458 if (!tc
->getStats().multi_file_torrent
)
462 BEncoder
enc(new BEncoderBufferOutput(data
));
464 root
->saveExpandedState(index(0,0,QModelIndex()),tv
,&enc
);
470 void TorrentFileTreeModel::loadExpandedState(QTreeView
* tv
,const QByteArray
& state
)
472 if (!tc
->getStats().multi_file_torrent
)
475 BDecoder
dec(state
,false,0);
476 BNode
* n
= dec
.decode();
477 if (n
&& n
->getType() == BNode::DICT
)
480 root
->loadExpandedState(index(0,0,QModelIndex()),tv
,n
);
485 bt::TorrentFileInterface
* TorrentFileTreeModel::indexToFile(const QModelIndex
& idx
)
490 Node
* n
= (Node
*)idx
.internalPointer();
497 QString
TorrentFileTreeModel::dirPath(const QModelIndex
& idx
)
500 return QString::null
;
502 Node
* n
= (Node
*)idx
.internalPointer();
504 return QString::null
;
506 QString ret
= n
->name
;
511 ret
= n
->name
+ bt::DirSeparator() + ret
;
517 void TorrentFileTreeModel::changePriority(const QModelIndexList
& indexes
,bt::Priority newpriority
)
519 foreach (QModelIndex idx
,indexes
)
521 Node
* n
= (Node
*)idx
.internalPointer();
525 setData(idx
,newpriority
,Qt::UserRole
);
530 #include "torrentfiletreemodel.moc"