Created
December 3, 2010 02:06
-
-
Save kovrov/726464 to your computer and use it in GitHub Desktop.
QMF FolderListModel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Qt | |
#include <QMap> | |
#include <QtAlgorithms> | |
// QMF | |
#include <qmfclient/qmailstore.h> // QMailStore | |
// project | |
#include "folderlistmodel.h" | |
#define CONNECT(a,b,c,d) if (!QObject::connect(a,b,c,d)) { Q_ASSERT (false); } | |
struct TreeItem | |
{ | |
TreeItem(const QMailFolderId &folder_id, const QString &folder_name, TreeItem *parent_ptr) | |
: parent (parent_ptr), | |
id (folder_id), | |
name (folder_name) | |
{} | |
~TreeItem() | |
{ | |
qDeleteAll(children); | |
} | |
QList<TreeItem*> children; | |
TreeItem *parent; | |
QMailFolderId id; | |
QString name; | |
}; | |
FolderListModel::FolderListModel(QObject *parent) | |
: QAbstractItemModel(parent), | |
mRootItem (NULL) | |
{ | |
QMailStore *store = QMailStore::instance(); | |
CONNECT (store, SIGNAL(accountsRemoved(QMailAccountIdList)), | |
this, SLOT(onAccountsRemoved(QMailAccountIdList))); | |
CONNECT (store, SIGNAL(foldersAdded(QMailFolderIdList)), | |
this, SLOT(onFoldersAdded(QMailFolderIdList))); | |
CONNECT (store, SIGNAL(foldersUpdated(QMailFolderIdList)), | |
this, SLOT(onFoldersUpdated(QMailFolderIdList))); | |
CONNECT (store, SIGNAL(foldersRemoved(QMailFolderIdList)), | |
this, SLOT(onFoldersRemoved(QMailFolderIdList))); | |
} | |
FolderListModel::~FolderListModel() | |
{ | |
delete mRootItem; | |
} | |
static | |
void recursive_setup(const QMailAccountId &account_id, TreeItem *parent) | |
{ | |
QMailFolderKey key | |
= QMailFolderKey(QMailFolderKey::parentAccountId(account_id)) | |
& QMailFolderKey(QMailFolderKey::parentFolderId(parent->id)) | |
& QMailFolderKey(QMailFolderKey::status(QMailFolder::NonMail, | |
QMailDataComparator::Excludes)); | |
foreach (const QMailFolderId &id, QMailStore::instance()->queryFolders(key)) { | |
const QMailFolder folder(id); | |
TreeItem *item = new TreeItem(folder.id(), folder.displayName(), parent); | |
parent->children.append(item); | |
recursive_setup(account_id, item); | |
} | |
} | |
void FolderListModel::setAccountId(const QMailAccountId &id) | |
{ | |
if (mRootItem && QMailFolder(mRootItem->id).parentAccountId() == id) | |
return; | |
QMailAccount account(id); | |
if (!account.id().isValid()) { | |
if (mRootItem) { | |
delete mRootItem; | |
mRootItem = NULL; | |
emit layoutChanged(); | |
} | |
return; | |
} | |
emit layoutAboutToBeChanged(); | |
if (mRootItem) | |
delete mRootItem; | |
mRootItem = new TreeItem(QMailFolderId(), account.name(), NULL); | |
recursive_setup(id, mRootItem); | |
emit layoutChanged(); | |
} | |
QMailFolderId FolderListModel::idFromIndex(const QModelIndex &index) const | |
{ | |
if (!index.isValid()) | |
return QMailFolderId(); | |
return static_cast<TreeItem*>(index.internalPointer())->id; | |
} | |
int FolderListModel::rowCount(const QModelIndex &parent) const | |
{ | |
if (parent.column() > 0) | |
return 0; | |
if (NULL == mRootItem) | |
return 0; | |
TreeItem *parent_item = parent.isValid() | |
? static_cast<TreeItem*>(parent.internalPointer()) | |
: mRootItem; | |
return parent_item->children.count(); | |
} | |
int FolderListModel::columnCount(const QModelIndex &parent) const | |
{ | |
Q_UNUSED (parent); | |
return 1; | |
} | |
QVariant FolderListModel::data(const QModelIndex &index, int role) const | |
{ | |
if (!index.isValid()) | |
return QVariant(); | |
if (role != Qt::DisplayRole) | |
return QVariant(); | |
return static_cast<TreeItem*>(index.internalPointer())->name; | |
} | |
Qt::ItemFlags FolderListModel::flags(const QModelIndex &index) const | |
{ | |
if (!index.isValid()) | |
return 0; | |
return Qt::ItemIsEnabled | Qt::ItemIsSelectable; | |
} | |
QModelIndex FolderListModel::index(int row, int column, const QModelIndex &parent) const | |
{ | |
if (!hasIndex(row, column, parent)) | |
return QModelIndex(); | |
TreeItem *parent_item = parent.isValid() | |
? static_cast<TreeItem*>(parent.internalPointer()) | |
: mRootItem; | |
Q_ASSERT (parent_item); | |
if (TreeItem *tree_item = parent_item->children.value(row)) | |
return createIndex(row, column, tree_item); | |
return QModelIndex(); | |
} | |
QModelIndex FolderListModel::parent(const QModelIndex &index) const | |
{ | |
if (!index.isValid()) | |
return QModelIndex(); | |
TreeItem *parent_item = static_cast<TreeItem*>(index.internalPointer())->parent; | |
if (parent_item == mRootItem) | |
return QModelIndex(); | |
int row = parent_item->parent | |
? parent_item->parent->children.indexOf(parent_item) | |
: 0; | |
return createIndex(row, 0, parent_item); | |
} | |
void FolderListModel::onAccountsRemoved(const QMailAccountIdList &list) | |
{ | |
if (NULL == mRootItem) | |
return; | |
if (list.indexOf(QMailFolder(mRootItem->id).parentAccountId()) == -1) | |
return; | |
delete mRootItem; | |
mRootItem = NULL; | |
emit layoutChanged(); | |
} | |
static | |
TreeItem* find_node(TreeItem* tree_item, const QMailFolderId &id) | |
{ | |
Q_ASSERT (NULL != tree_item); | |
if (tree_item->id == id) | |
return tree_item; | |
foreach (TreeItem *child_item, tree_item->children) { | |
if (TreeItem *res = find_node(child_item, id)) | |
return res; | |
} | |
return NULL; | |
} | |
void FolderListModel::onFoldersAdded(const QMailFolderIdList &list) | |
{ | |
const QMailAccountId &folder_id = QMailFolder(mRootItem->id).parentAccountId(); | |
QMap<TreeItem*, QList<TreeItem*> > new_folders; | |
foreach (const QMailFolderId &id, list) { | |
const QMailFolder folder(id); | |
TreeItem *parent_item = find_node(mRootItem, folder.parentFolderId()); | |
if (NULL == parent_item) | |
continue; | |
new_folders[parent_item] << new TreeItem(folder.id(), folder.displayName(), parent_item); | |
} | |
foreach (TreeItem *parent_item, new_folders.keys()) { | |
const QModelIndex &parent_index = (parent_item->parent) | |
? createIndex(parent_item->parent->children.indexOf(parent_item), 0, parent_item) | |
: QModelIndex(); | |
int first = parent_item->children.count(); | |
int last = first + new_folders[parent_item].count(); | |
beginInsertRows(parent_index, first, last); | |
foreach (TreeItem *item, new_folders[parent_item]) { | |
Q_ASSERT (item->parent == parent_item); | |
item->parent->children.append(item); | |
recursive_setup(folder_id, item); | |
} | |
endInsertRows(); | |
} | |
} | |
static | |
void find_all_in(const QMailFolderIdList &list, TreeItem *parent, QList<TreeItem*> *res) | |
{ | |
if (list.indexOf(parent->id) != -1) | |
res->append(parent); | |
foreach (TreeItem *item, parent->children) | |
find_all_in(list, item, res); | |
} | |
void FolderListModel::onFoldersUpdated(const QMailFolderIdList &list) | |
{ | |
QList<TreeItem*> found; | |
find_all_in(list, mRootItem, &found); | |
foreach (TreeItem *item, found) { | |
const QMailFolder folder(item->id); | |
if (folder.displayName() != item->name) { | |
item->name = folder.displayName(); | |
const QModelIndex &index = (item->parent) | |
? createIndex(item->parent->children.indexOf(item), 0, item) | |
: QModelIndex(); | |
emit dataChanged(index, index); | |
} | |
} | |
} | |
static | |
void find_roots_in(const QMailFolderIdList &list, TreeItem *parent, QList<TreeItem*> *res) | |
{ | |
if (list.indexOf(parent->id) != -1) { | |
res->append(parent); | |
return; | |
} | |
foreach (TreeItem *item, parent->children) | |
find_roots_in(list, item, res); | |
} | |
void FolderListModel::onFoldersRemoved(const QMailFolderIdList &list) | |
{ | |
if (NULL == mRootItem) | |
return; | |
if (list.indexOf(mRootItem->id) != -1) { | |
delete mRootItem; | |
mRootItem = NULL; | |
// TODO: emit rowsRemoved instead of | |
emit layoutChanged(); | |
return; | |
} | |
QList<TreeItem*> found; | |
find_roots_in(list, mRootItem, &found); | |
if (found.isEmpty()) | |
return; | |
QMap<TreeItem*, QList<TreeItem*> > folders; | |
foreach (TreeItem* item, found) { | |
folders[item->parent] << item; | |
} | |
foreach (TreeItem *parent_item, folders.keys()) { | |
const QModelIndex &parent_index = (parent_item->parent) | |
? createIndex(parent_item->parent->children.indexOf(parent_item), 0, parent_item) | |
: QModelIndex(); | |
QList<int> indices; | |
foreach (TreeItem *item, folders[parent_item]) { | |
Q_ASSERT (item->parent == parent_item); | |
indices << parent_item->children.indexOf(item); | |
} | |
qSort(indices); | |
int begin = indices.takeLast(); | |
int end = begin; | |
do { | |
if (!indices.isEmpty() && begin - 1 == indices.last()) { | |
begin = indices.takeLast(); | |
if (!indices.isEmpty()) | |
continue; | |
} | |
beginRemoveRows(parent_index, begin, end); | |
auto it = parent_item->children.begin(); | |
parent_item->children.erase(it + begin, it + end + 1); | |
endRemoveRows(); | |
if (!indices.isEmpty()) { | |
begin = indices.takeLast(); | |
end = begin; | |
} | |
} | |
while (!indices.isEmpty()); | |
} | |
qDeleteAll(found); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FOLDERLISTMODEL_H | |
#define FOLDERLISTMODEL_H | |
#include <QAbstractItemModel> | |
#include <qmfclient/qmailid.h> | |
class FolderListModel : public QAbstractItemModel | |
{ | |
Q_OBJECT | |
public: | |
explicit FolderListModel(QObject *parent = 0); | |
virtual ~FolderListModel(); | |
void setAccountId(const QMailAccountId &id); | |
QMailFolderId idFromIndex(const QModelIndex &index) const; | |
QVariant data(const QModelIndex &index, int role) const; | |
Qt::ItemFlags flags(const QModelIndex &index) const; | |
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; | |
QModelIndex parent(const QModelIndex &index) const; | |
int rowCount(const QModelIndex &parent = QModelIndex()) const; | |
int columnCount(const QModelIndex &parent = QModelIndex()) const; | |
private slots: | |
void onAccountsRemoved(const QMailAccountIdList &); | |
void onFoldersAdded(const QMailFolderIdList &); | |
void onFoldersUpdated(const QMailFolderIdList &); | |
void onFoldersRemoved(const QMailFolderIdList &); | |
private: | |
struct TreeItem *mRootItem; | |
}; | |
#endif // FOLDERLISTMODEL_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment