1 Star 0 Fork 1

陈炳煌/sqlitebrowser

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
RemoteModel.cpp 9.80 KB
一键复制 编辑 原始数据 按行查看 历史
Martin Kleusberg 提交于 2019-05-03 20:42 +08:00 . Use even less Qt containers
#include <QImage>
#include "RemoteModel.h"
#include "RemoteDatabase.h"
using json = nlohmann::json;
RemoteModelItem::RemoteModelItem(RemoteModelItem* parent) :
m_parent(parent),
m_fetchedDirectoryList(false)
{
}
RemoteModelItem::~RemoteModelItem()
{
qDeleteAll(m_children);
}
QVariant RemoteModelItem::value(RemoteModelColumns column) const
{
return m_values[column];
}
void RemoteModelItem::setValue(RemoteModelColumns column, QVariant value)
{
m_values[column] = value;
}
void RemoteModelItem::appendChild(RemoteModelItem *item)
{
m_children.push_back(item);
}
RemoteModelItem* RemoteModelItem::child(int row) const
{
return m_children[static_cast<size_t>(row)];
}
RemoteModelItem* RemoteModelItem::parent() const
{
return m_parent;
}
int RemoteModelItem::childCount() const
{
return static_cast<int>(m_children.size());
}
int RemoteModelItem::row() const
{
if(m_parent)
{
auto f = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), const_cast<RemoteModelItem*>(this));
if(f == m_parent->m_children.end())
return -1;
else
return static_cast<int>(std::distance(m_parent->m_children.begin(), f));
}
return 0;
}
bool RemoteModelItem::fetchedDirectoryList() const
{
return m_fetchedDirectoryList;
}
void RemoteModelItem::setFetchedDirectoryList(bool fetched)
{
m_fetchedDirectoryList = fetched;
}
std::vector<RemoteModelItem*> RemoteModelItem::loadArray(const json& array, RemoteModelItem* parent)
{
std::vector<RemoteModelItem*> items;
// Loop through all directory items
for(const auto& elem : array)
{
// Create a new model item with the specified parent
RemoteModelItem* item = new RemoteModelItem(parent);
// Save all relevant values. If one of the values isn't set in the JSON document, an empty string
// will be stored
item->setValue(RemoteModelColumnName, QString::fromStdString(elem["name"]));
item->setValue(RemoteModelColumnType, QString::fromStdString(elem["type"]));
item->setValue(RemoteModelColumnUrl, QString::fromStdString(elem["url"]));
item->setValue(RemoteModelColumnLastModified, QString::fromStdString(elem["last_modified"]));
if(elem.contains("commit_id"))
item->setValue(RemoteModelColumnCommitId, QString::fromStdString(elem["commit_id"]));
if(elem.contains("size"))
item->setValue(RemoteModelColumnSize, QString::number(static_cast<int>(elem["size"])));
items.push_back(item);
}
return items;
}
RemoteModel::RemoteModel(QObject* parent, RemoteDatabase& remote) :
QAbstractItemModel(parent),
rootItem(new RemoteModelItem()),
remoteDatabase(remote)
{
// Initialise list of column names
headerList << tr("Name") << tr("Commit") << tr("Last modified") << tr("Size");
// Set up signals
connect(&remoteDatabase, &RemoteDatabase::gotDirList, this, &RemoteModel::parseDirectoryListing);
}
RemoteModel::~RemoteModel()
{
delete rootItem;
}
void RemoteModel::setNewRootDir(const QString& url, const QString& cert)
{
// Get user name from client cert
currentUserName = remoteDatabase.getInfoFromClientCert(cert, RemoteDatabase::CertInfoUser);
// Save settings
currentRootDirectory = url;
currentClientCert = cert;
// Fetch root directory and put the reply data under the root item
remoteDatabase.fetch(currentRootDirectory, RemoteDatabase::RequestTypeDirectory, currentClientCert, QModelIndex());
}
void RemoteModel::parseDirectoryListing(const QString& text, const QVariant& userdata)
{
// Load new JSON root document assuming it's an array
json array = json::parse(text.toStdString(), nullptr, false);
if(array.is_discarded() || !array.is_array())
return;
// Get model index to store the new data under
QModelIndex parent = userdata.toModelIndex();
RemoteModelItem* parentItem = const_cast<RemoteModelItem*>(modelIndexToItem(parent));
// An invalid model index indicates that this is a new root item. This means the old one needs to be entirely deleted first.
if(!parent.isValid())
{
// Clear root item
beginResetModel();
delete rootItem;
rootItem = new RemoteModelItem();
endResetModel();
// Set parent model index and parent item to the new values
parent = QModelIndex();
parentItem = rootItem;
}
// Insert data
beginInsertRows(parent, 0, static_cast<int>(array.size()));
std::vector<RemoteModelItem*> items = RemoteModelItem::loadArray(array, parentItem);
for(RemoteModelItem* item : items)
parentItem->appendChild(item);
endInsertRows();
// Emit directory listing parsed signal
emit directoryListingParsed(parent);
}
QModelIndex RemoteModel::index(int row, int column, const QModelIndex& parent) const
{
if(!hasIndex(row, column, parent))
return QModelIndex();
const RemoteModelItem* parentItem = modelIndexToItem(parent);
RemoteModelItem* childItem = parentItem->child(row);
if(childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex RemoteModel::parent(const QModelIndex& index) const
{
if(!index.isValid())
return QModelIndex();
const RemoteModelItem* childItem = modelIndexToItem(index);
RemoteModelItem* parentItem = childItem->parent();
if(parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
QVariant RemoteModel::data(const QModelIndex& index, int role) const
{
// Don't return data for invalid indices
if(!index.isValid())
return QVariant();
// Type of item
const RemoteModelItem* item = modelIndexToItem(index);
QString type = item->value(RemoteModelColumnType).toString();
// Decoration role? Only for first column!
if(role == Qt::DecorationRole && index.column() == 0)
{
// Use different icons depending on item type
if(type == "folder" && index.parent() == QModelIndex() && item->value(RemoteModelColumnName) == currentUserName)
return QImage(":/icons/folder_user");
else if(type == "folder")
return QImage(":/icons/folder");
else if(type == "database")
return QImage(":/icons/database");
} else if(role == Qt::DisplayRole) {
// Display role?
// Return different value depending on column
switch(index.column())
{
case 0:
{
return item->value(RemoteModelColumnName);
}
case 1:
{
if(type == "folder")
return QVariant();
return item->value(RemoteModelColumnCommitId);
}
case 2:
{
return item->value(RemoteModelColumnLastModified);
}
case 3:
{
// Folders don't have a size
if(type == "folder")
return QVariant();
// Convert size to human readable format
float size = item->value(RemoteModelColumnSize).toFloat();
QStringList list;
list << "KiB" << "MiB" << "GiB" << "TiB";
QStringListIterator it(list);
QString unit(tr("bytes"));
while(size >= 1024.0f && it.hasNext())
{
unit = it.next();
size /= 1024.0f;
}
return QString().setNum(size, 'f', 2).remove(".00") + QString(" ") + unit;
}
}
}
return QVariant();
}
QVariant RemoteModel::headerData(int section, Qt::Orientation orientation, int role) const
{
// Call default implementation for vertical headers and for non-display roles
if(role != Qt::DisplayRole || orientation != Qt::Horizontal)
return QAbstractItemModel::headerData(section, orientation, role);
// Return header string depending on column
return headerList.at(section);
}
int RemoteModel::rowCount(const QModelIndex& parent) const
{
if(parent.column() > 0)
return 0;
const RemoteModelItem* parentItem = modelIndexToItem(parent);
return parentItem->childCount();
}
int RemoteModel::columnCount(const QModelIndex& /*parent*/) const
{
return headerList.size();
}
bool RemoteModel::hasChildren(const QModelIndex& parent) const
{
if(!parent.isValid())
return true;
// If the item actually has children or is of type "folder" (and may have no children yet), we say that it actually has children
const RemoteModelItem* item = modelIndexToItem(parent);
return item->childCount() || item->value(RemoteModelColumnType) == "folder";
}
bool RemoteModel::canFetchMore(const QModelIndex& parent) const
{
if(!parent.isValid())
return false;
// If the item is of type "folder" and we haven't tried fetching a directory listing yet, we indicate that there might be more data to load
const RemoteModelItem* item = modelIndexToItem(parent);
return item->value(RemoteModelColumnType) == "folder" && !item->fetchedDirectoryList();
}
void RemoteModel::fetchMore(const QModelIndex& parent)
{
// Can we even fetch more data?
if(!canFetchMore(parent))
return;
// Get parent item
RemoteModelItem* item = static_cast<RemoteModelItem*>(parent.internalPointer());
// Fetch item URL
item->setFetchedDirectoryList(true);
remoteDatabase.fetch(item->value(RemoteModelColumnUrl).toString(), RemoteDatabase::RequestTypeDirectory, currentClientCert, parent);
}
const QString& RemoteModel::currentClientCertificate() const
{
return currentClientCert;
}
const RemoteModelItem* RemoteModel::modelIndexToItem(const QModelIndex& idx) const
{
if(!idx.isValid())
return rootItem;
else
return static_cast<const RemoteModelItem*>(idx.internalPointer());
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/ax4688/sqlitebrowser.git
git@gitee.com:ax4688/sqlitebrowser.git
ax4688
sqlitebrowser
sqlitebrowser
master

搜索帮助