# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kbookmark.cc

    00001 // -*- c-basic-offset:4; indent-tabs-mode:nil -*-
    00002 // vim: set ts=4 sts=4 sw=4 et:
    00003 /* This file is part of the KDE libraries
    00004    Copyright (C) 2000 David Faure <faure@kde.org>
    00005    Copyright (C) 2003 Alexander Kellett <lypanov@kde.org>
    00006
    00007    This library is free software; you can redistribute it and/or
    00008    modify it under the terms of the GNU Library General Public
    00009    License version 2 as published by the Free Software Foundation.
    00010
    00011    This library is distributed in the hope that it will be useful,
    00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014    Library General Public License for more details.
    00015
    00016    You should have received a copy of the GNU Library General Public License
    00017    along with this library; see the file COPYING.LIB.  If not, write to
    00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00019    Boston, MA 02111-1307, USA.
    00020 */
    00021
    00022 #include "kbookmark.h"
    00023 #include <qvaluestack.h>
    00024 #include <kdebug.h>
    00025 #include <kmimetype.h>
    00026 #include <kstringhandler.h>
    00027 #include <kinputdialog.h>
    00028 #include <kglobal.h>
    00029 #include <klocale.h>
    00030 #include <assert.h>
    00031 #include <kapplication.h>
    00032 #include <dcopclient.h>
    00033 #include <kbookmarkmanager.h>
    00034
    00035 KBookmarkGroup::KBookmarkGroup()
    00036  : KBookmark( QDomElement() )
    00037 {
    00038 }
    00039
    00040 KBookmarkGroup::KBookmarkGroup( QDomElement elem )
    00041  : KBookmark(elem)
    00042 {
    00043 }
    00044
    00045 QString KBookmarkGroup::groupAddress() const
    00046 {
    00047     if (m_address.isEmpty())
    00048         m_address = address();
    00049     return m_address;
    00050 }
    00051
    00052 bool KBookmarkGroup::isOpen() const
    00053 {
    00054     return element.attribute("folded") == "no"; // default is: folded
    00055 }
    00056
    00057 // Returns first element node equal to or after node n
    00058 static QDomElement firstElement(QDomNode n)
    00059 {
    00060     while(!n.isNull() && !n.isElement())
    00061         n = n.nextSibling();
    00062     return n.toElement();
    00063 }
    00064
    00065 // Returns first element node equal to or before node n
    00066 static QDomElement lastElement(QDomNode n)
    00067 {
    00068     while(!n.isNull() && !n.isElement())
    00069         n = n.previousSibling();
    00070     return n.toElement();
    00071 }
    00072
    00073 KBookmark KBookmarkGroup::first() const
    00074 {
    00075     return KBookmark( nextKnownTag( firstElement(element.firstChild()), true ) );
    00076 }
    00077
    00078 KBookmark KBookmarkGroup::previous( const KBookmark & current ) const
    00079 {
    00080     return KBookmark( nextKnownTag( lastElement(current.element.previousSibling()), false ) );
    00081 }
    00082
    00083 KBookmark KBookmarkGroup::next( const KBookmark & current ) const
    00084 {
    00085     return KBookmark( nextKnownTag( firstElement(current.element.nextSibling()), true ) );
    00086 }
    00087
    00088 // KDE4: Change QDomElement to QDomNode so that we can get rid of
    00089 // firstElement() and lastElement()
    00090 QDomElement KBookmarkGroup::nextKnownTag( QDomElement start, bool goNext ) const
    00091 {
    00092     static const QString & bookmark = KGlobal::staticQString("bookmark");
    00093     static const QString & folder = KGlobal::staticQString("folder");
    00094     static const QString & separator = KGlobal::staticQString("separator");
    00095
    00096     for( QDomNode n = start; !n.isNull(); )
    00097     {
    00098         QDomElement elem = n.toElement();
    00099         QString tag = elem.tagName();
    00100         if (tag == folder || tag == bookmark || tag == separator)
    00101             return elem;
    00102         if (goNext)
    00103             n = n.nextSibling();
    00104         else
    00105             n = n.previousSibling();
    00106     }
    00107     return QDomElement();
    00108 }
    00109
    00110 KBookmarkGroup KBookmarkGroup::createNewFolder( KBookmarkManager* mgr, const QString & text, bool emitSignal )
    00111 {
    00112     QString txt( text );
    00113     if ( text.isEmpty() )
    00114     {
    00115         bool ok;
    00116         QString caption = parentGroup().fullText().isEmpty() ?
    00117                       i18n( "Create New Bookmark Folder" ) :
    00118                       i18n( "Create New Bookmark Folder in %1" )
    00119                       .arg( parentGroup().text() );
    00120         txt = KInputDialog::getText( caption, i18n( "New folder:" ),
    00121                       QString::null, &ok );
    00122         if ( !ok )
    00123             return KBookmarkGroup();
    00124     }
    00125
    00126     Q_ASSERT(!element.isNull());
    00127     QDomDocument doc = element.ownerDocument();
    00128     QDomElement groupElem = doc.createElement( "folder" );
    00129     element.appendChild( groupElem );
    00130     QDomElement textElem = doc.createElement( "title" );
    00131     groupElem.appendChild( textElem );
    00132     textElem.appendChild( doc.createTextNode( txt ) );
    00133
    00134     KBookmarkGroup grp(groupElem);
    00135
    00136     if (emitSignal)
    00137         emit mgr->notifier().createdNewFolder(
    00138                                 mgr->path(), grp.fullText(),
    00139                                 grp.address() );
    00140
    00141     return grp;
    00142
    00143 }
    00144
    00145 KBookmark KBookmarkGroup::createNewSeparator()
    00146 {
    00147     Q_ASSERT(!element.isNull());
    00148     QDomDocument doc = element.ownerDocument();
    00149     Q_ASSERT(!doc.isNull());
    00150     QDomElement sepElem = doc.createElement( "separator" );
    00151     element.appendChild( sepElem );
    00152     return KBookmark(sepElem);
    00153 }
    00154
    00155 bool KBookmarkGroup::moveItem( const KBookmark & item, const KBookmark & after )
    00156 {
    00157     QDomNode n;
    00158     if ( !after.isNull() )
    00159         n = element.insertAfter( item.element, after.element );
    00160     else // first child
    00161     {
    00162         if ( element.firstChild().isNull() ) // Empty element -> set as real first child
    00163             n = element.insertBefore( item.element, QDomElement() );
    00164
    00165         // we have to skip everything up to the first valid child
    00166         QDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true);
    00167         if ( !firstChild.isNull() )
    00168             n = element.insertBefore( item.element, firstChild );
    00169         else
    00170         {
    00171             // No real first child -> append after the <title> etc.
    00172             n = element.appendChild( item.element );
    00173         }
    00174     }
    00175     return (!n.isNull());
    00176 }
    00177
    00178 KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal )
    00179 {
    00180     element.appendChild( bm.internalElement() );
    00181
    00182     if (emitSignal) {
    00183         if ( bm.hasMetaData() ) {
    00184             mgr->notifyCompleteChange( "" );
    00185         } else {
    00186             emit mgr->notifier().addedBookmark(
    00187                                      mgr->path(), bm.url().url(),
    00188                                      bm.fullText(), bm.address(), bm.icon() );
    00189         }
    00190     }
    00191
    00192     return bm;
    00193 }
    00194
    00195 KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const QString & text, const KURL & url, const QString & icon, bool emitSignal )
    00196 {
    00197     //kdDebug(7043) << "KBookmarkGroup::addBookmark " << text << " into " << m_address << endl;
    00198     QDomDocument doc = element.ownerDocument();
    00199     QDomElement elem = doc.createElement( "bookmark" );
    00200     elem.setAttribute( "href", url.url( 0, 106 ) ); // write utf8 URL (106 is mib enum for utf8)
    00201     QString _icon = icon;
    00202     if ( _icon.isEmpty() )
    00203         _icon = KMimeType::iconForURL( url );
    00204     elem.setAttribute( "icon", _icon );
    00205
    00206     QDomElement textElem = doc.createElement( "title" );
    00207     elem.appendChild( textElem );
    00208     textElem.appendChild( doc.createTextNode( text ) );
    00209
    00210     return addBookmark( mgr, KBookmark( elem ), emitSignal );
    00211 }
    00212
    00213 void KBookmarkGroup::deleteBookmark( KBookmark bk )
    00214 {
    00215     element.removeChild( bk.element );
    00216 }
    00217
    00218 bool KBookmarkGroup::isToolbarGroup() const
    00219 {
    00220     return ( element.attribute("toolbar") == "yes" );
    00221 }
    00222
    00223 QDomElement KBookmarkGroup::findToolbar() const
    00224 {
    00225     if ( element.attribute("toolbar") == "yes" )
    00226         return element;
    00227     for (QDomNode n = element.firstChild(); !n.isNull() ; n = n.nextSibling() )
    00228     {
    00229         QDomElement e = n.toElement();
    00230         // Search among the "folder" children only
    00231         if ( e.tagName() == "folder" )
    00232         {
    00233             if ( e.attribute("toolbar") == "yes" )
    00234                 return e;
    00235             else
    00236             {
    00237                 QDomElement result = KBookmarkGroup(e).findToolbar();
    00238                 if (!result.isNull())
    00239                     return result;
    00240             }
    00241         }
    00242     }
    00243     return QDomElement();
    00244 }
    00245
    00246 QValueList<KURL> KBookmarkGroup::groupUrlList() const
    00247 {
    00248     QValueList<KURL> urlList;
    00249     for ( KBookmark bm = first(); !bm.isNull(); bm = next(bm) )
    00250     {
    00251         if ( bm.isSeparator() || bm.isGroup() )
    00252            continue;
    00253         urlList << bm.url();
    00254     }
    00255     return urlList;
    00256 }
    00257
    00259
    00260 bool KBookmark::isGroup() const
    00261 {
    00262     QString tag = element.tagName();
    00263     return ( tag == "folder"
    00264              || tag == "xbel" ); // don't forget the toplevel group
    00265 }
    00266
    00267 bool KBookmark::isSeparator() const
    00268 {
    00269     return (element.tagName() == "separator");
    00270 }
    00271
    00272 bool KBookmark::hasParent() const
    00273 {
    00274     QDomElement parent = element.parentNode().toElement();
    00275     return !parent.isNull();
    00276 }
    00277
    00278 QString KBookmark::text() const
    00279 {
    00280     return KStringHandler::csqueeze( fullText() );
    00281 }
    00282
    00283 QString KBookmark::fullText() const
    00284 {
    00285     if (isSeparator())
    00286         return i18n("--- separator ---");
    00287
    00288     return element.namedItem("title").toElement().text();
    00289 }
    00290
    00291 KURL KBookmark::url() const
    00292 {
    00293     return KURL(element.attribute("href"), 106); // Decode it from utf8 (106 is mib enum for utf8)
    00294 }
    00295
    00296 QString KBookmark::icon() const
    00297 {
    00298     QString icon = element.attribute("icon");
    00299     if ( icon.isEmpty() )
    00300         // Default icon depends on URL for bookmarks, and is default directory
    00301         // icon for groups.
    00302         if ( isGroup() )
    00303             icon = "bookmark_folder";
    00304         else
    00305             if ( isSeparator() )
    00306                 icon = "eraser"; // whatever
    00307             else
    00308                 icon = KMimeType::iconForURL( url() );
    00309     return icon;
    00310 }
    00311
    00312 KBookmarkGroup KBookmark::parentGroup() const
    00313 {
    00314     return KBookmarkGroup( element.parentNode().toElement() );
    00315 }
    00316
    00317 KBookmarkGroup KBookmark::toGroup() const
    00318 {
    00319     Q_ASSERT( isGroup() );
    00320     return KBookmarkGroup(element);
    00321 }
    00322
    00323 QString KBookmark::address() const
    00324 {
    00325     if ( element.tagName() == "xbel" )
    00326         return ""; // not QString::null !
    00327     else
    00328     {
    00329         // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :)
    00330         if (!hasParent())
    00331         {
    00332             Q_ASSERT(hasParent());
    00333             return "ERROR"; // Avoid an infinite loop
    00334         }
    00335         KBookmarkGroup group = parentGroup();
    00336         QString parentAddress = group.address();
    00337         uint counter = 0;
    00338         // Implementation note: we don't use QDomNode's childNode list because we
    00339         // would have to skip "TEXT", which KBookmarkGroup already does for us.
    00340         for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk), ++counter )
    00341         {
    00342             if ( bk.element == element )
    00343                 return parentAddress + "/" + QString::number(counter);
    00344         }
    00345         kdWarning() << "KBookmark::address : this can't happen!  " << parentAddress << endl;
    00346         return "ERROR";
    00347     }
    00348 }
    00349
    00350 KBookmark KBookmark::standaloneBookmark( const QString & text, const KURL & url, const QString & icon )
    00351 {
    00352     QDomDocument doc("xbel");
    00353     QDomElement elem = doc.createElement("xbel");
    00354     doc.appendChild( elem );
    00355     KBookmarkGroup grp( elem );
    00356     grp.addBookmark( 0L, text, url, icon, false );
    00357     return grp.first();
    00358 }
    00359
    00360 static QDomNode cd_or_create(QDomNode node, QString name)
    00361 {
    00362     QDomNode subnode = node.namedItem(name);
    00363     if (subnode.isNull())
    00364     {
    00365         subnode = node.ownerDocument().createElement(name);
    00366         node.appendChild(subnode);
    00367     }
    00368     return subnode;
    00369 }
    00370
    00371 static QDomText get_or_create_text(QDomNode node)
    00372 {
    00373     QDomNode subnode = node.firstChild();
    00374     if (subnode.isNull())
    00375     {
    00376         subnode = node.ownerDocument().createTextNode("");
    00377         node.appendChild(subnode);
    00378     }
    00379     return subnode.toText();
    00380 }
    00381
    00382 // Look for a metadata with owner="http://www.kde.org" or without any owner (for compatibility)
    00383 static QDomNode findOrCreateMetadata( QDomNode& parent )
    00384 {
    00385     static const char kdeOwner[] = "http://www.kde.org";
    00386     QDomElement metadataElement;
    00387     for ( QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) {
    00388         QDomElement elem = _node.toElement();
    00389         if ( !elem.isNull() && elem.tagName() == "metadata" ) {
    00390             const QString owner = elem.attribute( "owner" );
    00391             if ( owner == kdeOwner )
    00392                 return elem;
    00393             if ( owner.isEmpty() )
    00394                 metadataElement = elem;
    00395         }
    00396     }
    00397     if ( metadataElement.isNull() ) {
    00398         metadataElement = parent.ownerDocument().createElement( "metadata" );
    00399         parent.appendChild(metadataElement);
    00400     }
    00401     metadataElement.setAttribute( "owner", kdeOwner );
    00402     return metadataElement;
    00403 }
    00404
    00405 bool KBookmark::hasMetaData() const
    00406 {
    00407     // ### NOTE: this code creates <info> and <metadata>, despite its name and the const.
    00408     // It doesn't matter much in practice since it's only called for newly-created bookmarks,
    00409     // which will get metadata soon after anyway.
    00410     QDomNode n = cd_or_create( internalElement(), "info" );
    00411     return findOrCreateMetadata( n ).hasChildNodes();
    00412 }
    00413
    00414 void KBookmark::updateAccessMetadata()
    00415 {
    00416     kdDebug(7043) << "KBookmark::updateAccessMetadata " << address() << " " << url().prettyURL() << endl;
    00417
    00418     const uint timet = QDateTime::currentDateTime().toTime_t();
    00419     setMetaDataItem( "time_added", QString::number( timet ), DontOverwriteMetaData );
    00420     setMetaDataItem( "time_visited", QString::number( timet ) );
    00421
    00422     QString countStr = metaDataItem( "visit_count" ); // TODO use spec'ed name
    00423     bool ok;
    00424     int currentCount = countStr.toInt(&ok);
    00425     if (!ok)
    00426         currentCount = 0;
    00427     currentCount++;
    00428     setMetaDataItem( "visit_count", QString::number( currentCount ) );
    00429
    00430     // TODO - for 4.0 - time_modified
    00431 }
    00432
    00433 QString KBookmark::metaDataItem( const QString &key ) const
    00434 {
    00435     QDomNode infoNode = cd_or_create( internalElement(), "info" );
    00436     infoNode = findOrCreateMetadata( infoNode );
    00437     for ( QDomNode n = infoNode.firstChild(); !n.isNull(); n = n.nextSibling() ) {
    00438         if ( !n.isElement() ) {
    00439             continue;
    00440         }
    00441         const QDomElement e = n.toElement();
    00442         if ( e.tagName() == key ) {
    00443             return e.text();
    00444         }
    00445     }
    00446     return QString::null;
    00447 }
    00448
    00449 void KBookmark::setMetaDataItem( const QString &key, const QString &value, MetaDataOverwriteMode mode )
    00450 {
    00451     QDomNode infoNode = cd_or_create( internalElement(), "info" );
    00452     infoNode = findOrCreateMetadata( infoNode );
    00453
    00454     QDomNode item = cd_or_create( infoNode, key );
    00455     QDomText text = get_or_create_text( item );
    00456     if ( mode == DontOverwriteMetaData && !text.data().isEmpty() ) {
    00457         return;
    00458     }
    00459
    00460     text.setData( value );
    00461 }
    00462
    00463 void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root)
    00464 {
    00465     // non-recursive bookmark iterator
    00466     QValueStack<KBookmarkGroup> stack;
    00467     stack.push(root);
    00468     KBookmark bk = stack.top().first();
    00469     for (;;) {
    00470         if (bk.isNull())
    00471         {
    00472             if (stack.isEmpty())
    00473                 return;
    00474             if (stack.count() > 1)
    00475                 visitLeave(stack.top());
    00476             bk = stack.pop();
    00477             bk = stack.top().next(bk);
    00478             if (bk.isNull())
    00479                 continue;
    00480         }
    00481
    00482         if (bk.isGroup())
    00483         {
    00484             KBookmarkGroup gp = bk.toGroup();
    00485             visitEnter(gp);
    00486             if (!gp.first().isNull())
    00487             {
    00488                 stack.push(gp);
    00489                 bk = gp.first();
    00490                 continue;
    00491             }
    00492             // empty group
    00493             visitLeave(gp);
    00494         }
    00495         else
    00496             visit(bk);
    00497
    00498         bk = stack.top().next(bk);
    00499     }
    00500
    00501     // never reached
    00502 }
    00503

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:55 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003