1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "xbel.h"
35
36 #include <QtCore/QFile>
37
BookmarkNode(BookmarkNode::Type type,BookmarkNode * parent)38 BookmarkNode::BookmarkNode(BookmarkNode::Type type, BookmarkNode *parent) :
39 expanded(false)
40 , m_parent(parent)
41 , m_type(type)
42 {
43 if (parent)
44 parent->add(this);
45 }
46
~BookmarkNode()47 BookmarkNode::~BookmarkNode()
48 {
49 if (m_parent)
50 m_parent->remove(this);
51 qDeleteAll(m_children);
52 m_parent = 0;
53 m_type = BookmarkNode::Root;
54 }
55
operator ==(const BookmarkNode & other)56 bool BookmarkNode::operator==(const BookmarkNode &other)
57 {
58 if (url != other.url
59 || title != other.title
60 || desc != other.desc
61 || expanded != other.expanded
62 || m_type != other.m_type
63 || m_children.count() != other.m_children.count())
64 return false;
65
66 for (int i = 0; i < m_children.count(); ++i)
67 if (!((*(m_children[i])) == (*(other.m_children[i]))))
68 return false;
69 return true;
70 }
71
type() const72 BookmarkNode::Type BookmarkNode::type() const
73 {
74 return m_type;
75 }
76
setType(Type type)77 void BookmarkNode::setType(Type type)
78 {
79 m_type = type;
80 }
81
children() const82 QList<BookmarkNode *> BookmarkNode::children() const
83 {
84 return m_children;
85 }
86
parent() const87 BookmarkNode *BookmarkNode::parent() const
88 {
89 return m_parent;
90 }
91
add(BookmarkNode * child,int offset)92 void BookmarkNode::add(BookmarkNode *child, int offset)
93 {
94 Q_ASSERT(child->m_type != Root);
95 if (child->m_parent)
96 child->m_parent->remove(child);
97 child->m_parent = this;
98 if (-1 == offset)
99 offset = m_children.size();
100 m_children.insert(offset, child);
101 }
102
remove(BookmarkNode * child)103 void BookmarkNode::remove(BookmarkNode *child)
104 {
105 child->m_parent = 0;
106 m_children.removeAll(child);
107 }
108
109
XbelReader()110 XbelReader::XbelReader()
111 {
112 }
113
read(const QString & fileName)114 BookmarkNode *XbelReader::read(const QString &fileName)
115 {
116 QFile file(fileName);
117 if (!file.exists()) {
118 return new BookmarkNode(BookmarkNode::Root);
119 }
120 file.open(QFile::ReadOnly);
121 return read(&file);
122 }
123
read(QIODevice * device)124 BookmarkNode *XbelReader::read(QIODevice *device)
125 {
126 BookmarkNode *root = new BookmarkNode(BookmarkNode::Root);
127 setDevice(device);
128 if (readNextStartElement()) {
129 QString version = attributes().value(QLatin1String("version")).toString();
130 if (name() == QLatin1String("xbel")
131 && (version.isEmpty() || version == QLatin1String("1.0"))) {
132 readXBEL(root);
133 } else {
134 raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
135 }
136 }
137 return root;
138 }
139
readXBEL(BookmarkNode * parent)140 void XbelReader::readXBEL(BookmarkNode *parent)
141 {
142 Q_ASSERT(isStartElement() && name() == QLatin1String("xbel"));
143
144 while (readNextStartElement()) {
145 if (name() == QLatin1String("folder"))
146 readFolder(parent);
147 else if (name() == QLatin1String("bookmark"))
148 readBookmarkNode(parent);
149 else if (name() == QLatin1String("separator"))
150 readSeparator(parent);
151 else
152 skipCurrentElement();
153 }
154 }
155
readFolder(BookmarkNode * parent)156 void XbelReader::readFolder(BookmarkNode *parent)
157 {
158 Q_ASSERT(isStartElement() && name() == QLatin1String("folder"));
159
160 BookmarkNode *folder = new BookmarkNode(BookmarkNode::Folder, parent);
161 folder->expanded = (attributes().value(QLatin1String("folded")) == QLatin1String("no"));
162
163 while (readNextStartElement()) {
164 if (name() == QLatin1String("title"))
165 readTitle(folder);
166 else if (name() == QLatin1String("desc"))
167 readDescription(folder);
168 else if (name() == QLatin1String("folder"))
169 readFolder(folder);
170 else if (name() == QLatin1String("bookmark"))
171 readBookmarkNode(folder);
172 else if (name() == QLatin1String("separator"))
173 readSeparator(folder);
174 else
175 skipCurrentElement();
176 }
177 }
178
readTitle(BookmarkNode * parent)179 void XbelReader::readTitle(BookmarkNode *parent)
180 {
181 Q_ASSERT(isStartElement() && name() == QLatin1String("title"));
182 parent->title = readElementText();
183 }
184
readDescription(BookmarkNode * parent)185 void XbelReader::readDescription(BookmarkNode *parent)
186 {
187 Q_ASSERT(isStartElement() && name() == QLatin1String("desc"));
188 parent->desc = readElementText();
189 }
190
readSeparator(BookmarkNode * parent)191 void XbelReader::readSeparator(BookmarkNode *parent)
192 {
193 new BookmarkNode(BookmarkNode::Separator, parent);
194 // empty elements have a start and end element
195 readNext();
196 }
197
readBookmarkNode(BookmarkNode * parent)198 void XbelReader::readBookmarkNode(BookmarkNode *parent)
199 {
200 Q_ASSERT(isStartElement() && name() == QLatin1String("bookmark"));
201 BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark, parent);
202 bookmark->url = attributes().value(QLatin1String("href")).toString();
203 while (readNextStartElement()) {
204 if (name() == QLatin1String("title"))
205 readTitle(bookmark);
206 else if (name() == QLatin1String("desc"))
207 readDescription(bookmark);
208 else
209 skipCurrentElement();
210 }
211 if (bookmark->title.isEmpty())
212 bookmark->title = QObject::tr("Unknown title");
213 }
214
215
XbelWriter()216 XbelWriter::XbelWriter()
217 {
218 setAutoFormatting(true);
219 }
220
write(const QString & fileName,const BookmarkNode * root)221 bool XbelWriter::write(const QString &fileName, const BookmarkNode *root)
222 {
223 QFile file(fileName);
224 if (!root || !file.open(QFile::WriteOnly))
225 return false;
226 return write(&file, root);
227 }
228
write(QIODevice * device,const BookmarkNode * root)229 bool XbelWriter::write(QIODevice *device, const BookmarkNode *root)
230 {
231 setDevice(device);
232
233 writeStartDocument();
234 writeDTD(QLatin1String("<!DOCTYPE xbel>"));
235 writeStartElement(QLatin1String("xbel"));
236 writeAttribute(QLatin1String("version"), QLatin1String("1.0"));
237 if (root->type() == BookmarkNode::Root) {
238 for (int i = 0; i < root->children().count(); ++i)
239 writeItem(root->children().at(i));
240 } else {
241 writeItem(root);
242 }
243
244 writeEndDocument();
245 return true;
246 }
247
writeItem(const BookmarkNode * parent)248 void XbelWriter::writeItem(const BookmarkNode *parent)
249 {
250 switch (parent->type()) {
251 case BookmarkNode::Folder:
252 writeStartElement(QLatin1String("folder"));
253 writeAttribute(QLatin1String("folded"), parent->expanded ? QLatin1String("no") : QLatin1String("yes"));
254 writeTextElement(QLatin1String("title"), parent->title);
255 for (int i = 0; i < parent->children().count(); ++i)
256 writeItem(parent->children().at(i));
257 writeEndElement();
258 break;
259 case BookmarkNode::Bookmark:
260 writeStartElement(QLatin1String("bookmark"));
261 if (!parent->url.isEmpty())
262 writeAttribute(QLatin1String("href"), parent->url);
263 writeTextElement(QLatin1String("title"), parent->title);
264 if (!parent->desc.isEmpty())
265 writeAttribute(QLatin1String("desc"), parent->desc);
266 writeEndElement();
267 break;
268 case BookmarkNode::Separator:
269 writeEmptyElement(QLatin1String("separator"));
270 break;
271 default:
272 break;
273 }
274 }
275
276