kio Library API Documentation

kbookmarkmanager.cc

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "kbookmarkmanager.h"
00020 #include "kbookmarkimporter.h"
00021 #include <kdebug.h>
00022 #include <krun.h>
00023 #include <kstandarddirs.h>
00024 #include <ksavefile.h>
00025 #include <qtextstream.h>
00026 #include <qregexp.h>
00027 #include <kmessagebox.h>
00028 #include <kprocess.h>
00029 #include <klocale.h>
00030 #include <kapplication.h>
00031 #include <dcopclient.h>
00032 #include <qfile.h>
00033 #include <qfileinfo.h>
00034 #include <qtextstream.h>
00035 #include <kstaticdeleter.h>
00036 
00037 QPtrList<KBookmarkManager>* KBookmarkManager::s_pSelf = 0L;
00038 KStaticDeleter<QPtrList<KBookmarkManager> > sdbm;
00039 
00040 KBookmarkManager* KBookmarkManager::managerForFile( const QString& bookmarksFile, bool bImportDesktopFiles )
00041 {
00042     if ( !s_pSelf ) {
00043         sdbm.setObject( s_pSelf, new QPtrList<KBookmarkManager> );
00044         s_pSelf->setAutoDelete( true );
00045     }
00046     QPtrListIterator<KBookmarkManager> it ( *s_pSelf );
00047     for ( ; it.current() ; ++it )
00048         if ( it.current()->path() == bookmarksFile )
00049             return it.current();
00050 
00051     KBookmarkManager* mgr = new KBookmarkManager( bookmarksFile, bImportDesktopFiles );
00052     s_pSelf->append( mgr );
00053     return mgr;
00054 }
00055 
00056 KBookmarkManager::KBookmarkManager( const QString & bookmarksFile, bool bImportDesktopFiles )
00057     : DCOPObject(QCString("KBookmarkManager-")+bookmarksFile.utf8()), m_doc("xbel"), m_docIsLoaded(false)
00058 {
00059     m_toolbarDoc.clear();
00060 
00061     m_update = true;
00062     m_showNSBookmarks = true;
00063 
00064     Q_ASSERT( !bookmarksFile.isEmpty() );
00065     m_bookmarksFile = bookmarksFile;
00066 
00067     if ( !QFile::exists(m_bookmarksFile) )
00068     {
00069         // First time we use this class
00070         QDomElement topLevel = m_doc.createElement("xbel");
00071         m_doc.appendChild( topLevel );
00072         if ( bImportDesktopFiles )
00073             importDesktopFiles();
00074         m_docIsLoaded = true;
00075     }
00076 }
00077 
00078 KBookmarkManager::~KBookmarkManager()
00079 {
00080     if ( s_pSelf )
00081         s_pSelf->removeRef( this );
00082 }
00083 
00084 void KBookmarkManager::setUpdate(bool update)
00085 {
00086     m_update = update;
00087 }
00088 
00089 const QDomDocument &KBookmarkManager::internalDocument() const
00090 {
00091     if(!m_docIsLoaded)
00092     {
00093         parse();
00094         m_toolbarDoc.clear();
00095     }
00096     return m_doc;
00097 }
00098 
00099 void KBookmarkManager::parse() const
00100 {
00101     m_docIsLoaded = true;
00102     //kdDebug(1203) << "KBookmarkManager::parse " << m_bookmarksFile << endl;
00103     QFile file( m_bookmarksFile );
00104     if ( !file.open( IO_ReadOnly ) )
00105     {
00106         kdWarning() << "Can't open " << m_bookmarksFile << endl;
00107         return;
00108     }
00109     m_doc = QDomDocument("xbel");
00110     m_doc.setContent( &file );
00111 
00112     QDomElement docElem = m_doc.documentElement();
00113     if ( docElem.isNull() )
00114         kdWarning() << "KBookmarkManager::parse : can't parse " << m_bookmarksFile << endl;
00115     else
00116     {
00117         QString mainTag = docElem.tagName();
00118         if ( mainTag == "BOOKMARKS" )
00119         {
00120             kdWarning() << "Old style bookmarks found. Calling convertToXBEL." << endl;
00121             docElem.setTagName("xbel");
00122             if ( docElem.hasAttribute( "HIDE_NSBK" ) && m_showNSBookmarks ) // non standard either, but we need it
00123             {
00124                 docElem.setAttribute( "hide_nsbk", docElem.attribute( "HIDE_NSBK" ) == "1" ? "yes" : "no" );
00125                 docElem.removeAttribute( "HIDE_NSBK" );
00126             }
00127 
00128             convertToXBEL( docElem );
00129             save();
00130         }
00131         else if ( mainTag != "xbel" )
00132             kdWarning() << "KBookmarkManager::parse : unknown main tag " << mainTag << endl;
00133     }
00134 
00135     file.close();
00136 }
00137 
00138 void KBookmarkManager::convertToXBEL( QDomElement & group )
00139 {
00140     QDomNode n = group.firstChild();
00141     while( !n.isNull() )
00142     {
00143         QDomElement e = n.toElement();
00144         if ( !e.isNull() )
00145             if ( e.tagName() == "TEXT" )
00146             {
00147                 e.setTagName("title");
00148             }
00149             else if ( e.tagName() == "SEPARATOR" )
00150             {
00151                 e.setTagName("separator"); // so close...
00152             }
00153             else if ( e.tagName() == "GROUP" )
00154             {
00155                 e.setTagName("folder");
00156                 convertAttribute(e, "ICON","icon"); // non standard, but we need it
00157                 if ( e.hasAttribute( "TOOLBAR" ) ) // non standard either, but we need it
00158                 {
00159                     e.setAttribute( "toolbar", e.attribute( "TOOLBAR" ) == "1" ? "yes" : "no" );
00160                     e.removeAttribute( "TOOLBAR" );
00161                 }
00162 
00163                 convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem
00164                 bool open = (e.attribute("OPEN") == "1");
00165                 e.removeAttribute("OPEN");
00166                 e.setAttribute("folded", open ? "no" : "yes");
00167                 convertToXBEL( e );
00168             }
00169             else
00170                 if ( e.tagName() == "BOOKMARK" )
00171                 {
00172                     e.setTagName("bookmark"); // so much difference :-)
00173                     convertAttribute(e, "ICON","icon"); // non standard, but we need it
00174                     convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem
00175                     convertAttribute(e, "URL","href");
00176                     QString text = e.text();
00177                     while ( !e.firstChild().isNull() ) // clean up the old contained text
00178                         e.removeChild(e.firstChild());
00179                     QDomElement titleElem = e.ownerDocument().createElement("title");
00180                     e.appendChild( titleElem ); // should be the only child anyway
00181                     titleElem.appendChild( e.ownerDocument().createTextNode( text ) );
00182                 }
00183                 else
00184                     kdWarning(1203) << "Unknown tag " << e.tagName() << endl;
00185         n = n.nextSibling();
00186     }
00187 }
00188 
00189 void KBookmarkManager::convertAttribute( QDomElement elem, const QString & oldName, const QString & newName )
00190 {
00191     if ( elem.hasAttribute( oldName ) )
00192     {
00193         elem.setAttribute( newName, elem.attribute( oldName ) );
00194         elem.removeAttribute( oldName );
00195     }
00196 }
00197 
00198 void KBookmarkManager::importDesktopFiles()
00199 {
00200     KBookmarkImporter importer( const_cast<QDomDocument *>(&internalDocument()) );
00201     QString path(KGlobal::dirs()->saveLocation("data", "kfm/bookmarks", true));
00202     importer.import( path );
00203     //kdDebug(1203) << internalDocument().toCString() << endl;
00204 
00205     save();
00206 }
00207 
00208 bool KBookmarkManager::save( bool toolbarCache ) const
00209 {
00210     return saveAs( m_bookmarksFile, toolbarCache );
00211 }
00212 
00213 bool KBookmarkManager::saveAs( const QString & filename, bool toolbarCache ) const
00214 {
00215     //kdDebug(1203) << "KBookmarkManager::save " << filename << endl;
00216 
00217     // Save the bookmark toolbar folder for quick loading
00218     // but only when it will actually make things quicker
00219     const QString cacheFilename = filename + QString::fromLatin1(".tbcache");
00220     if(toolbarCache && !root().isToolbarGroup())
00221     {
00222         KSaveFile cacheFile( cacheFilename );
00223         if ( cacheFile.status() == 0 )
00224         {
00225             QString str;
00226             QTextStream stream(&str, IO_WriteOnly);
00227             stream << root().findToolbar();
00228             QCString cstr = str.utf8();
00229             cacheFile.file()->writeBlock( cstr.data(), cstr.length() );
00230             cacheFile.close();
00231         }
00232     }
00233     else // remove any (now) stale cache
00234     {
00235         QFile::remove( cacheFilename );
00236     }
00237 
00238     KSaveFile file( filename );
00239 
00240     if ( file.status() != 0 )
00241     {
00242         KMessageBox::error( 0L, i18n("Couldn't save bookmarks in %1. %2").arg(filename).arg(strerror(file.status())) );
00243         return false;
00244     }
00245     QCString cstr = internalDocument().toCString(); // is in UTF8
00246     file.file()->writeBlock( cstr.data(), cstr.length() );
00247     if (!file.close())
00248     {
00249         KMessageBox::error( 0L, i18n("Couldn't save bookmarks in %1. %2").arg(filename).arg(strerror(file.status())) );
00250         return false;
00251     }
00252     return true;
00253 }
00254 
00255 KBookmarkGroup KBookmarkManager::root() const
00256 {
00257     return KBookmarkGroup(internalDocument().documentElement());
00258 }
00259 
00260 KBookmarkGroup KBookmarkManager::toolbar()
00261 {
00262     kdDebug(1203) << "KBookmarkManager::toolbar begin" << endl;
00263     // Only try to read from a toolbar cache if the full document isn't loaded
00264     if(!m_docIsLoaded)
00265     {
00266         kdDebug(1203) << "KBookmarkManager::toolbar trying cache" << endl;
00267         const QString cacheFilename = m_bookmarksFile + QString::fromLatin1(".tbcache");
00268         QFileInfo bmInfo(m_bookmarksFile);
00269         QFileInfo cacheInfo(cacheFilename);
00270         if (m_toolbarDoc.isNull() &&
00271             QFile::exists(cacheFilename) &&
00272             bmInfo.lastModified() < cacheInfo.lastModified())
00273         {
00274             kdDebug(1203) << "KBookmarkManager::toolbar reading file" << endl;
00275             QFile file( cacheFilename );
00276 
00277             if ( file.open( IO_ReadOnly ) )
00278             {
00279                 m_toolbarDoc = QDomDocument("cache");
00280                 m_toolbarDoc.setContent( &file );
00281                 kdDebug(1203) << "KBookmarkManager::toolbar opened" << endl;
00282             }
00283         }
00284         if (!m_toolbarDoc.isNull())
00285         {
00286             kdDebug(1203) << "KBookmarkManager::toolbar returning element" << endl;
00287             QDomElement elem = m_toolbarDoc.firstChild().toElement();
00288             return KBookmarkGroup(elem);
00289         }
00290     }
00291 
00292     // Fallback to the normal way if there is no cache or if the bookmark file
00293     // is already loaded
00294     QDomElement elem = root().findToolbar();
00295     if (elem.isNull())
00296         return root(); // Root is the bookmark toolbar if none has been set.
00297     else
00298         return KBookmarkGroup(root().findToolbar());
00299 }
00300 
00301 KBookmark KBookmarkManager::findByAddress( const QString & address, bool tolerant )
00302 {
00303     //kdDebug(1203) << "KBookmarkManager::findByAddress " << address << endl;
00304     KBookmark result = root();
00305     // The address is something like /5/10/2+
00306     QStringList addresses = QStringList::split(QRegExp("[/+]"),address);
00307     // kdWarning() << addresses.join(",") << endl;
00308     for ( QStringList::Iterator it = addresses.begin() ; it != addresses.end() ; )
00309     {
00310        bool append = ((*it) == "+");
00311        uint number = (*it).toUInt();
00312        Q_ASSERT(result.isGroup());
00313        KBookmarkGroup group = result.toGroup();
00314        KBookmark bk = group.first(), lbk = bk; // last non-null bookmark
00315        for ( uint i = 0 ; ( (i<number) || append ) && !bk.isNull() ; ++i ) {
00316            lbk = bk;
00317            bk = group.next(bk);
00318          //kdWarning() << i << endl;
00319        }
00320        it++;
00321        int shouldBeGroup = !bk.isGroup() && (it != addresses.end());
00322        if ( tolerant && ( bk.isNull() || shouldBeGroup ) ) {
00323           if (!lbk.isNull()) result = lbk;
00324           //kdWarning() << "break" << endl;
00325           break;
00326        }
00327        //kdWarning() << "found section" << endl;
00328        result = bk;
00329     }
00330     if (result.isNull()) {
00331        kdWarning() << "KBookmarkManager::findByAddress: couldn't find item " << address << endl;
00332        Q_ASSERT(!tolerant);
00333     }
00334     //kdWarning() << "found " << result.address() << endl;
00335     return result;
00336  }
00337 
00338 void KBookmarkManager::emitChanged( KBookmarkGroup & group )
00339 {
00340     save();
00341 
00342     // Tell the other processes too
00343     //kdDebug(1203) << "KBookmarkManager::emitChanged : broadcasting change " << group.address() << endl;
00344     QByteArray data;
00345     QDataStream stream( data, IO_WriteOnly );
00346     stream << group.address();
00347     QCString objId( "KBookmarkManager-" );
00348     objId += m_bookmarksFile.utf8();
00349     kapp->dcopClient()->send( "*", objId, "notifyChanged(QString)", data );
00350 
00351     // We do get our own broadcast, so no need for this anymore
00352     //emit changed( group );
00353 }
00354 
00355 void KBookmarkManager::notifyCompleteChange( QString caller ) // DCOP call
00356 {
00357     if (!m_update) return;
00358 
00359     //kdDebug(1203) << "KBookmarkManager::notifyCompleteChange" << endl;
00360     // The bk editor tells us we should reload everything
00361     // Reparse
00362     parse();
00363     // Tell our GUI
00364     // (emit with group == "" to directly mark the root menu as dirty)
00365     emit changed( "", caller );
00366     // Also tell specifically about the toolbar - unless it's the root as well
00367     KBookmarkGroup tbGroup = toolbar();
00368     if (!tbGroup.isNull() && !tbGroup.groupAddress().isEmpty())
00369         emit changed( tbGroup.groupAddress(), caller );
00370 }
00371 
00372 void KBookmarkManager::notifyChanged( QString groupAddress ) // DCOP call
00373 {
00374     if (!m_update) return;
00375 
00376     // Reparse (the whole file, no other choice)
00377     // Of course, if we are the emitter this is a bit stupid....
00378     parse();
00379 
00380     //kdDebug(1203) << "KBookmarkManager::notifyChanged " << groupAddress << endl;
00381     //KBookmarkGroup group = findByAddress( groupAddress ).toGroup();
00382     //Q_ASSERT(!group.isNull());
00383     emit changed( groupAddress, QString::null );
00384 }
00385 
00386 bool KBookmarkManager::showNSBookmarks() const
00387 {
00388     // The attr name is HIDE, so that the default is to show them
00389     return root().internalElement().attribute("hide_nsbk") != "yes";
00390 }
00391 
00392 void KBookmarkManager::setShowNSBookmarks( bool show )
00393 {
00394     m_showNSBookmarks = show;
00395     root().internalElement().setAttribute("hide_nsbk", show ? "no" : "yes");
00396 }
00397 
00398 void KBookmarkManager::slotEditBookmarks()
00399 {
00400     KProcess proc;
00401     proc << QString::fromLatin1("keditbookmarks") << m_bookmarksFile;
00402     proc.start(KProcess::DontCare);
00403 }
00404 
00406 
00407 void KBookmarkOwner::openBookmarkURL(const QString& url)
00408 {
00409   (void) new KRun(url);
00410 }
00411 
00412 void KBookmarkOwner::virtual_hook( int, void* )
00413 { /*BASE::virtual_hook( id, data );*/ }
00414 
00415 #include "kbookmarkmanager.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:13:11 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001