00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kbookmarkmanager.h"
00023 #include "kbookmarkmenu.h"
00024 #include "kbookmarkmenu_p.h"
00025 #include "kbookmarkimporter.h"
00026 #include <kdebug.h>
00027 #include <krun.h>
00028 #include <kstandarddirs.h>
00029 #include <ksavefile.h>
00030 #include <dcopref.h>
00031 #include <qregexp.h>
00032 #include <kmessagebox.h>
00033 #include <kprocess.h>
00034 #include <klocale.h>
00035 #include <kapplication.h>
00036 #include <dcopclient.h>
00037 #include <qfile.h>
00038 #include <qfileinfo.h>
00039 #include <qtextstream.h>
00040 #include <kstaticdeleter.h>
00041 #include <qptrstack.h>
00042
00043 #include "dptrtemplate.h"
00044
00045 class KBookmarkManagerPrivate : public dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate> {
00046 public:
00047 QString m_editorCaption;
00048 bool m_browserEditor;
00049 };
00050 template<> QPtrDict<KBookmarkManagerPrivate>* dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate>::d_ptr = 0;
00051
00052 KBookmarkManagerPrivate* KBookmarkManager::dptr() const {
00053 return KBookmarkManagerPrivate::d( this );
00054 }
00055
00056
00057 QPtrList<KBookmarkManager>* KBookmarkManager::s_pSelf;
00058 static KStaticDeleter<QPtrList<KBookmarkManager> > sdbm;
00059
00060 class KBookmarkMap : private KBookmarkGroupTraverser {
00061 public:
00062 KBookmarkMap( KBookmarkManager * );
00063 void update();
00064 QValueList<KBookmark> find( const QString &url ) const
00065 { return m_bk_map[url]; }
00066 private:
00067 virtual void visit(const KBookmark &);
00068 virtual void visitEnter(const KBookmarkGroup &) { ; }
00069 virtual void visitLeave(const KBookmarkGroup &) { ; }
00070 private:
00071 typedef QValueList<KBookmark> KBookmarkList;
00072 QMap<QString, KBookmarkList> m_bk_map;
00073 KBookmarkManager *m_manager;
00074 };
00075
00076 static KBookmarkMap *s_bk_map = 0;
00077
00078 KBookmarkMap::KBookmarkMap( KBookmarkManager *manager ) {
00079 m_manager = manager;
00080 }
00081
00082 void KBookmarkMap::update()
00083 {
00084 m_bk_map.clear();
00085 KBookmarkGroup root = m_manager->root();
00086 traverse(root);
00087 }
00088
00089 void KBookmarkMap::visit(const KBookmark &bk)
00090 {
00091 if (!bk.isSeparator()) {
00092
00093 m_bk_map[bk.internalElement().attribute("href")].append(bk);
00094 }
00095 }
00096
00097
00098 KBookmarkManager* KBookmarkManager::managerForFile( const QString& bookmarksFile, bool bImportDesktopFiles )
00099 {
00100 if ( !s_pSelf ) {
00101 sdbm.setObject( s_pSelf, new QPtrList<KBookmarkManager> );
00102 s_pSelf->setAutoDelete( true );
00103 }
00104 QPtrListIterator<KBookmarkManager> it ( *s_pSelf );
00105 for ( ; it.current() ; ++it )
00106 if ( it.current()->path() == bookmarksFile )
00107 return it.current();
00108
00109 KBookmarkManager* mgr = new KBookmarkManager( bookmarksFile, bImportDesktopFiles );
00110 s_pSelf->append( mgr );
00111 return mgr;
00112 }
00113
00114
00115 KBookmarkManager* KBookmarkManager::createTempManager()
00116 {
00117 if ( !s_pSelf ) {
00118 sdbm.setObject( s_pSelf, new QPtrList<KBookmarkManager> );
00119 s_pSelf->setAutoDelete( true );
00120 }
00121 KBookmarkManager* mgr = new KBookmarkManager();
00122 s_pSelf->append( mgr );
00123 return mgr;
00124 }
00125
00126 #define PI_DATA "version=\"1.0\" encoding=\"UTF-8\""
00127
00128 KBookmarkManager::KBookmarkManager( const QString & bookmarksFile, bool bImportDesktopFiles )
00129 : DCOPObject(QCString("KBookmarkManager-")+bookmarksFile.utf8()), m_doc("xbel"), m_docIsLoaded(false)
00130 {
00131 m_toolbarDoc.clear();
00132
00133 m_update = true;
00134 m_showNSBookmarks = true;
00135
00136 Q_ASSERT( !bookmarksFile.isEmpty() );
00137 m_bookmarksFile = bookmarksFile;
00138
00139 if ( !QFile::exists(m_bookmarksFile) )
00140 {
00141 QDomElement topLevel = m_doc.createElement("xbel");
00142 m_doc.appendChild( topLevel );
00143 m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel );
00144 if ( bImportDesktopFiles )
00145 importDesktopFiles();
00146 m_docIsLoaded = true;
00147 }
00148
00149 connectDCOPSignal(0, objId(), "bookmarksChanged(QString)", "notifyChanged(QString)", false);
00150 connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false);
00151 }
00152
00153 KBookmarkManager::KBookmarkManager( )
00154 : DCOPObject(QCString("KBookmarkManager-generated")), m_doc("xbel"), m_docIsLoaded(true)
00155 {
00156 m_toolbarDoc.clear();
00157
00158 m_update = false;
00159 m_showNSBookmarks = true;
00160
00161 m_bookmarksFile = QString::null;
00162
00163 QDomElement topLevel = m_doc.createElement("xbel");
00164 m_doc.appendChild( topLevel );
00165 m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel );
00166
00167
00168 #if 0
00169 connectDCOPSignal(0, objId(), "bookmarksChanged(QString)", "notifyChanged(QString)", false);
00170 connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false);
00171 #endif
00172 }
00173
00174 KBookmarkManager::~KBookmarkManager()
00175 {
00176 if ( s_pSelf )
00177 s_pSelf->removeRef( this );
00178 }
00179
00180 void KBookmarkManager::setUpdate( bool update )
00181 {
00182 m_update = update;
00183 }
00184
00185 const QDomDocument &KBookmarkManager::internalDocument() const
00186 {
00187 if(!m_docIsLoaded)
00188 {
00189 parse();
00190 m_toolbarDoc.clear();
00191 }
00192 return m_doc;
00193 }
00194
00195
00196 void KBookmarkManager::parse() const
00197 {
00198 m_docIsLoaded = true;
00199
00200 QFile file( m_bookmarksFile );
00201 if ( !file.open( IO_ReadOnly ) )
00202 {
00203 kdWarning() << "Can't open " << m_bookmarksFile << endl;
00204 return;
00205 }
00206 m_doc = QDomDocument("xbel");
00207 m_doc.setContent( &file );
00208
00209 QDomElement docElem = m_doc.documentElement();
00210 if ( docElem.isNull() )
00211 kdWarning() << "KBookmarkManager::parse : can't parse " << m_bookmarksFile << endl;
00212 else
00213 {
00214 QString mainTag = docElem.tagName();
00215 if ( mainTag == "BOOKMARKS" )
00216 {
00217 kdWarning() << "Old style bookmarks found. Calling convertToXBEL." << endl;
00218 docElem.setTagName("xbel");
00219 if ( docElem.hasAttribute( "HIDE_NSBK" ) && m_showNSBookmarks )
00220 {
00221 docElem.setAttribute( "hide_nsbk", docElem.attribute( "HIDE_NSBK" ) == "1" ? "yes" : "no" );
00222 docElem.removeAttribute( "HIDE_NSBK" );
00223 }
00224
00225 convertToXBEL( docElem );
00226 save();
00227 }
00228 else if ( mainTag != "xbel" )
00229 kdWarning() << "KBookmarkManager::parse : unknown main tag " << mainTag << endl;
00230
00231 QDomNode n = m_doc.documentElement().previousSibling();
00232 if ( n.isProcessingInstruction() )
00233 {
00234 QDomProcessingInstruction pi = n.toProcessingInstruction();
00235 pi.parentNode().removeChild(pi);
00236 }
00237
00238 QDomProcessingInstruction pi;
00239 pi = m_doc.createProcessingInstruction( "xml", PI_DATA );
00240 m_doc.insertBefore( pi, docElem );
00241 }
00242
00243 file.close();
00244 if ( !s_bk_map )
00245 s_bk_map = new KBookmarkMap( const_cast<KBookmarkManager*>( this ) );
00246 s_bk_map->update();
00247 }
00248
00249 void KBookmarkManager::convertToXBEL( QDomElement & group )
00250 {
00251 QDomNode n = group.firstChild();
00252 while( !n.isNull() )
00253 {
00254 QDomElement e = n.toElement();
00255 if ( !e.isNull() )
00256 if ( e.tagName() == "TEXT" )
00257 {
00258 e.setTagName("title");
00259 }
00260 else if ( e.tagName() == "SEPARATOR" )
00261 {
00262 e.setTagName("separator");
00263 }
00264 else if ( e.tagName() == "GROUP" )
00265 {
00266 e.setTagName("folder");
00267 convertAttribute(e, "ICON","icon");
00268 if ( e.hasAttribute( "TOOLBAR" ) )
00269 {
00270 e.setAttribute( "toolbar", e.attribute( "TOOLBAR" ) == "1" ? "yes" : "no" );
00271 e.removeAttribute( "TOOLBAR" );
00272 }
00273
00274 convertAttribute(e, "NETSCAPEINFO","netscapeinfo");
00275 bool open = (e.attribute("OPEN") == "1");
00276 e.removeAttribute("OPEN");
00277 e.setAttribute("folded", open ? "no" : "yes");
00278 convertToXBEL( e );
00279 }
00280 else
00281 if ( e.tagName() == "BOOKMARK" )
00282 {
00283 e.setTagName("bookmark");
00284 convertAttribute(e, "ICON","icon");
00285 convertAttribute(e, "NETSCAPEINFO","netscapeinfo");
00286 convertAttribute(e, "URL","href");
00287 QString text = e.text();
00288 while ( !e.firstChild().isNull() )
00289 e.removeChild(e.firstChild());
00290 QDomElement titleElem = e.ownerDocument().createElement("title");
00291 e.appendChild( titleElem );
00292 titleElem.appendChild( e.ownerDocument().createTextNode( text ) );
00293 }
00294 else
00295 kdWarning(7043) << "Unknown tag " << e.tagName() << endl;
00296 n = n.nextSibling();
00297 }
00298 }
00299
00300 void KBookmarkManager::convertAttribute( QDomElement elem, const QString & oldName, const QString & newName )
00301 {
00302 if ( elem.hasAttribute( oldName ) )
00303 {
00304 elem.setAttribute( newName, elem.attribute( oldName ) );
00305 elem.removeAttribute( oldName );
00306 }
00307 }
00308
00309 void KBookmarkManager::importDesktopFiles()
00310 {
00311 KBookmarkImporter importer( const_cast<QDomDocument *>(&internalDocument()) );
00312 QString path(KGlobal::dirs()->saveLocation("data", "kfm/bookmarks", true));
00313 importer.import( path );
00314
00315
00316 save();
00317 }
00318
00319 bool KBookmarkManager::save( bool toolbarCache ) const
00320 {
00321 return saveAs( m_bookmarksFile, toolbarCache );
00322 }
00323
00324 bool KBookmarkManager::saveAs( const QString & filename, bool toolbarCache ) const
00325 {
00326 kdDebug(7043) << "KBookmarkManager::save " << filename << endl;
00327
00328
00329
00330 const QString cacheFilename = filename + QString::fromLatin1(".tbcache");
00331 if(toolbarCache && !root().isToolbarGroup())
00332 {
00333 KSaveFile cacheFile( cacheFilename );
00334 if ( cacheFile.status() == 0 )
00335 {
00336 QString str;
00337 QTextStream stream(&str, IO_WriteOnly);
00338 stream << root().findToolbar();
00339 QCString cstr = str.utf8();
00340 cacheFile.file()->writeBlock( cstr.data(), cstr.length() );
00341 cacheFile.close();
00342 }
00343 }
00344 else
00345 {
00346 QFile::remove( cacheFilename );
00347 }
00348
00349 KSaveFile file( filename );
00350 if ( file.status() == 0 )
00351 {
00352 file.backupFile( file.name(), QString::null, ".bak" );
00353 QCString cstr;
00354 cstr = internalDocument().toCString();
00355 file.file()->writeBlock( cstr.data(), cstr.length() );
00356 if ( file.close() )
00357 return true;
00358 }
00359
00360 static int hadSaveError = false;
00361 file.abort();
00362 if ( !hadSaveError ) {
00363 QString error = i18n("Unable to save bookmarks in %1. Reported error was: %2. "
00364 "This error message will only be shown once. The cause "
00365 "of the error needs to be fixed as quickly as possible, "
00366 "which is most likely a full hard drive.")
00367 .arg(filename).arg(strerror(file.status()));
00368 if (qApp->type() != QApplication::Tty)
00369 KMessageBox::error( 0L, error );
00370 else
00371 kdError() << error << endl;
00372 }
00373 hadSaveError = true;
00374 return false;
00375 }
00376
00377 KBookmarkGroup KBookmarkManager::root() const
00378 {
00379 return KBookmarkGroup(internalDocument().documentElement());
00380 }
00381
00382 KBookmarkGroup KBookmarkManager::toolbar()
00383 {
00384 kdDebug(7043) << "KBookmarkManager::toolbar begin" << endl;
00385
00386 if(!m_docIsLoaded)
00387 {
00388 kdDebug(7043) << "KBookmarkManager::toolbar trying cache" << endl;
00389 const QString cacheFilename = m_bookmarksFile + QString::fromLatin1(".tbcache");
00390 QFileInfo bmInfo(m_bookmarksFile);
00391 QFileInfo cacheInfo(cacheFilename);
00392 if (m_toolbarDoc.isNull() &&
00393 QFile::exists(cacheFilename) &&
00394 bmInfo.lastModified() < cacheInfo.lastModified())
00395 {
00396 kdDebug(7043) << "KBookmarkManager::toolbar reading file" << endl;
00397 QFile file( cacheFilename );
00398
00399 if ( file.open( IO_ReadOnly ) )
00400 {
00401 m_toolbarDoc = QDomDocument("cache");
00402 m_toolbarDoc.setContent( &file );
00403 kdDebug(7043) << "KBookmarkManager::toolbar opened" << endl;
00404 }
00405 }
00406 if (!m_toolbarDoc.isNull())
00407 {
00408 kdDebug(7043) << "KBookmarkManager::toolbar returning element" << endl;
00409 QDomElement elem = m_toolbarDoc.firstChild().toElement();
00410 return KBookmarkGroup(elem);
00411 }
00412 }
00413
00414
00415
00416 QDomElement elem = root().findToolbar();
00417 if (elem.isNull())
00418 return root();
00419 else
00420 return KBookmarkGroup(root().findToolbar());
00421 }
00422
00423 KBookmark KBookmarkManager::findByAddress( const QString & address, bool tolerant )
00424 {
00425
00426 KBookmark result = root();
00427
00428 QStringList addresses = QStringList::split(QRegExp("[/+]"),address);
00429
00430 for ( QStringList::Iterator it = addresses.begin() ; it != addresses.end() ; )
00431 {
00432 bool append = ((*it) == "+");
00433 uint number = (*it).toUInt();
00434 Q_ASSERT(result.isGroup());
00435 KBookmarkGroup group = result.toGroup();
00436 KBookmark bk = group.first(), lbk = bk;
00437 for ( uint i = 0 ; ( (i<number) || append ) && !bk.isNull() ; ++i ) {
00438 lbk = bk;
00439 bk = group.next(bk);
00440
00441 }
00442 it++;
00443 int shouldBeGroup = !bk.isGroup() && (it != addresses.end());
00444 if ( tolerant && ( bk.isNull() || shouldBeGroup ) ) {
00445 if (!lbk.isNull()) result = lbk;
00446
00447 break;
00448 }
00449
00450 result = bk;
00451 }
00452 if (result.isNull()) {
00453 kdWarning() << "KBookmarkManager::findByAddress: couldn't find item " << address << endl;
00454 Q_ASSERT(!tolerant);
00455 }
00456
00457 return result;
00458 }
00459
00460 static QString pickUnusedTitle( KBookmarkGroup parentBookmark,
00461 const QString &title, const QString &url
00462 ) {
00463
00464 KBookmark ch = parentBookmark.first();
00465 int count = 1;
00466 QString uniqueTitle = title;
00467 do
00468 {
00469 while ( !ch.isNull() )
00470 {
00471 if ( uniqueTitle == ch.text() )
00472 {
00473
00474 if ( url != ch.url().url() )
00475 {
00476 uniqueTitle = title + QString(" (%1)").arg(++count);
00477
00478 ch = parentBookmark.first();
00479 break;
00480 }
00481 else
00482 {
00483
00484 return QString::null;
00485 }
00486 }
00487 ch = parentBookmark.next( ch );
00488 }
00489 } while ( !ch.isNull() );
00490
00491 return uniqueTitle;
00492 }
00493
00494 KBookmarkGroup KBookmarkManager::addBookmarkDialog(
00495 const QString & _url, const QString & _title,
00496 const QString & _parentBookmarkAddress
00497 ) {
00498 QString url = _url;
00499 QString title = _title;
00500 QString parentBookmarkAddress = _parentBookmarkAddress;
00501
00502 if ( url.isEmpty() )
00503 {
00504 KMessageBox::error( 0L, i18n("Cannot add bookmark with empty URL."));
00505 return KBookmarkGroup();
00506 }
00507
00508 if ( title.isEmpty() )
00509 title = url;
00510
00511 if ( KBookmarkSettings::self()->m_advancedaddbookmark)
00512 {
00513 KBookmarkEditDialog dlg( title, url, this, KBookmarkEditDialog::InsertionMode, parentBookmarkAddress );
00514 if ( dlg.exec() != KDialogBase::Accepted )
00515 return KBookmarkGroup();
00516 title = dlg.finalTitle();
00517 url = dlg.finalUrl();
00518 parentBookmarkAddress = dlg.finalAddress();
00519 }
00520
00521 KBookmarkGroup parentBookmark;
00522 parentBookmark = findByAddress( parentBookmarkAddress ).toGroup();
00523 Q_ASSERT( !parentBookmark.isNull() );
00524
00525 QString uniqueTitle = pickUnusedTitle( parentBookmark, title, url );
00526 if ( !uniqueTitle.isNull() )
00527 parentBookmark.addBookmark( this, uniqueTitle, KURL( url ));
00528
00529 return parentBookmark;
00530 }
00531
00532 void KBookmarkManager::emitChanged( KBookmarkGroup & group )
00533 {
00534 save();
00535
00536
00537
00538
00539 QByteArray data;
00540 QDataStream ds( data, IO_WriteOnly );
00541 ds << group.address();
00542
00543 emitDCOPSignal("bookmarksChanged(QString)", data);
00544
00545
00546
00547 }
00548
00549 void KBookmarkManager::emitConfigChanged()
00550 {
00551 emitDCOPSignal("bookmarkConfigChanged()", QByteArray());
00552 }
00553
00554 void KBookmarkManager::notifyCompleteChange( QString caller )
00555 {
00556 if (!m_update) return;
00557
00558
00559
00560
00561 parse();
00562
00563
00564 emit changed( "", caller );
00565
00566 KBookmarkGroup tbGroup = toolbar();
00567 if (!tbGroup.isNull() && !tbGroup.groupAddress().isEmpty())
00568 emit changed( tbGroup.groupAddress(), caller );
00569 }
00570
00571 void KBookmarkManager::notifyConfigChanged()
00572 {
00573 kdDebug() << "reloaded bookmark config!" << endl;
00574 KBookmarkSettings::self()->readSettings();
00575 parse();
00576 }
00577
00578 void KBookmarkManager::notifyChanged( QString groupAddress )
00579 {
00580 if (!m_update) return;
00581
00582
00583
00584 if (callingDcopClient()->senderId() != DCOPClient::mainClient()->appId())
00585 parse();
00586
00587
00588
00589
00590 emit changed( groupAddress, QString::null );
00591 }
00592
00593 bool KBookmarkManager::showNSBookmarks() const
00594 {
00595 return KBookmarkMenu::showDynamicBookmarks("netscape").show;
00596 }
00597
00598 void KBookmarkManager::setShowNSBookmarks( bool show )
00599 {
00600 m_showNSBookmarks = show;
00601 if (this != userBookmarksManager())
00602 return;
00603 KBookmarkMenu::DynMenuInfo info
00604 = KBookmarkMenu::showDynamicBookmarks("netscape");
00605 info.show = show;
00606 KBookmarkMenu::setDynamicBookmarks("netscape", info);
00607 }
00608
00609 void KBookmarkManager::setEditorOptions( const QString& caption, bool browser )
00610 {
00611 dptr()->m_editorCaption = caption;
00612 dptr()->m_browserEditor = browser;
00613 }
00614
00615 void KBookmarkManager::slotEditBookmarks()
00616 {
00617 KProcess proc;
00618 proc << QString::fromLatin1("keditbookmarks");
00619 if (!dptr()->m_editorCaption.isNull())
00620 proc << QString::fromLatin1("--customcaption") << dptr()->m_editorCaption;
00621 if (!dptr()->m_browserEditor)
00622 proc << QString::fromLatin1("--nobrowser");
00623 proc << m_bookmarksFile;
00624 proc.start(KProcess::DontCare);
00625 }
00626
00627 void KBookmarkManager::slotEditBookmarksAtAddress( const QString& address )
00628 {
00629 KProcess proc;
00630 proc << QString::fromLatin1("keditbookmarks")
00631 << QString::fromLatin1("--address") << address
00632 << m_bookmarksFile;
00633 proc.start(KProcess::DontCare);
00634 }
00635
00637
00638 void KBookmarkOwner::openBookmarkURL( const QString& url )
00639 {
00640 (void) new KRun(KURL( url ));
00641 }
00642
00643 void KBookmarkOwner::virtual_hook( int, void* )
00644 { }
00645
00646 bool KBookmarkManager::updateAccessMetadata( const QString & url, bool emitSignal )
00647 {
00648 if (!s_bk_map) {
00649 s_bk_map = new KBookmarkMap(this);
00650 s_bk_map->update();
00651 }
00652
00653 QValueList<KBookmark> list = s_bk_map->find(url);
00654 if ( list.count() == 0 )
00655 return false;
00656
00657 for ( QValueList<KBookmark>::iterator it = list.begin();
00658 it != list.end(); ++it )
00659 (*it).updateAccessMetadata();
00660
00661 if (emitSignal)
00662 emit notifier().updatedAccessMetadata( path(), url );
00663
00664 return true;
00665 }
00666
00667 void KBookmarkManager::updateFavicon( const QString &url, const QString &faviconurl, bool emitSignal )
00668 {
00669 Q_UNUSED(faviconurl);
00670
00671 if (!s_bk_map) {
00672 s_bk_map = new KBookmarkMap(this);
00673 s_bk_map->update();
00674 }
00675
00676 QValueList<KBookmark> list = s_bk_map->find(url);
00677 for ( QValueList<KBookmark>::iterator it = list.begin();
00678 it != list.end(); ++it )
00679 {
00680
00681
00682
00683 }
00684
00685 if (emitSignal)
00686 {
00687
00688
00689 }
00690 }
00691
00692 KBookmarkManager* KBookmarkManager::userBookmarksManager()
00693 {
00694 QString bookmarksFile = locateLocal("data", QString::fromLatin1("konqueror/bookmarks.xml"));
00695 return KBookmarkManager::managerForFile( bookmarksFile );
00696 }
00697
00698 KBookmarkSettings* KBookmarkSettings::s_self = 0;
00699
00700 void KBookmarkSettings::readSettings()
00701 {
00702 KConfig config("kbookmarkrc", false, false);
00703 config.setGroup("Bookmarks");
00704
00705
00706 s_self->m_advancedaddbookmark = config.readBoolEntry("AdvancedAddBookmarkDialog", true);
00707
00708
00709 s_self->m_contextmenu = config.readBoolEntry("ContextMenuActions", true);
00710 s_self->m_quickactions = config.readBoolEntry("QuickActionSubmenu", false);
00711 s_self->m_filteredtoolbar = config.readBoolEntry("FilteredToolbar", false);
00712 }
00713
00714 KBookmarkSettings *KBookmarkSettings::self()
00715 {
00716 if (!s_self)
00717 {
00718 s_self = new KBookmarkSettings;
00719 readSettings();
00720 }
00721 return s_self;
00722 }
00723
00724 #include "kbookmarkmanager.moc"