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>
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())
44 // recursively compare children
45 const QDomNodeList node1Children
= node1
.childNodes();
46 const QDomNodeList node2Children
= node2
.childNodes();
48 if (node1Children
.count () != node2Children
.count ())
51 for (int i
=0; i
<node1Children
.count ();i
++) {
52 if (!deepCompareDomNodes(node1Children
.at(i
), node2Children
.at(i
) ))
58 static QString
nodeAsString(const QDomNode
& node1
)
61 QTextStream
ts( &str
, QIODevice::WriteOnly
);
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
)
100 KBookmark bookmark
= root
.first();
101 while (!bookmark
.isNull()) {
103 bookmark
= root
.next(bookmark
);
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();
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
);
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
);
167 //kDebug() << "keeping" << bookmark.text();
169 sharedBookmark
= sharedRoot
.next(sharedBookmark
);
170 bookmark
= root
.next(bookmark
);
174 // they don't match -> remove
175 //kDebug() << "removing" << bookmark.text();
176 KBookmark bookmarkToRemove
= bookmark
;
177 bookmark
= root
.next(bookmark
);
178 root
.deleteBookmark(bookmarkToRemove
);
183 // append the remaining shared bookmarks
184 while(!sharedBookmark
.isNull()) {
185 root
.addBookmark(cloneBookmark(sharedBookmark
));
186 sharedBookmark
= sharedRoot
.next(sharedBookmark
);
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();
203 // first check if they are the same
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
);
215 // end of sharedBookmarks?
216 if (sharedBookmark
.isNull()) {
221 // do the bookmarks match?
222 if (compareBookmarks(bookmark
, sharedBookmark
)) {
223 if (!exactCompareBookmarks(bookmark
, sharedBookmark
)) {
231 sharedBookmark
= sharedRoot
.next(sharedBookmark
);
232 bookmark
= root
.next(bookmark
);
235 //kDebug() << "dirty=" << dirty << " oldsize=" << bookmarkGroupSize(sharedRoot) << " count=" << count;
237 if (bookmarkGroupSize(sharedRoot
) != count
)
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
);
253 sharedRoot
.addBookmark(cloneBookmark(bookmark
));
254 bookmark
= root
.next(bookmark
);
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"