• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/bookmarks
 

kio/bookmarks

  • kio
  • bookmarks
kbookmark.cc
1 // -*- c-basic-offset:4; indent-tabs-mode:nil -*-
2 // vim: set ts=4 sts=4 sw=4 et:
3 /* This file is part of the KDE libraries
4  Copyright (C) 2000 David Faure <faure@kde.org>
5  Copyright (C) 2003 Alexander Kellett <lypanov@kde.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "kbookmark.h"
23 #include <tqvaluestack.h>
24 #include <kdebug.h>
25 #include <kmimetype.h>
26 #include <kstringhandler.h>
27 #include <kinputdialog.h>
28 #include <kglobal.h>
29 #include <klocale.h>
30 #include <assert.h>
31 #include <kapplication.h>
32 #include <dcopclient.h>
33 #include <kbookmarkmanager.h>
34 
35 KBookmarkGroup::KBookmarkGroup()
36  : KBookmark( TQDomElement() )
37 {
38 }
39 
40 KBookmarkGroup::KBookmarkGroup( TQDomElement elem )
41  : KBookmark(elem)
42 {
43 }
44 
45 TQString KBookmarkGroup::groupAddress() const
46 {
47  if (m_address.isEmpty())
48  m_address = address();
49  return m_address;
50 }
51 
52 bool KBookmarkGroup::isOpen() const
53 {
54  return element.attribute("folded") == "no"; // default is: folded
55 }
56 
57 // Returns first element node equal to or after node n
58 static TQDomElement firstElement(TQDomNode n)
59 {
60  while(!n.isNull() && !n.isElement())
61  n = n.nextSibling();
62  return n.toElement();
63 }
64 
65 // Returns first element node equal to or before node n
66 static TQDomElement lastElement(TQDomNode n)
67 {
68  while(!n.isNull() && !n.isElement())
69  n = n.previousSibling();
70  return n.toElement();
71 }
72 
73 KBookmark KBookmarkGroup::first() const
74 {
75  return KBookmark( nextKnownTag( firstElement(element.firstChild()), true ) );
76 }
77 
78 KBookmark KBookmarkGroup::previous( const KBookmark & current ) const
79 {
80  return KBookmark( nextKnownTag( lastElement(current.element.previousSibling()), false ) );
81 }
82 
83 KBookmark KBookmarkGroup::next( const KBookmark & current ) const
84 {
85  return KBookmark( nextKnownTag( firstElement(current.element.nextSibling()), true ) );
86 }
87 
88 // KDE4: Change TQDomElement to TQDomNode so that we can get rid of
89 // firstElement() and lastElement()
90 TQDomElement KBookmarkGroup::nextKnownTag( TQDomElement start, bool goNext ) const
91 {
92  static const TQString & bookmark = KGlobal::staticQString("bookmark");
93  static const TQString & folder = KGlobal::staticQString("folder");
94  static const TQString & separator = KGlobal::staticQString("separator");
95 
96  for( TQDomNode n = start; !n.isNull(); )
97  {
98  TQDomElement elem = n.toElement();
99  TQString tag = elem.tagName();
100  if (tag == folder || tag == bookmark || tag == separator)
101  return elem;
102  if (goNext)
103  n = n.nextSibling();
104  else
105  n = n.previousSibling();
106  }
107  return TQDomElement();
108 }
109 
110 KBookmarkGroup KBookmarkGroup::createNewFolder( KBookmarkManager* mgr, const TQString & text, bool emitSignal )
111 {
112  TQString txt( text );
113  if ( text.isEmpty() )
114  {
115  bool ok;
116  TQString caption = parentGroup().fullText().isEmpty() ?
117  i18n( "Create New Bookmark Folder" ) :
118  i18n( "Create New Bookmark Folder in %1" )
119  .arg( parentGroup().text() );
120  txt = KInputDialog::getText( caption, i18n( "New folder:" ),
121  TQString::null, &ok );
122  if ( !ok )
123  return KBookmarkGroup();
124  }
125 
126  Q_ASSERT(!element.isNull());
127  TQDomDocument doc = element.ownerDocument();
128  TQDomElement groupElem = doc.createElement( "folder" );
129  element.appendChild( groupElem );
130  TQDomElement textElem = doc.createElement( "title" );
131  groupElem.appendChild( textElem );
132  textElem.appendChild( doc.createTextNode( txt ) );
133 
134  KBookmarkGroup grp(groupElem);
135 
136  if (emitSignal)
137  emit mgr->notifier().createdNewFolder(
138  mgr->path(), grp.fullText(),
139  grp.address() );
140 
141  return grp;
142 
143 }
144 
145 KBookmark KBookmarkGroup::createNewSeparator()
146 {
147  Q_ASSERT(!element.isNull());
148  TQDomDocument doc = element.ownerDocument();
149  Q_ASSERT(!doc.isNull());
150  TQDomElement sepElem = doc.createElement( "separator" );
151  element.appendChild( sepElem );
152  return KBookmark(sepElem);
153 }
154 
155 bool KBookmarkGroup::moveItem( const KBookmark & item, const KBookmark & after )
156 {
157  TQDomNode n;
158  if ( !after.isNull() )
159  n = element.insertAfter( item.element, after.element );
160  else // first child
161  {
162  if ( element.firstChild().isNull() ) // Empty element -> set as real first child
163  n = element.insertBefore( item.element, TQDomElement() );
164 
165  // we have to skip everything up to the first valid child
166  TQDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true);
167  if ( !firstChild.isNull() )
168  n = element.insertBefore( item.element, firstChild );
169  else
170  {
171  // No real first child -> append after the <title> etc.
172  n = element.appendChild( item.element );
173  }
174  }
175  return (!n.isNull());
176 }
177 
178 KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal )
179 {
180  element.appendChild( bm.internalElement() );
181 
182  if (emitSignal) {
183  if ( bm.hasMetaData() ) {
184  mgr->notifyCompleteChange( "" );
185  } else {
186  emit mgr->notifier().addedBookmark(
187  mgr->path(), bm.url().url(),
188  bm.fullText(), bm.address(), bm.icon() );
189  }
190  }
191 
192  return bm;
193 }
194 
195 KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const TQString & text, const KURL & url, const TQString & icon, bool emitSignal )
196 {
197  //kdDebug(7043) << "KBookmarkGroup::addBookmark " << text << " into " << m_address << endl;
198  TQDomDocument doc = element.ownerDocument();
199  TQDomElement elem = doc.createElement( "bookmark" );
200  elem.setAttribute( "href", url.url( 0, 106 ) ); // write utf8 URL (106 is mib enum for utf8)
201  TQString _icon = icon;
202  if ( _icon.isEmpty() )
203  _icon = KMimeType::iconForURL( url );
204  elem.setAttribute( "icon", _icon );
205 
206  TQDomElement textElem = doc.createElement( "title" );
207  elem.appendChild( textElem );
208  textElem.appendChild( doc.createTextNode( text ) );
209 
210  return addBookmark( mgr, KBookmark( elem ), emitSignal );
211 }
212 
213 void KBookmarkGroup::deleteBookmark( KBookmark bk )
214 {
215  element.removeChild( bk.element );
216 }
217 
218 bool KBookmarkGroup::isToolbarGroup() const
219 {
220  return ( element.attribute("toolbar") == "yes" );
221 }
222 
223 TQDomElement KBookmarkGroup::findToolbar() const
224 {
225  if ( element.attribute("toolbar") == "yes" )
226  return element;
227  for (TQDomNode n = element.firstChild(); !n.isNull() ; n = n.nextSibling() )
228  {
229  TQDomElement e = n.toElement();
230  // Search among the "folder" children only
231  if ( e.tagName() == "folder" )
232  {
233  if ( e.attribute("toolbar") == "yes" )
234  return e;
235  else
236  {
237  TQDomElement result = KBookmarkGroup(e).findToolbar();
238  if (!result.isNull())
239  return result;
240  }
241  }
242  }
243  return TQDomElement();
244 }
245 
246 TQValueList<KURL> KBookmarkGroup::groupUrlList() const
247 {
248  TQValueList<KURL> urlList;
249  for ( KBookmark bm = first(); !bm.isNull(); bm = next(bm) )
250  {
251  if ( bm.isSeparator() || bm.isGroup() )
252  continue;
253  urlList << bm.url();
254  }
255  return urlList;
256 }
257 
259 
260 bool KBookmark::isGroup() const
261 {
262  TQString tag = element.tagName();
263  return ( tag == "folder"
264  || tag == "xbel" ); // don't forget the toplevel group
265 }
266 
267 bool KBookmark::isSeparator() const
268 {
269  return (element.tagName() == "separator");
270 }
271 
272 bool KBookmark::hasParent() const
273 {
274  TQDomElement parent = element.parentNode().toElement();
275  return !parent.isNull();
276 }
277 
278 TQString KBookmark::text() const
279 {
280  return KStringHandler::csqueeze( fullText() );
281 }
282 
283 TQString KBookmark::fullText() const
284 {
285  if (isSeparator())
286  return i18n("--- separator ---");
287 
288  return element.namedItem("title").toElement().text();
289 }
290 
291 KURL KBookmark::url() const
292 {
293  return KURL(element.attribute("href"), 106); // Decode it from utf8 (106 is mib enum for utf8)
294 }
295 
296 TQString KBookmark::icon() const
297 {
298  TQString icon = element.attribute("icon");
299  if ( icon.isEmpty() ) {
300  // Default icon depends on URL for bookmarks, and is default directory
301  // icon for groups.
302  if ( isGroup() ) {
303  icon = "bookmark_folder";
304  }
305  else {
306  if ( isSeparator() ) {
307  icon = "eraser"; // whatever
308  }
309  else {
310  icon = KMimeType::iconForURL( url() );
311  }
312  }
313  }
314  return icon;
315 }
316 
317 KBookmarkGroup KBookmark::parentGroup() const
318 {
319  return KBookmarkGroup( element.parentNode().toElement() );
320 }
321 
322 KBookmarkGroup KBookmark::toGroup() const
323 {
324  Q_ASSERT( isGroup() );
325  return KBookmarkGroup(element);
326 }
327 
328 TQString KBookmark::address() const
329 {
330  if ( element.tagName() == "xbel" )
331  return ""; // not TQString::null !
332  else
333  {
334  // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :)
335  if (!hasParent())
336  {
337  Q_ASSERT(hasParent());
338  return "ERROR"; // Avoid an infinite loop
339  }
340  KBookmarkGroup group = parentGroup();
341  TQString parentAddress = group.address();
342  uint counter = 0;
343  // Implementation note: we don't use QDomNode's childNode list because we
344  // would have to skip "TEXT", which KBookmarkGroup already does for us.
345  for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk), ++counter )
346  {
347  if ( bk.element == element )
348  return parentAddress + "/" + TQString::number(counter);
349  }
350  kdWarning() << "KBookmark::address : this can't happen! " << parentAddress << endl;
351  return "ERROR";
352  }
353 }
354 
355 KBookmark KBookmark::standaloneBookmark( const TQString & text, const KURL & url, const TQString & icon )
356 {
357  TQDomDocument doc("xbel");
358  TQDomElement elem = doc.createElement("xbel");
359  doc.appendChild( elem );
360  KBookmarkGroup grp( elem );
361  grp.addBookmark( 0L, text, url, icon, false );
362  return grp.first();
363 }
364 
365 // For some strange reason TQString("").left(0) returns TQString::null;
366 // That breaks commonParent()
367 TQString KBookmark::left(const TQString & str, uint len)
368 {
369  //kdDebug()<<"********"<<TQString("").left(0).isNull()<<endl;
370  if(len == 0)
371  return TQString("");
372  else
373  return str.left(len);
374 }
375 
376 TQString KBookmark::commonParent(TQString A, TQString B)
377 {
378  TQString error("ERROR");
379  if(A == error || B == error)
380  return error;
381 
382  A += "/";
383  B += "/";
384 
385  uint lastCommonSlash = 0;
386  uint lastPos = A.length() < B.length() ? A.length() : B.length();
387  for(uint i=0; i < lastPos; ++i)
388  {
389  if(A[i] != B[i])
390  return left(A, lastCommonSlash);
391  if(A[i] == '/')
392  lastCommonSlash = i;
393  }
394  return left(A, lastCommonSlash);
395 }
396 
397 static TQDomNode cd_or_create(TQDomNode node, TQString name)
398 {
399  TQDomNode subnode = node.namedItem(name);
400  if (subnode.isNull())
401  {
402  subnode = node.ownerDocument().createElement(name);
403  node.appendChild(subnode);
404  }
405  return subnode;
406 }
407 
408 static TQDomText get_or_create_text(TQDomNode node)
409 {
410  TQDomNode subnode = node.firstChild();
411  if (subnode.isNull())
412  {
413  subnode = node.ownerDocument().createTextNode("");
414  node.appendChild(subnode);
415  }
416  return subnode.toText();
417 }
418 
419 // Look for a metadata with owner="http://www.kde.org" or without any owner (for compatibility)
420 static TQDomNode findOrCreateMetadata( TQDomNode& parent )
421 {
422  static const char kdeOwner[] = "http://www.kde.org";
423  TQDomElement metadataElement;
424  for ( TQDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) {
425  TQDomElement elem = _node.toElement();
426  if ( !elem.isNull() && elem.tagName() == "metadata" ) {
427  const TQString owner = elem.attribute( "owner" );
428  if ( owner == kdeOwner )
429  return elem;
430  if ( owner.isEmpty() )
431  metadataElement = elem;
432  }
433  }
434  if ( metadataElement.isNull() ) {
435  metadataElement = parent.ownerDocument().createElement( "metadata" );
436  parent.appendChild(metadataElement);
437  }
438  metadataElement.setAttribute( "owner", kdeOwner );
439  return metadataElement;
440 }
441 
442 bool KBookmark::hasMetaData() const
443 {
444  // ### NOTE: this code creates <info> and <metadata>, despite its name and the const.
445  // It doesn't matter much in practice since it's only called for newly-created bookmarks,
446  // which will get metadata soon after anyway.
447  TQDomNode n = cd_or_create( internalElement(), "info" );
448  return findOrCreateMetadata( n ).hasChildNodes();
449 }
450 
451 void KBookmark::updateAccessMetadata()
452 {
453  kdDebug(7043) << "KBookmark::updateAccessMetadata " << address() << " " << url().prettyURL() << endl;
454 
455  const uint timet = TQDateTime::currentDateTime().toTime_t();
456  setMetaDataItem( "time_added", TQString::number( timet ), DontOverwriteMetaData );
457  setMetaDataItem( "time_visited", TQString::number( timet ) );
458 
459  TQString countStr = metaDataItem( "visit_count" ); // TODO use spec'ed name
460  bool ok;
461  int currentCount = countStr.toInt(&ok);
462  if (!ok)
463  currentCount = 0;
464  currentCount++;
465  setMetaDataItem( "visit_count", TQString::number( currentCount ) );
466 
467  // TODO - for 4.0 - time_modified
468 }
469 
470 TQString KBookmark::metaDataItem( const TQString &key ) const
471 {
472  TQDomNode infoNode = cd_or_create( internalElement(), "info" );
473  infoNode = findOrCreateMetadata( infoNode );
474  for ( TQDomNode n = infoNode.firstChild(); !n.isNull(); n = n.nextSibling() ) {
475  if ( !n.isElement() ) {
476  continue;
477  }
478  const TQDomElement e = n.toElement();
479  if ( e.tagName() == key ) {
480  return e.text();
481  }
482  }
483  return TQString::null;
484 }
485 
486 void KBookmark::setMetaDataItem( const TQString &key, const TQString &value, MetaDataOverwriteMode mode )
487 {
488  TQDomNode infoNode = cd_or_create( internalElement(), "info" );
489  infoNode = findOrCreateMetadata( infoNode );
490 
491  TQDomNode item = cd_or_create( infoNode, key );
492  TQDomText text = get_or_create_text( item );
493  if ( mode == DontOverwriteMetaData && !text.data().isEmpty() ) {
494  return;
495  }
496 
497  text.setData( value );
498 }
499 
500 void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root)
501 {
502  // non-recursive bookmark iterator
503  TQValueStack<KBookmarkGroup> stack;
504  stack.push(root);
505  KBookmark bk = stack.top().first();
506  for (;;) {
507  if (bk.isNull())
508  {
509  if (stack.isEmpty())
510  return;
511  if (stack.count() > 1)
512  visitLeave(stack.top());
513  bk = stack.pop();
514  bk = stack.top().next(bk);
515  if (bk.isNull())
516  continue;
517  }
518 
519  if (bk.isGroup())
520  {
521  KBookmarkGroup gp = bk.toGroup();
522  visitEnter(gp);
523  if (!gp.first().isNull())
524  {
525  stack.push(gp);
526  bk = gp.first();
527  continue;
528  }
529  // empty group
530  visitLeave(gp);
531  }
532  else
533  visit(bk);
534 
535  bk = stack.top().next(bk);
536  }
537 
538  // never reached
539 }
540 
KBookmarkGroup::previous
KBookmark previous(const KBookmark &current) const
Return the prevous sibling of a child bookmark of this group.
Definition: kbookmark.cc:78
KBookmarkManager::notifier
KBookmarkNotifier & notifier()
Access to bookmark notifier, for emitting signals.
Definition: kbookmarkmanager.h:237
KBookmarkGroup::isToolbarGroup
bool isToolbarGroup() const
Definition: kbookmark.cc:218
KBookmarkGroup::createNewSeparator
KBookmark createNewSeparator()
Create a new bookmark separator Don&#39;t forget to use KBookmarkManager::self()->emitChanged( parentBook...
Definition: kbookmark.cc:145
KBookmarkGroup::createNewFolder
KBookmarkGroup createNewFolder(KBookmarkManager *mgr, const TQString &text=TQString::null, bool emitSignal=true)
Create a new bookmark folder, as the last child of this group.
Definition: kbookmark.cc:110
KBookmarkGroup::addBookmark
KBookmark addBookmark(KBookmarkManager *mgr, const KBookmark &bm, bool emitSignal=true)
Create a new bookmark, as the last child of this group Don&#39;t forget to use KBookmarkManager::self()->...
Definition: kbookmark.cc:178
KBookmarkManager
This class implements the reading/writing of bookmarks in XML.
Definition: kbookmarkmanager.h:53
KBookmarkGroup::groupUrlList
TQValueList< KURL > groupUrlList() const
Definition: kbookmark.cc:246
KBookmarkGroup::groupAddress
TQString groupAddress() const
Much like KBookmark::address, but caches the address into m_address.
Definition: kbookmark.cc:45
KBookmarkGroup::KBookmarkGroup
KBookmarkGroup()
Create an invalid group.
Definition: kbookmark.cc:35
KBookmarkManager::notifyCompleteChange
ASYNC notifyCompleteChange(TQString caller)
Reparse the whole bookmarks file and notify about the change (Called by the bookmark editor) ...
Definition: kbookmarkmanager.cc:563
KBookmarkGroup
A group of bookmarks.
Definition: kbookmark.h:199
KBookmarkManager::path
TQString path()
This will return the path that this manager is using to read the bookmarks.
Definition: kbookmarkmanager.h:134
KBookmarkGroup::isOpen
bool isOpen() const
Definition: kbookmark.cc:52
KBookmarkGroup::deleteBookmark
void deleteBookmark(KBookmark bk)
Delete a bookmark - it has to be one of our children ! Don&#39;t forget to use KBookmarkManager::self()->...
Definition: kbookmark.cc:213
KBookmarkGroup::moveItem
bool moveItem(const KBookmark &item, const KBookmark &after)
Moves item after after (which should be a child of ours).
Definition: kbookmark.cc:155
KBookmarkGroup::next
KBookmark next(const KBookmark &current) const
Return the next sibling of a child bookmark of this group.
Definition: kbookmark.cc:83
KBookmarkGroup::first
KBookmark first() const
Return the first child bookmark of this group.
Definition: kbookmark.cc:73

kio/bookmarks

Skip menu "kio/bookmarks"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kio/bookmarks

Skip menu "kio/bookmarks"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/bookmarks by doxygen 1.8.11
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |