source: trunk/examples/xmlpatterns/filetree/filetree.cpp@ 168

Last change on this file since 168 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 12.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtCore/QUrl>
43#include <QtCore/QVariant>
44#include <QtXmlPatterns/QXmlNamePool>
45#include "filetree.h"
46
47/*
48The model has two types of nodes: elements & attributes.
49
50 <directory name="">
51 <file name="">
52 </file>
53 </directory>
54
55 In QXmlNodeModelIndex we store two values. QXmlNodeIndex::data()
56 is treated as a signed int, and it is an index into m_fileInfos
57 unless it is -1, in which case it has no meaning and the value
58 of QXmlNodeModelIndex::additionalData() is a Type name instead.
59 */
60
61/*!
62 The constructor passes \a pool to the base class, then loads an
63 internal vector with an instance of QXmlName for each of the
64 strings "file", "directory", "fileName", "filePath", "size",
65 "mimeType", and "suffix".
66 */
67//! [2]
68FileTree::FileTree(const QXmlNamePool& pool)
69 : QSimpleXmlNodeModel(pool),
70 m_filterAllowAll(QDir::AllEntries |
71 QDir::AllDirs |
72 QDir::NoDotAndDotDot |
73 QDir::Hidden),
74 m_sortFlags(QDir::Name)
75{
76 QXmlNamePool np = namePool();
77 m_names.resize(7);
78 m_names[File] = QXmlName(np, QLatin1String("file"));
79 m_names[Directory] = QXmlName(np, QLatin1String("directory"));
80 m_names[AttributeFileName] = QXmlName(np, QLatin1String("fileName"));
81 m_names[AttributeFilePath] = QXmlName(np, QLatin1String("filePath"));
82 m_names[AttributeSize] = QXmlName(np, QLatin1String("size"));
83 m_names[AttributeMIMEType] = QXmlName(np, QLatin1String("mimeType"));
84 m_names[AttributeSuffix] = QXmlName(np, QLatin1String("suffix"));
85}
86//! [2]
87
88/*!
89 Returns the QXmlNodeModelIndex for the model node representing
90 the directory \a dirName.
91
92 It calls QDir::cleanPath(), because an instance of QFileInfo
93 constructed for a path ending in '/' will return the empty string in
94 fileName(), instead of the directory name.
95*/
96QXmlNodeModelIndex FileTree::nodeFor(const QString& dirName) const
97{
98 QFileInfo dirInfo(QDir::cleanPath(dirName));
99 Q_ASSERT(dirInfo.exists());
100 return toNodeIndex(dirInfo);
101}
102
103/*!
104 Since the value will always be in m_fileInfos, it is safe for
105 us to return a const reference to it.
106 */
107//! [6]
108const QFileInfo&
109FileTree::toFileInfo(const QXmlNodeModelIndex &nodeIndex) const
110{
111 return m_fileInfos.at(nodeIndex.data());
112}
113//! [6]
114
115/*!
116 Returns the model node index for the node specified by the
117 QFileInfo and node Type.
118 */
119//! [1]
120QXmlNodeModelIndex
121FileTree::toNodeIndex(const QFileInfo &fileInfo, Type attributeName) const
122{
123 const int indexOf = m_fileInfos.indexOf(fileInfo);
124
125 if (indexOf == -1) {
126 m_fileInfos.append(fileInfo);
127 return createIndex(m_fileInfos.count()-1, attributeName);
128 }
129 else
130 return createIndex(indexOf, attributeName);
131}
132//! [1]
133
134/*!
135 Returns the model node index for the node specified by the
136 QFileInfo, which must be a Type::File or Type::Directory.
137 */
138//! [0]
139QXmlNodeModelIndex FileTree::toNodeIndex(const QFileInfo &fileInfo) const
140{
141 return toNodeIndex(fileInfo, fileInfo.isDir() ? Directory : File);
142}
143//! [0]
144
145/*!
146 This private helper function is only called by nextFromSimpleAxis().
147 It is called whenever nextFromSimpleAxis() is called with an axis
148 parameter of either \c{PreviousSibling} or \c{NextSibling}.
149 */
150//! [5]
151QXmlNodeModelIndex FileTree::nextSibling(const QXmlNodeModelIndex &nodeIndex,
152 const QFileInfo &fileInfo,
153 qint8 offset) const
154{
155 Q_ASSERT(offset == -1 || offset == 1);
156
157 // Get the context node's parent.
158 const QXmlNodeModelIndex parent(nextFromSimpleAxis(Parent, nodeIndex));
159
160 if (parent.isNull())
161 return QXmlNodeModelIndex();
162
163 // Get the parent's child list.
164 const QFileInfo parentFI(toFileInfo(parent));
165 Q_ASSERT(Type(parent.additionalData()) == Directory);
166 const QFileInfoList siblings(QDir(parentFI.absoluteFilePath()).entryInfoList(QStringList(),
167 m_filterAllowAll,
168 m_sortFlags));
169 Q_ASSERT_X(!siblings.isEmpty(), Q_FUNC_INFO, "Can't happen! We started at a child.");
170
171 // Find the index of the child where we started.
172 const int indexOfMe = siblings.indexOf(fileInfo);
173
174 // Apply the offset.
175 const int siblingIndex = indexOfMe + offset;
176 if (siblingIndex < 0 || siblingIndex > siblings.count() - 1)
177 return QXmlNodeModelIndex();
178 else
179 return toNodeIndex(siblings.at(siblingIndex));
180}
181//! [5]
182
183/*!
184 This function is called by the QtXmlPatterns query engine when it
185 wants to move to the next node in the model. It moves along an \a
186 axis, \e from the node specified by \a nodeIndex.
187
188 This function is usually the one that requires the most design and
189 implementation work, because the implementation depends on the
190 perhaps unique structure of your non-XML data.
191
192 There are \l {QAbstractXmlNodeModel::SimpleAxis} {four values} for
193 \a axis that the implementation must handle, but there are really
194 only two axes, i.e., vertical and horizontal. Two of the four values
195 specify direction on the vertical axis (\c{Parent} and
196 \c{FirstChild}), and the other two values specify direction on the
197 horizontal axis (\c{PreviousSibling} and \c{NextSibling}).
198
199 The typical implementation will be a \c switch statement with
200 a case for each of the four \a axis values.
201 */
202//! [4]
203QXmlNodeModelIndex
204FileTree::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &nodeIndex) const
205{
206 const QFileInfo fi(toFileInfo(nodeIndex));
207 const Type type = Type(nodeIndex.additionalData());
208
209 if (type != File && type != Directory) {
210 Q_ASSERT_X(axis == Parent, Q_FUNC_INFO, "An attribute only has a parent!");
211 return toNodeIndex(fi, Directory);
212 }
213
214 switch (axis) {
215 case Parent:
216 return toNodeIndex(QFileInfo(fi.path()), Directory);
217
218 case FirstChild:
219 {
220 if (type == File) // A file has no children.
221 return QXmlNodeModelIndex();
222 else {
223 Q_ASSERT(type == Directory);
224 Q_ASSERT_X(fi.isDir(), Q_FUNC_INFO, "It isn't really a directory!");
225 const QDir dir(fi.absoluteFilePath());
226 Q_ASSERT(dir.exists());
227
228 const QFileInfoList children(dir.entryInfoList(QStringList(),
229 m_filterAllowAll,
230 m_sortFlags));
231 if (children.isEmpty())
232 return QXmlNodeModelIndex();
233 const QFileInfo firstChild(children.first());
234 return toNodeIndex(firstChild);
235 }
236 }
237
238 case PreviousSibling:
239 return nextSibling(nodeIndex, fi, -1);
240
241 case NextSibling:
242 return nextSibling(nodeIndex, fi, 1);
243 }
244
245 Q_ASSERT_X(false, Q_FUNC_INFO, "Don't ever get here!");
246 return QXmlNodeModelIndex();
247}
248//! [4]
249
250/*!
251 No matter what part of the file system we model (the whole file
252 tree or a subtree), \a node will always have \c{file:///} as
253 the document URI.
254 */
255QUrl FileTree::documentUri(const QXmlNodeModelIndex &node) const
256{
257 Q_UNUSED(node);
258 return QUrl("file:///");
259}
260
261/*!
262 This function returns QXmlNodeModelIndex::Element if \a node
263 is a directory or a file, and QXmlNodeModelIndex::Attribute
264 otherwise.
265 */
266QXmlNodeModelIndex::NodeKind
267FileTree::kind(const QXmlNodeModelIndex &node) const
268{
269 switch (Type(node.additionalData())) {
270 case Directory:
271 case File:
272 return QXmlNodeModelIndex::Element;
273 default:
274 return QXmlNodeModelIndex::Attribute;
275 }
276}
277
278/*!
279 No order is defined for this example, so we always return
280 QXmlNodeModelIndex::Precedes, just to keep everyone happy.
281 */
282QXmlNodeModelIndex::DocumentOrder
283FileTree::compareOrder(const QXmlNodeModelIndex&,
284 const QXmlNodeModelIndex&) const
285{
286 return QXmlNodeModelIndex::Precedes;
287}
288
289/*!
290 Returns the name of \a node. The caller guarantees that \a node is
291 not null and that it is contained in this node model.
292 */
293//! [3]
294QXmlName FileTree::name(const QXmlNodeModelIndex &node) const
295{
296 return m_names.at(node.additionalData());
297}
298//! [3]
299
300/*!
301 Always returns the QXmlNodeModelIndex for the root of the
302 file system, i.e. "/".
303 */
304QXmlNodeModelIndex FileTree::root(const QXmlNodeModelIndex &node) const
305{
306 Q_UNUSED(node);
307 return toNodeIndex(QFileInfo(QLatin1String("/")));
308}
309
310/*!
311 Returns the typed value for \a node, which must be either an
312 attribute or an element. The QVariant returned represents the atomic
313 value of an attribute or the atomic value contained in an element.
314
315 If the QVariant is returned as a default constructed variant,
316 it means that \a node has no typed value.
317 */
318QVariant FileTree::typedValue(const QXmlNodeModelIndex &node) const
319{
320 const QFileInfo &fi = toFileInfo(node);
321
322 switch (Type(node.additionalData())) {
323 case Directory:
324 // deliberate fall through.
325 case File:
326 return QString();
327 case AttributeFileName:
328 return fi.fileName();
329 case AttributeFilePath:
330 return fi.filePath();
331 case AttributeSize:
332 return fi.size();
333 case AttributeMIMEType:
334 {
335 /* We don't have any MIME detection code currently, so return
336 * the most generic one. */
337 return QLatin1String("application/octet-stream");
338 }
339 case AttributeSuffix:
340 return fi.suffix();
341 }
342
343 Q_ASSERT_X(false, Q_FUNC_INFO, "This line should never be reached.");
344 return QString();
345}
346
347/*!
348 Returns the attributes of \a element. The caller guarantees
349 that \a element is an element in this node model.
350 */
351QVector<QXmlNodeModelIndex>
352FileTree::attributes(const QXmlNodeModelIndex &element) const
353{
354 QVector<QXmlNodeModelIndex> result;
355
356 /* Both elements has this attribute. */
357 const QFileInfo &forElement = toFileInfo(element);
358 result.append(toNodeIndex(forElement, AttributeFilePath));
359 result.append(toNodeIndex(forElement, AttributeFileName));
360
361 if (Type(element.additionalData() == File)) {
362 result.append(toNodeIndex(forElement, AttributeSize));
363 result.append(toNodeIndex(forElement, AttributeSuffix));
364 //result.append(toNodeIndex(forElement, AttributeMIMEType));
365 }
366 else {
367 Q_ASSERT(element.additionalData() == Directory);
368 }
369
370 return result;
371}
372
Note: See TracBrowser for help on using the repository browser.