fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kfile / kfileplacessharedbookmarks.cpp
blobac6e3b1352b165703f56660e71307052e5b9f51f
1 /* This file is part of the KDE project
2 Copyright (C) 2008 Norbert Frese <nf2@scheinwelt.at>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
20 #include "kfileplacessharedbookmarks_p.h"
22 #include <QtCore/QObject>
23 #include <QtCore/QTextStream>
24 #include <QtCore/QFile>
25 #include <kstandarddirs.h>
26 #include <kbookmarkmanager.h>
27 #include <kbookmark.h>
28 #include <kdebug.h>
30 //////////////// utility functions
32 static bool compareBookmarks(const KBookmark & bookmark1, const KBookmark & bookmark2)
34 return (bookmark1.url() == bookmark2.url() || bookmark1.text() == bookmark2.text());
37 static bool deepCompareDomNodes(const QDomNode & node1, const QDomNode & node2)
40 // compare name and value
41 if (node1.nodeName() != node2.nodeName() || node1.nodeValue() != node2.nodeValue())
42 return false;
44 // recursively compare children
45 const QDomNodeList node1Children = node1.childNodes();
46 const QDomNodeList node2Children = node2.childNodes();
48 if (node1Children.count () != node2Children.count ())
49 return false;
51 for (int i=0; i<node1Children.count ();i++) {
52 if (!deepCompareDomNodes(node1Children.at(i), node2Children.at(i) ))
53 return false;
55 return true;
58 static QString nodeAsString(const QDomNode & node1)
60 QString str;
61 QTextStream ts( &str, QIODevice::WriteOnly );
62 ts << node1;
63 return str;
66 static bool exactCompareBookmarks(const KBookmark & bookmark1, const KBookmark & bookmark2)
68 //kDebug() << "excat comparing:\n" << nodeAsString(bookmark1.internalElement()) << "\nwith:\n" << nodeAsString(bookmark2.internalElement());
69 return deepCompareDomNodes(bookmark1.internalElement(), bookmark2.internalElement());
72 static void cloneBookmarkContents(const KBookmark & target, const KBookmark & source)
74 const QDomElement targetEl = target.internalElement();
75 QDomNode parent = targetEl.parentNode ();
76 QDomNode clonedNode = source.internalElement().cloneNode(true);
77 parent.replaceChild (clonedNode , targetEl );
80 static KBookmark cloneBookmark(const KBookmark & toClone)
82 const QDomNode cloned = toClone.internalElement().cloneNode(true);
83 return KBookmark(cloned.toElement ());
87 static void emptyBookmarkGroup(KBookmarkGroup & root)
89 KBookmark bookmark = root.first();
90 while (!bookmark.isNull()) {
91 KBookmark bookmarkToRemove = bookmark;
92 bookmark = root.next(bookmark);
93 root.deleteBookmark(bookmarkToRemove);
97 static int bookmarkGroupSize(KBookmarkGroup & root)
99 int count=0;
100 KBookmark bookmark = root.first();
101 while (!bookmark.isNull()) {
102 count++;
103 bookmark = root.next(bookmark);
105 return count;
108 //////////////// class KFilePlacesSharedBookmarks
110 KFilePlacesSharedBookmarks::KFilePlacesSharedBookmarks(KBookmarkManager * mgr)
112 m_placesBookmarkManager = mgr;
114 const QString file = KStandardDirs().localxdgdatadir() + "/user-places.xbel";
115 m_sharedBookmarkManager = KBookmarkManager::managerForExternalFile(file);
117 connect(m_sharedBookmarkManager, SIGNAL(changed(const QString&, const QString&)),
118 this, SLOT(slotSharedBookmarksChanged()));
119 connect(m_sharedBookmarkManager, SIGNAL(bookmarksChanged(const QString&)),
120 this, SLOT(slotSharedBookmarksChanged()));
122 connect(m_placesBookmarkManager, SIGNAL(changed(const QString&, const QString&)),
123 this, SLOT(slotBookmarksChanged()));
124 connect(m_placesBookmarkManager, SIGNAL(bookmarksChanged(const QString&)),
125 this, SLOT(slotBookmarksChanged()));
127 integrateSharedBookmarks();
130 bool KFilePlacesSharedBookmarks::integrateSharedBookmarks()
132 KBookmarkGroup root = m_placesBookmarkManager->root();
133 KBookmark bookmark = root.first();
135 KBookmarkGroup sharedRoot = m_sharedBookmarkManager->root();
136 KBookmark sharedBookmark = sharedRoot.first();
138 bool dirty = false;
140 while (!bookmark.isNull()) {
141 //kDebug() << "importing" << bookmark.text();
143 // skip over system items
144 if (bookmark.metaDataItem("isSystemItem") == "true") {
145 bookmark = root.next(bookmark);
146 continue;
149 // do the bookmarks match?
150 if (!sharedBookmark.isNull() && compareBookmarks(bookmark, sharedBookmark)) {
151 //kDebug() << "excat comparing: targetbk:\n" << nodeAsString(bookmark.internalElement()) << "\nsourcbk:\n" << nodeAsString(sharedBookmark.internalElement());
153 if (!exactCompareBookmarks(bookmark, sharedBookmark)) {
154 KBookmark cloneTarget=bookmark;
155 KBookmark cloneSource = sharedBookmark;
157 sharedBookmark = sharedRoot.next(sharedBookmark);
158 bookmark = root.next(bookmark);
160 //kDebug() << "cloning" << cloneSource.text();
161 //kDebug() << "cloning: target=\n" << nodeAsString(cloneTarget.internalElement()) << "\n source:\n" << nodeAsString(cloneSource.internalElement());
163 cloneBookmarkContents(cloneTarget, cloneSource);
164 dirty = true;
165 continue;
166 } else {
167 //kDebug() << "keeping" << bookmark.text();
169 sharedBookmark = sharedRoot.next(sharedBookmark);
170 bookmark = root.next(bookmark);
171 continue;
174 // they don't match -> remove
175 //kDebug() << "removing" << bookmark.text();
176 KBookmark bookmarkToRemove = bookmark;
177 bookmark = root.next(bookmark);
178 root.deleteBookmark(bookmarkToRemove);
180 dirty = true;
183 // append the remaining shared bookmarks
184 while(!sharedBookmark.isNull()) {
185 root.addBookmark(cloneBookmark(sharedBookmark));
186 sharedBookmark = sharedRoot.next(sharedBookmark);
187 dirty = true;
190 return dirty;
193 bool KFilePlacesSharedBookmarks::exportSharedBookmarks()
195 KBookmarkGroup root = m_placesBookmarkManager->root();
196 KBookmark bookmark = root.first();
198 KBookmarkGroup sharedRoot = m_sharedBookmarkManager->root();
199 KBookmark sharedBookmark = sharedRoot.first();
201 bool dirty = false;
203 // first check if they are the same
204 int count=0;
205 while (!bookmark.isNull()) {
206 //kDebug() << "exporting..." << bookmark.text();
208 // skip over system items
209 if (bookmark.metaDataItem("isSystemItem") == "true") {
210 bookmark = root.next(bookmark);
211 continue;
213 count++;
215 // end of sharedBookmarks?
216 if (sharedBookmark.isNull()) {
217 dirty=true;
218 break;
221 // do the bookmarks match?
222 if (compareBookmarks(bookmark, sharedBookmark)) {
223 if (!exactCompareBookmarks(bookmark, sharedBookmark)) {
224 dirty = true;
225 break;
227 } else {
228 dirty=true;
229 break;
231 sharedBookmark = sharedRoot.next(sharedBookmark);
232 bookmark = root.next(bookmark);
235 //kDebug() << "dirty=" << dirty << " oldsize=" << bookmarkGroupSize(sharedRoot) << " count=" << count;
237 if (bookmarkGroupSize(sharedRoot) != count)
238 dirty=true;
240 if (dirty) {
241 emptyBookmarkGroup(sharedRoot);
243 // append all bookmarks
244 KBookmark bookmark = root.first();
246 while(!bookmark.isNull()) {
248 if (bookmark.metaDataItem("isSystemItem") == "true") {
249 bookmark = root.next(bookmark);
250 continue;
253 sharedRoot.addBookmark(cloneBookmark(bookmark));
254 bookmark = root.next(bookmark);
255 dirty = true;
259 return dirty;
263 void KFilePlacesSharedBookmarks::slotSharedBookmarksChanged()
265 kDebug() << "shared bookmarks changed";
266 bool dirty = integrateSharedBookmarks();
267 if (dirty) m_placesBookmarkManager->emitChanged();
270 void KFilePlacesSharedBookmarks::slotBookmarksChanged()
272 kDebug() << "places bookmarks changed";
273 bool dirty = exportSharedBookmarks();
274 if (dirty) m_sharedBookmarkManager->emitChanged();
277 #include "kfileplacessharedbookmarks_p.moc"