#include <QtCore/QUrl>
#include <QtCore/QVariant>
#include <QtXmlPatterns/QXmlNamePool>
#include "filetree.h"
FileTree::FileTree(const QXmlNamePool& pool)
: QSimpleXmlNodeModel(pool),
m_filterAllowAll(QDir::AllEntries |
QDir::AllDirs |
QDir::NoDotAndDotDot |
QDir::Hidden),
m_sortFlags(QDir::Name)
{
QXmlNamePool np = namePool();
m_names.resize(7);
m_names[File] = QXmlName(np, QLatin1String("file"));
m_names[Directory] = QXmlName(np, QLatin1String("directory"));
m_names[AttributeFileName] = QXmlName(np, QLatin1String("fileName"));
m_names[AttributeFilePath] = QXmlName(np, QLatin1String("filePath"));
m_names[AttributeSize] = QXmlName(np, QLatin1String("size"));
m_names[AttributeMIMEType] = QXmlName(np, QLatin1String("mimeType"));
m_names[AttributeSuffix] = QXmlName(np, QLatin1String("suffix"));
}
QXmlNodeModelIndex FileTree::nodeFor(const QString& dirName) const
{
QFileInfo dirInfo(QDir::cleanPath(dirName));
Q_ASSERT(dirInfo.exists());
return toNodeIndex(dirInfo);
}
const QFileInfo&
FileTree::toFileInfo(const QXmlNodeModelIndex &nodeIndex) const
{
return m_fileInfos.at(nodeIndex.data());
}
QXmlNodeModelIndex
FileTree::toNodeIndex(const QFileInfo &fileInfo, Type attributeName) const
{
const int indexOf = m_fileInfos.indexOf(fileInfo);
if (indexOf == -1) {
m_fileInfos.append(fileInfo);
return createIndex(m_fileInfos.count()-1, attributeName);
}
else
return createIndex(indexOf, attributeName);
}
QXmlNodeModelIndex FileTree::toNodeIndex(const QFileInfo &fileInfo) const
{
return toNodeIndex(fileInfo, fileInfo.isDir() ? Directory : File);
}
QXmlNodeModelIndex FileTree::nextSibling(const QXmlNodeModelIndex &nodeIndex,
const QFileInfo &fileInfo,
qint8 offset) const
{
Q_ASSERT(offset == -1 || offset == 1);
// Get the context node's parent.
const QXmlNodeModelIndex parent(nextFromSimpleAxis(Parent, nodeIndex));
if (parent.isNull())
return QXmlNodeModelIndex();
// Get the parent's child list.
const QFileInfo parentFI(toFileInfo(parent));
Q_ASSERT(Type(parent.additionalData()) == Directory);
const QFileInfoList siblings(QDir(parentFI.absoluteFilePath()).entryInfoList(QStringList(),
m_filterAllowAll,
m_sortFlags));
Q_ASSERT_X(!siblings.isEmpty(), Q_FUNC_INFO, "Can't happen! We started at a child.");
// Find the index of the child where we started.
const int indexOfMe = siblings.indexOf(fileInfo);
// Apply the offset.
const int siblingIndex = indexOfMe + offset;
if (siblingIndex < 0 || siblingIndex > siblings.count() - 1)
return QXmlNodeModelIndex();
else
return toNodeIndex(siblings.at(siblingIndex));
}
//! [5]
QXmlNodeModelIndex
FileTree::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &nodeIndex) const
{
const QFileInfo fi(toFileInfo(nodeIndex));
const Type type = Type(nodeIndex.additionalData());
if (type != File && type != Directory) {
Q_ASSERT_X(axis == Parent, Q_FUNC_INFO, "An attribute only has a parent!");
return toNodeIndex(fi, Directory);
}
switch (axis) {
case Parent:
return toNodeIndex(QFileInfo(fi.path()), Directory);
case FirstChild:
{
if (type == File) // A file has no children.
return QXmlNodeModelIndex();
else {
Q_ASSERT(type == Directory);
Q_ASSERT_X(fi.isDir(), Q_FUNC_INFO, "It isn't really a directory!");
const QDir dir(fi.absoluteFilePath());
Q_ASSERT(dir.exists());
const QFileInfoList children(dir.entryInfoList(QStringList(),
m_filterAllowAll,
m_sortFlags));
if (children.isEmpty())
return QXmlNodeModelIndex();
const QFileInfo firstChild(children.first());
return toNodeIndex(firstChild);
}
}
case PreviousSibling:
return nextSibling(nodeIndex, fi, -1);
case NextSibling:
return nextSibling(nodeIndex, fi, 1);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Don't ever get here!");
return QXmlNodeModelIndex();
}
QUrl FileTree::documentUri(const QXmlNodeModelIndex &node) const
{
Q_UNUSED(node);
return QUrl("file:///");
}
QXmlNodeModelIndex::NodeKind
FileTree::kind(const QXmlNodeModelIndex &node) const
{
switch (Type(node.additionalData())) {
case Directory:
case File:
return QXmlNodeModelIndex::Element;
default:
return QXmlNodeModelIndex::Attribute;
}
}
QXmlNodeModelIndex::DocumentOrder
FileTree::compareOrder(const QXmlNodeModelIndex&,
const QXmlNodeModelIndex&) const
{
return QXmlNodeModelIndex::Is;
}
QXmlName FileTree::name(const QXmlNodeModelIndex &node) const
{
return m_names.at(node.additionalData());
}
QXmlNodeModelIndex FileTree::root(const QXmlNodeModelIndex &node) const
{
Q_UNUSED(node);
return toNodeIndex(QFileInfo(QLatin1String("/")));
}
QVariant FileTree::typedValue(const QXmlNodeModelIndex &node) const
{
const QFileInfo &fi = toFileInfo(node);
switch (Type(node.additionalData())) {
case Directory:
// deliberate fall through.
case File:
return QString();
case AttributeFileName:
return fi.fileName();
case AttributeFilePath:
return fi.filePath();
case AttributeSize:
return fi.size();
case AttributeMIMEType:
{
/* We don't have any MIME detection code currently, so return
* the most generic one. */
return QLatin1String("application/octet-stream");
}
case AttributeSuffix:
return fi.suffix();
}
Q_ASSERT_X(false, Q_FUNC_INFO, "This line should never be reached.");
return QString();
}
QVector<QXmlNodeModelIndex>
FileTree::attributes(const QXmlNodeModelIndex &element) const
{
QVector<QXmlNodeModelIndex> result;
/* Both elements has this attribute. */
const QFileInfo &forElement = toFileInfo(element);
result.append(toNodeIndex(forElement, AttributeFilePath));
result.append(toNodeIndex(forElement, AttributeFileName));
if (Type(element.additionalData() == File)) {
result.append(toNodeIndex(forElement, AttributeSize));
result.append(toNodeIndex(forElement, AttributeSuffix));
//result.append(toNodeIndex(forElement, AttributeMIMEType));
}
else {
Q_ASSERT(element.additionalData() == Directory);
}
return result;
}