mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
Use PascalCase for Qt client filenames
Split FileTree.{h,cc} and FilterBar.{h,cc} files so that each class
is in its own file.
This breaks translations (some classes got renamed => context changed),
to be fixed by next commit (along with Tx sync).
This commit is contained in:
386
qt/FileTreeModel.cc
Normal file
386
qt/FileTreeModel.cc
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* This file Copyright (C) 2009-2015 Mnemosyne LLC
|
||||
*
|
||||
* It may be used under the GNU GPL versions 2 or 3
|
||||
* or any future license endorsed by Mnemosyne LLC.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "FileTreeItem.h"
|
||||
#include "FileTreeModel.h"
|
||||
|
||||
FileTreeModel::FileTreeModel (QObject * parent, bool isEditable):
|
||||
QAbstractItemModel(parent),
|
||||
myRootItem (new FileTreeItem),
|
||||
myIndexCache (),
|
||||
myIsEditable (isEditable)
|
||||
{
|
||||
}
|
||||
|
||||
FileTreeModel::~FileTreeModel()
|
||||
{
|
||||
clear();
|
||||
|
||||
delete myRootItem;
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::setEditable (bool editable)
|
||||
{
|
||||
myIsEditable = editable;
|
||||
}
|
||||
|
||||
FileTreeItem *
|
||||
FileTreeModel::itemFromIndex (const QModelIndex& index) const
|
||||
{
|
||||
return static_cast<FileTreeItem*>(index.internalPointer());
|
||||
}
|
||||
|
||||
QVariant
|
||||
FileTreeModel::data (const QModelIndex &index, int role) const
|
||||
{
|
||||
QVariant value;
|
||||
|
||||
if (index.isValid())
|
||||
value = itemFromIndex(index)->data (index.column(), role);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
Qt::ItemFlags
|
||||
FileTreeModel::flags (const QModelIndex& index) const
|
||||
{
|
||||
int i(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
if(myIsEditable && (index.column() == COL_NAME))
|
||||
i |= Qt::ItemIsEditable;
|
||||
|
||||
if(index.column() == COL_WANTED)
|
||||
i |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
|
||||
|
||||
return (Qt::ItemFlags)i;
|
||||
}
|
||||
|
||||
bool
|
||||
FileTreeModel::setData (const QModelIndex& index, const QVariant& newname, int role)
|
||||
{
|
||||
if (role == Qt::EditRole)
|
||||
{
|
||||
FileTreeItem * item = itemFromIndex (index);
|
||||
|
||||
emit pathEdited (item->path (), newname.toString ());
|
||||
}
|
||||
|
||||
return false; // don't update the view until the session confirms the change
|
||||
}
|
||||
|
||||
QVariant
|
||||
FileTreeModel::headerData (int column, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant data;
|
||||
|
||||
if (orientation==Qt::Horizontal && role==Qt::DisplayRole)
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
case COL_NAME:
|
||||
data.setValue (tr("File"));
|
||||
break;
|
||||
|
||||
case COL_SIZE:
|
||||
data.setValue (tr("Size"));
|
||||
break;
|
||||
|
||||
case COL_PROGRESS:
|
||||
data.setValue (tr("Progress"));
|
||||
break;
|
||||
|
||||
case COL_WANTED:
|
||||
data.setValue (tr("Download"));
|
||||
break;
|
||||
|
||||
case COL_PRIORITY:
|
||||
data.setValue (tr("Priority"));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
FileTreeModel::index (int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
QModelIndex i;
|
||||
|
||||
if (hasIndex (row, column, parent))
|
||||
{
|
||||
FileTreeItem * parentItem;
|
||||
|
||||
if (!parent.isValid ())
|
||||
parentItem = myRootItem;
|
||||
else
|
||||
parentItem = itemFromIndex (parent);
|
||||
|
||||
FileTreeItem * childItem = parentItem->child (row);
|
||||
|
||||
if (childItem)
|
||||
i = createIndex (row, column, childItem);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
FileTreeModel::parent (const QModelIndex& child) const
|
||||
{
|
||||
return parent (child, 0); // QAbstractItemModel::parent() wants col 0
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
FileTreeModel::parent (const QModelIndex& child, int column) const
|
||||
{
|
||||
QModelIndex parent;
|
||||
|
||||
if (child.isValid())
|
||||
parent = indexOf (itemFromIndex(child)->parent(), column);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
int
|
||||
FileTreeModel::rowCount (const QModelIndex& parent) const
|
||||
{
|
||||
FileTreeItem * parentItem;
|
||||
|
||||
if (parent.isValid())
|
||||
parentItem = itemFromIndex (parent);
|
||||
else
|
||||
parentItem = myRootItem;
|
||||
|
||||
return parentItem->childCount();
|
||||
}
|
||||
|
||||
int
|
||||
FileTreeModel::columnCount (const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return NUM_COLUMNS;
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
FileTreeModel::indexOf (FileTreeItem * item, int column) const
|
||||
{
|
||||
if (!item || item==myRootItem)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(item->row(), column, item);
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::clearSubtree (const QModelIndex& top)
|
||||
{
|
||||
size_t i = rowCount (top);
|
||||
|
||||
while (i > 0)
|
||||
clearSubtree(index(--i, 0, top));
|
||||
|
||||
FileTreeItem * const item = itemFromIndex (top);
|
||||
if (item == 0)
|
||||
return;
|
||||
|
||||
if (item->fileIndex () != -1)
|
||||
myIndexCache.remove (item->fileIndex ());
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::clear ()
|
||||
{
|
||||
beginResetModel ();
|
||||
clearSubtree (QModelIndex());
|
||||
endResetModel ();
|
||||
|
||||
assert (myIndexCache.isEmpty ());
|
||||
}
|
||||
|
||||
FileTreeItem *
|
||||
FileTreeModel::findItemForFileIndex (int fileIndex) const
|
||||
{
|
||||
return myIndexCache.value (fileIndex, 0);
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::addFile (int fileIndex,
|
||||
const QString & filename,
|
||||
bool wanted,
|
||||
int priority,
|
||||
uint64_t totalSize,
|
||||
uint64_t have,
|
||||
QList<QModelIndex> & rowsAdded,
|
||||
bool updateFields)
|
||||
{
|
||||
FileTreeItem * item;
|
||||
QStringList tokens = filename.split (QChar::fromLatin1('/'));
|
||||
|
||||
item = findItemForFileIndex (fileIndex);
|
||||
|
||||
if (item) // this file is already in the tree, we've added this
|
||||
{
|
||||
QModelIndex indexWithChangedParents;
|
||||
while (!tokens.isEmpty())
|
||||
{
|
||||
const QString token = tokens.takeLast();
|
||||
const std::pair<int,int> changed = item->update (token, wanted, priority, have, updateFields);
|
||||
if (changed.first >= 0)
|
||||
{
|
||||
dataChanged (indexOf (item, changed.first), indexOf (item, changed.second));
|
||||
if (!indexWithChangedParents.isValid () &&
|
||||
changed.first <= COL_PRIORITY && changed.second >= COL_SIZE)
|
||||
indexWithChangedParents = indexOf (item, 0);
|
||||
}
|
||||
item = item->parent();
|
||||
}
|
||||
assert (item == myRootItem);
|
||||
if (indexWithChangedParents.isValid ())
|
||||
parentsChanged (indexWithChangedParents, COL_SIZE, COL_PRIORITY);
|
||||
}
|
||||
else // we haven't build the FileTreeItems for these tokens yet
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
item = myRootItem;
|
||||
while (!tokens.isEmpty())
|
||||
{
|
||||
const QString token = tokens.takeFirst();
|
||||
FileTreeItem * child(item->child(token));
|
||||
if (!child)
|
||||
{
|
||||
added = true;
|
||||
QModelIndex parentIndex (indexOf(item, 0));
|
||||
const int n (item->childCount());
|
||||
|
||||
beginInsertRows (parentIndex, n, n);
|
||||
if (tokens.isEmpty())
|
||||
child = new FileTreeItem (token, fileIndex, totalSize);
|
||||
else
|
||||
child = new FileTreeItem (token);
|
||||
item->appendChild (child);
|
||||
endInsertRows ();
|
||||
|
||||
rowsAdded.append (indexOf(child, 0));
|
||||
}
|
||||
item = child;
|
||||
}
|
||||
|
||||
if (item != myRootItem)
|
||||
{
|
||||
assert (item->fileIndex() == fileIndex);
|
||||
assert (item->totalSize() == totalSize);
|
||||
|
||||
myIndexCache[fileIndex] = item;
|
||||
|
||||
const std::pair<int,int> changed = item->update (item->name(), wanted, priority, have, added || updateFields);
|
||||
if (changed.first >= 0)
|
||||
dataChanged (indexOf (item, changed.first), indexOf (item, changed.second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::parentsChanged (const QModelIndex& index, int firstColumn, int lastColumn)
|
||||
{
|
||||
assert (firstColumn <= lastColumn);
|
||||
|
||||
QModelIndex walk = index;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
walk = parent (walk, firstColumn);
|
||||
if (!walk.isValid ())
|
||||
break;
|
||||
|
||||
dataChanged (walk, walk.sibling (walk.row (), lastColumn));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::subtreeChanged (const QModelIndex& index, int firstColumn, int lastColumn)
|
||||
{
|
||||
assert (firstColumn <= lastColumn);
|
||||
|
||||
const int childCount = rowCount (index);
|
||||
if (!childCount)
|
||||
return;
|
||||
|
||||
// tell everyone that this tier changed
|
||||
dataChanged (index.child (0, firstColumn), index.child (childCount - 1, lastColumn));
|
||||
|
||||
// walk the subtiers
|
||||
for (int i=0; i<childCount; ++i)
|
||||
subtreeChanged (index.child (i, 0), firstColumn, lastColumn);
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::clicked (const QModelIndex& index)
|
||||
{
|
||||
const int column (index.column());
|
||||
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
if (column == COL_WANTED)
|
||||
{
|
||||
bool want;
|
||||
QSet<int> file_ids;
|
||||
FileTreeItem * item;
|
||||
|
||||
item = itemFromIndex (index);
|
||||
item->twiddleWanted (file_ids, want);
|
||||
emit wantedChanged (file_ids, want);
|
||||
|
||||
dataChanged (index, index);
|
||||
parentsChanged (index, COL_SIZE, COL_WANTED);
|
||||
subtreeChanged (index, COL_WANTED, COL_WANTED);
|
||||
}
|
||||
else if (column == COL_PRIORITY)
|
||||
{
|
||||
int priority;
|
||||
QSet<int> file_ids;
|
||||
FileTreeItem * item;
|
||||
|
||||
item = itemFromIndex (index);
|
||||
item->twiddlePriority (file_ids, priority);
|
||||
emit priorityChanged (file_ids, priority);
|
||||
|
||||
dataChanged (index, index);
|
||||
parentsChanged (index, column, column);
|
||||
subtreeChanged (index, column, column);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileTreeModel::doubleClicked (const QModelIndex& index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
const int column (index.column());
|
||||
if (column == COL_WANTED || column == COL_PRIORITY)
|
||||
return;
|
||||
|
||||
FileTreeItem * item = itemFromIndex (index);
|
||||
|
||||
if (item->childCount () == 0 && item->isComplete ())
|
||||
emit openRequested (item->path ());
|
||||
}
|
||||
Reference in New Issue
Block a user