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

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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