diff options
Diffstat (limited to 'kio/bookmarks')
30 files changed, 6498 insertions, 0 deletions
diff --git a/kio/bookmarks/Makefile.am b/kio/bookmarks/Makefile.am new file mode 100644 index 000000000..2a41efd98 --- /dev/null +++ b/kio/bookmarks/Makefile.am @@ -0,0 +1,40 @@ +# This file is part of the KDE libraries +# Copyright (C) 1997 Stephan Kulow (coolo@kde.org) + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this library; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +INCLUDES= -I$(srcdir)/../libltdl/ -I$(top_srcdir) -I$(top_srcdir)/kdefx -I$(top_builddir)/kio/kio $(all_includes) + +noinst_LTLIBRARIES = libkbookmarks.la + +METASOURCES = AUTO + +# convenience lib - no _LDFLAGS or _LIBADD ! + +include_HEADERS = \ + kbookmark.h kbookmarkbar.h kbookmarkdrag.h kbookmarkexporter.h \ + kbookmarkimporter.h kbookmarkmanager.h kbookmarkmenu.h kbookmarknotifier.h \ + kbookmarkimporter_crash.h kbookmarkimporter_opera.h kbookmarkimporter_ie.h \ + kbookmarkimporter_ns.h kbookmarkimporter_kde1.h kbookmarkdombuilder.h +libkbookmarks_la_SOURCES = \ + kbookmark.cc kbookmarkbar.cc kbookmarkdrag.cc kbookmarkexporter.cc \ + kbookmarkimporter.cc kbookmarkmanager.cc kbookmarkmenu.cc \ + kbookmarkimporter_crash.cc kbookmarkimporter_opera.cc kbookmarkimporter_ie.cc \ + kbookmarkimporter_ns.cc kbookmarkimporter_kde1.cc kbookmarkdombuilder.cc \ + kbookmarkmanager.skel kbookmarknotifier.skel + +include $(top_srcdir)/admin/Doxyfile.am diff --git a/kio/bookmarks/dptrtemplate.h b/kio/bookmarks/dptrtemplate.h new file mode 100644 index 000000000..26fd0b3a9 --- /dev/null +++ b/kio/bookmarks/dptrtemplate.h @@ -0,0 +1,57 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __dptrtemplate_h__ +#define __dptrtemplate_h__ + +#include <qptrdict.h> + +template<class Instance, class PrivateData> +class dPtrTemplate { +public: + static PrivateData* d( const Instance* instance ) + { + if ( !d_ptr ) { + cleanup_d_ptr(); + d_ptr = new QPtrDict<PrivateData>; + qAddPostRoutine( cleanup_d_ptr ); + } + PrivateData* ret = d_ptr->find( (void*) instance ); + if ( ! ret ) { + ret = new PrivateData; + d_ptr->replace( (void*) instance, ret ); + } + return ret; + } + static void delete_d( const Instance* instance ) + { + if ( d_ptr ) + d_ptr->remove( (void*) instance ); + } +private: + static void cleanup_d_ptr() + { + delete d_ptr; + } + static QPtrDict<PrivateData>* d_ptr; +}; + +#endif diff --git a/kio/bookmarks/kbookmark.cc b/kio/bookmarks/kbookmark.cc new file mode 100644 index 000000000..59cf10db3 --- /dev/null +++ b/kio/bookmarks/kbookmark.cc @@ -0,0 +1,535 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmark.h" +#include <qvaluestack.h> +#include <kdebug.h> +#include <kmimetype.h> +#include <kstringhandler.h> +#include <kinputdialog.h> +#include <kglobal.h> +#include <klocale.h> +#include <assert.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <kbookmarkmanager.h> + +KBookmarkGroup::KBookmarkGroup() + : KBookmark( QDomElement() ) +{ +} + +KBookmarkGroup::KBookmarkGroup( QDomElement elem ) + : KBookmark(elem) +{ +} + +QString KBookmarkGroup::groupAddress() const +{ + if (m_address.isEmpty()) + m_address = address(); + return m_address; +} + +bool KBookmarkGroup::isOpen() const +{ + return element.attribute("folded") == "no"; // default is: folded +} + +// Returns first element node equal to or after node n +static QDomElement firstElement(QDomNode n) +{ + while(!n.isNull() && !n.isElement()) + n = n.nextSibling(); + return n.toElement(); +} + +// Returns first element node equal to or before node n +static QDomElement lastElement(QDomNode n) +{ + while(!n.isNull() && !n.isElement()) + n = n.previousSibling(); + return n.toElement(); +} + +KBookmark KBookmarkGroup::first() const +{ + return KBookmark( nextKnownTag( firstElement(element.firstChild()), true ) ); +} + +KBookmark KBookmarkGroup::previous( const KBookmark & current ) const +{ + return KBookmark( nextKnownTag( lastElement(current.element.previousSibling()), false ) ); +} + +KBookmark KBookmarkGroup::next( const KBookmark & current ) const +{ + return KBookmark( nextKnownTag( firstElement(current.element.nextSibling()), true ) ); +} + +// KDE4: Change QDomElement to QDomNode so that we can get rid of +// firstElement() and lastElement() +QDomElement KBookmarkGroup::nextKnownTag( QDomElement start, bool goNext ) const +{ + static const QString & bookmark = KGlobal::staticQString("bookmark"); + static const QString & folder = KGlobal::staticQString("folder"); + static const QString & separator = KGlobal::staticQString("separator"); + + for( QDomNode n = start; !n.isNull(); ) + { + QDomElement elem = n.toElement(); + QString tag = elem.tagName(); + if (tag == folder || tag == bookmark || tag == separator) + return elem; + if (goNext) + n = n.nextSibling(); + else + n = n.previousSibling(); + } + return QDomElement(); +} + +KBookmarkGroup KBookmarkGroup::createNewFolder( KBookmarkManager* mgr, const QString & text, bool emitSignal ) +{ + QString txt( text ); + if ( text.isEmpty() ) + { + bool ok; + QString caption = parentGroup().fullText().isEmpty() ? + i18n( "Create New Bookmark Folder" ) : + i18n( "Create New Bookmark Folder in %1" ) + .arg( parentGroup().text() ); + txt = KInputDialog::getText( caption, i18n( "New folder:" ), + QString::null, &ok ); + if ( !ok ) + return KBookmarkGroup(); + } + + Q_ASSERT(!element.isNull()); + QDomDocument doc = element.ownerDocument(); + QDomElement groupElem = doc.createElement( "folder" ); + element.appendChild( groupElem ); + QDomElement textElem = doc.createElement( "title" ); + groupElem.appendChild( textElem ); + textElem.appendChild( doc.createTextNode( txt ) ); + + KBookmarkGroup grp(groupElem); + + if (emitSignal) + emit mgr->notifier().createdNewFolder( + mgr->path(), grp.fullText(), + grp.address() ); + + return grp; + +} + +KBookmark KBookmarkGroup::createNewSeparator() +{ + Q_ASSERT(!element.isNull()); + QDomDocument doc = element.ownerDocument(); + Q_ASSERT(!doc.isNull()); + QDomElement sepElem = doc.createElement( "separator" ); + element.appendChild( sepElem ); + return KBookmark(sepElem); +} + +bool KBookmarkGroup::moveItem( const KBookmark & item, const KBookmark & after ) +{ + QDomNode n; + if ( !after.isNull() ) + n = element.insertAfter( item.element, after.element ); + else // first child + { + if ( element.firstChild().isNull() ) // Empty element -> set as real first child + n = element.insertBefore( item.element, QDomElement() ); + + // we have to skip everything up to the first valid child + QDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true); + if ( !firstChild.isNull() ) + n = element.insertBefore( item.element, firstChild ); + else + { + // No real first child -> append after the <title> etc. + n = element.appendChild( item.element ); + } + } + return (!n.isNull()); +} + +KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal ) +{ + element.appendChild( bm.internalElement() ); + + if (emitSignal) { + if ( bm.hasMetaData() ) { + mgr->notifyCompleteChange( "" ); + } else { + emit mgr->notifier().addedBookmark( + mgr->path(), bm.url().url(), + bm.fullText(), bm.address(), bm.icon() ); + } + } + + return bm; +} + +KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const QString & text, const KURL & url, const QString & icon, bool emitSignal ) +{ + //kdDebug(7043) << "KBookmarkGroup::addBookmark " << text << " into " << m_address << endl; + QDomDocument doc = element.ownerDocument(); + QDomElement elem = doc.createElement( "bookmark" ); + elem.setAttribute( "href", url.url( 0, 106 ) ); // write utf8 URL (106 is mib enum for utf8) + QString _icon = icon; + if ( _icon.isEmpty() ) + _icon = KMimeType::iconForURL( url ); + elem.setAttribute( "icon", _icon ); + + QDomElement textElem = doc.createElement( "title" ); + elem.appendChild( textElem ); + textElem.appendChild( doc.createTextNode( text ) ); + + return addBookmark( mgr, KBookmark( elem ), emitSignal ); +} + +void KBookmarkGroup::deleteBookmark( KBookmark bk ) +{ + element.removeChild( bk.element ); +} + +bool KBookmarkGroup::isToolbarGroup() const +{ + return ( element.attribute("toolbar") == "yes" ); +} + +QDomElement KBookmarkGroup::findToolbar() const +{ + if ( element.attribute("toolbar") == "yes" ) + return element; + for (QDomNode n = element.firstChild(); !n.isNull() ; n = n.nextSibling() ) + { + QDomElement e = n.toElement(); + // Search among the "folder" children only + if ( e.tagName() == "folder" ) + { + if ( e.attribute("toolbar") == "yes" ) + return e; + else + { + QDomElement result = KBookmarkGroup(e).findToolbar(); + if (!result.isNull()) + return result; + } + } + } + return QDomElement(); +} + +QValueList<KURL> KBookmarkGroup::groupUrlList() const +{ + QValueList<KURL> urlList; + for ( KBookmark bm = first(); !bm.isNull(); bm = next(bm) ) + { + if ( bm.isSeparator() || bm.isGroup() ) + continue; + urlList << bm.url(); + } + return urlList; +} + +////// + +bool KBookmark::isGroup() const +{ + QString tag = element.tagName(); + return ( tag == "folder" + || tag == "xbel" ); // don't forget the toplevel group +} + +bool KBookmark::isSeparator() const +{ + return (element.tagName() == "separator"); +} + +bool KBookmark::hasParent() const +{ + QDomElement parent = element.parentNode().toElement(); + return !parent.isNull(); +} + +QString KBookmark::text() const +{ + return KStringHandler::csqueeze( fullText() ); +} + +QString KBookmark::fullText() const +{ + if (isSeparator()) + return i18n("--- separator ---"); + + return element.namedItem("title").toElement().text(); +} + +KURL KBookmark::url() const +{ + return KURL(element.attribute("href"), 106); // Decode it from utf8 (106 is mib enum for utf8) +} + +QString KBookmark::icon() const +{ + QString icon = element.attribute("icon"); + if ( icon.isEmpty() ) + // Default icon depends on URL for bookmarks, and is default directory + // icon for groups. + if ( isGroup() ) + icon = "bookmark_folder"; + else + if ( isSeparator() ) + icon = "eraser"; // whatever + else + icon = KMimeType::iconForURL( url() ); + return icon; +} + +KBookmarkGroup KBookmark::parentGroup() const +{ + return KBookmarkGroup( element.parentNode().toElement() ); +} + +KBookmarkGroup KBookmark::toGroup() const +{ + Q_ASSERT( isGroup() ); + return KBookmarkGroup(element); +} + +QString KBookmark::address() const +{ + if ( element.tagName() == "xbel" ) + return ""; // not QString::null ! + else + { + // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :) + if (!hasParent()) + { + Q_ASSERT(hasParent()); + return "ERROR"; // Avoid an infinite loop + } + KBookmarkGroup group = parentGroup(); + QString parentAddress = group.address(); + uint counter = 0; + // Implementation note: we don't use QDomNode's childNode list because we + // would have to skip "TEXT", which KBookmarkGroup already does for us. + for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk), ++counter ) + { + if ( bk.element == element ) + return parentAddress + "/" + QString::number(counter); + } + kdWarning() << "KBookmark::address : this can't happen! " << parentAddress << endl; + return "ERROR"; + } +} + +KBookmark KBookmark::standaloneBookmark( const QString & text, const KURL & url, const QString & icon ) +{ + QDomDocument doc("xbel"); + QDomElement elem = doc.createElement("xbel"); + doc.appendChild( elem ); + KBookmarkGroup grp( elem ); + grp.addBookmark( 0L, text, url, icon, false ); + return grp.first(); +} + +// For some strange reason QString("").left(0) returns QString::null; +// That breaks commonParent() +QString KBookmark::left(const QString & str, uint len) +{ + //kdDebug()<<"********"<<QString("").left(0).isNull()<<endl; + if(len == 0) + return QString(""); + else + return str.left(len); +} + +QString KBookmark::commonParent(QString A, QString B) +{ + QString error("ERROR"); + if(A == error || B == error) + return error; + + A += "/"; + B += "/"; + + uint lastCommonSlash = 0; + uint lastPos = A.length() < B.length() ? A.length() : B.length(); + for(uint i=0; i < lastPos; ++i) + { + if(A[i] != B[i]) + return left(A, lastCommonSlash); + if(A[i] == '/') + lastCommonSlash = i; + } + return left(A, lastCommonSlash); +} + +static QDomNode cd_or_create(QDomNode node, QString name) +{ + QDomNode subnode = node.namedItem(name); + if (subnode.isNull()) + { + subnode = node.ownerDocument().createElement(name); + node.appendChild(subnode); + } + return subnode; +} + +static QDomText get_or_create_text(QDomNode node) +{ + QDomNode subnode = node.firstChild(); + if (subnode.isNull()) + { + subnode = node.ownerDocument().createTextNode(""); + node.appendChild(subnode); + } + return subnode.toText(); +} + +// Look for a metadata with owner="http://www.kde.org" or without any owner (for compatibility) +static QDomNode findOrCreateMetadata( QDomNode& parent ) +{ + static const char kdeOwner[] = "http://www.kde.org"; + QDomElement metadataElement; + for ( QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) { + QDomElement elem = _node.toElement(); + if ( !elem.isNull() && elem.tagName() == "metadata" ) { + const QString owner = elem.attribute( "owner" ); + if ( owner == kdeOwner ) + return elem; + if ( owner.isEmpty() ) + metadataElement = elem; + } + } + if ( metadataElement.isNull() ) { + metadataElement = parent.ownerDocument().createElement( "metadata" ); + parent.appendChild(metadataElement); + } + metadataElement.setAttribute( "owner", kdeOwner ); + return metadataElement; +} + +bool KBookmark::hasMetaData() const +{ + // ### NOTE: this code creates <info> and <metadata>, despite its name and the const. + // It doesn't matter much in practice since it's only called for newly-created bookmarks, + // which will get metadata soon after anyway. + QDomNode n = cd_or_create( internalElement(), "info" ); + return findOrCreateMetadata( n ).hasChildNodes(); +} + +void KBookmark::updateAccessMetadata() +{ + kdDebug(7043) << "KBookmark::updateAccessMetadata " << address() << " " << url().prettyURL() << endl; + + const uint timet = QDateTime::currentDateTime().toTime_t(); + setMetaDataItem( "time_added", QString::number( timet ), DontOverwriteMetaData ); + setMetaDataItem( "time_visited", QString::number( timet ) ); + + QString countStr = metaDataItem( "visit_count" ); // TODO use spec'ed name + bool ok; + int currentCount = countStr.toInt(&ok); + if (!ok) + currentCount = 0; + currentCount++; + setMetaDataItem( "visit_count", QString::number( currentCount ) ); + + // TODO - for 4.0 - time_modified +} + +QString KBookmark::metaDataItem( const QString &key ) const +{ + QDomNode infoNode = cd_or_create( internalElement(), "info" ); + infoNode = findOrCreateMetadata( infoNode ); + for ( QDomNode n = infoNode.firstChild(); !n.isNull(); n = n.nextSibling() ) { + if ( !n.isElement() ) { + continue; + } + const QDomElement e = n.toElement(); + if ( e.tagName() == key ) { + return e.text(); + } + } + return QString::null; +} + +void KBookmark::setMetaDataItem( const QString &key, const QString &value, MetaDataOverwriteMode mode ) +{ + QDomNode infoNode = cd_or_create( internalElement(), "info" ); + infoNode = findOrCreateMetadata( infoNode ); + + QDomNode item = cd_or_create( infoNode, key ); + QDomText text = get_or_create_text( item ); + if ( mode == DontOverwriteMetaData && !text.data().isEmpty() ) { + return; + } + + text.setData( value ); +} + +void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root) +{ + // non-recursive bookmark iterator + QValueStack<KBookmarkGroup> stack; + stack.push(root); + KBookmark bk = stack.top().first(); + for (;;) { + if (bk.isNull()) + { + if (stack.isEmpty()) + return; + if (stack.count() > 1) + visitLeave(stack.top()); + bk = stack.pop(); + bk = stack.top().next(bk); + if (bk.isNull()) + continue; + } + + if (bk.isGroup()) + { + KBookmarkGroup gp = bk.toGroup(); + visitEnter(gp); + if (!gp.first().isNull()) + { + stack.push(gp); + bk = gp.first(); + continue; + } + // empty group + visitLeave(gp); + } + else + visit(bk); + + bk = stack.top().next(bk); + } + + // never reached +} + diff --git a/kio/bookmarks/kbookmark.h b/kio/bookmarks/kbookmark.h new file mode 100644 index 000000000..9cb9b1fdf --- /dev/null +++ b/kio/bookmarks/kbookmark.h @@ -0,0 +1,329 @@ +// -*- c-basic-offset: 4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __kbookmark_h +#define __kbookmark_h + +#include <qstring.h> +#include <qvaluelist.h> +#include <qdom.h> +#include <kurl.h> + +class KBookmarkManager; +class KBookmarkGroup; + +class KIO_EXPORT KBookmark +{ + friend class KBookmarkGroup; +public: + enum MetaDataOverwriteMode { + OverwriteMetaData, DontOverwriteMetaData + }; + + KBookmark( ) {} + KBookmark( QDomElement elem ) : element(elem) {} + + static KBookmark standaloneBookmark( const QString & text, const KURL & url, const QString & icon = QString::null ); + + /** + * Whether the bookmark is a group or a normal bookmark + */ + bool isGroup() const; + + /** + * Whether the bookmark is a separator + */ + bool isSeparator() const; + + /** + * @return true if this is a null bookmark. This will never + * be the case for a real bookmark (in a menu), but it's used + * for instance as the end condition for KBookmarkGroup::next() + */ + bool isNull() const {return element.isNull();} + + /** + * @return true if bookmark is contained by a QDomDocument, + * if not it is most likely that it has become separated and + * is thus invalid and/or has been deleted from the bookmarks. + * @since 3.2 + */ + bool hasParent() const; + + /** + * Text shown for the bookmark + * If bigger than 40, the text is shortened by + * replacing middle characters with "..." (see KStringHandler::csqueeze) + */ + QString text() const; + /** + * Text shown for the bookmark, not truncated. + * You should not use this - this is mainly for keditbookmarks. + */ + QString fullText() const; + /** + * URL contained by the bookmark + */ + KURL url() const; + /** + * @return the pixmap file for this bookmark + * (i.e. the name of the icon) + */ + QString icon() const; + + /** + * @return the group containing this bookmark + */ + KBookmarkGroup parentGroup() const; + + /** + * Convert this to a group - do this only if + * isGroup() returns true. + */ + KBookmarkGroup toGroup() const; + + /** + * Return the "address" of this bookmark in the whole tree. + * This is used when telling other processes about a change + * in a given bookmark. The encoding of the address is "/4/2", for + * instance, to design the 2nd child inside the 4th child of the root bk. + */ + QString address() const; + + // Hard to decide. Good design would imply that each bookmark + // knows about its manager, so that there can be several managers. + // But if we say there is only one manager (i.e. set of bookmarks) + // per application, then KBookmarkManager::self() is much easier. + //KBookmarkManager * manager() const { return m_manager; } + + /** + * @internal for KEditBookmarks + */ + QDomElement internalElement() const { return element; } + + /** + * Updates the bookmarks access metadata + * Call when a user accesses the bookmark + * @since 3.2 + */ + void updateAccessMetadata(); + + // Utility functions (internal) + + /** + * @return address of parent + */ + static QString parentAddress( const QString & address ) + { return address.left( address.findRev('/') ); } + + /** + * @return position in parent (e.g. /4/5/2 -> 2) + */ + static uint positionInParent( const QString & address ) + { return address.mid( address.findRev('/') + 1 ).toInt(); } + + /** + * @return address of previous sibling (e.g. /4/5/2 -> /4/5/1) + * Returns QString::null for a first child + */ + static QString previousAddress( const QString & address ) + { + uint pp = positionInParent(address); + return pp>0 ? parentAddress(address) + '/' + QString::number(pp-1) : QString::null; + } + + /** + * @return address of next sibling (e.g. /4/5/2 -> /4/5/3) + * This doesn't check whether it actually exists + */ + static QString nextAddress( const QString & address ) + { return parentAddress(address) + '/' + QString::number(positionInParent(address)+1); } + + /** + * @return the common parent of both addresses which + * has the greatest depth + * @since 3.5 + */ + static QString commonParent(QString A, QString B); + + /** + * Get the value of a specific metadata item. + * @param key Name of the metadata item + * @return Value of the metadata item. QString::null is returned in case + * the specified key does not exist. + * @since 3.4 + */ + QString metaDataItem( const QString &key ) const; + + /** + * Change the value of a specific metadata item, or create the given item + * if it doesn't exist already. + * @param key Name of the metadata item to change + * @param value Value to use for the specified metadata item + * @param mode Whether to overwrite the item's value if it exists already or not. + * @since 3.4 + */ + void setMetaDataItem( const QString &key, const QString &value, MetaDataOverwriteMode mode = OverwriteMetaData ); + +protected: + QDomElement element; + // Note: you can't add new member variables here. + // The KBookmarks are created on the fly, as wrappers + // around internal QDomElements. Any additional information + // has to be implemented as an attribute of the QDomElement. + +private: + bool hasMetaData() const; + static QString left(const QString & str, uint len); +}; + +/** + * A group of bookmarks + */ +class KIO_EXPORT KBookmarkGroup : public KBookmark +{ +public: + /** + * Create an invalid group. This is mostly for use in QValueList, + * and other places where we need a null group. + * Also used as a parent for a bookmark that doesn't have one + * (e.g. Netscape bookmarks) + */ + KBookmarkGroup(); + + /** + * Create a bookmark group as specified by the given element + */ + KBookmarkGroup( QDomElement elem ); + + /** + * Much like KBookmark::address, but caches the + * address into m_address. + */ + QString groupAddress() const; + + /** + * @return true if the bookmark folder is opened in the bookmark editor + */ + bool isOpen() const; + + /** + * Return the first child bookmark of this group + */ + KBookmark first() const; + /** + * Return the prevous sibling of a child bookmark of this group + * @param current has to be one of our child bookmarks. + */ + KBookmark previous( const KBookmark & current ) const; + /** + * Return the next sibling of a child bookmark of this group + * @param current has to be one of our child bookmarks. + */ + KBookmark next( const KBookmark & current ) const; + + /** + * Create a new bookmark folder, as the last child of this group + * @param mgr the manager of the bookmark + * @param text for the folder. If empty, the user will be queried for it. + * @param emitSignal if true emit KBookmarkNotifier signal + */ + KBookmarkGroup createNewFolder( KBookmarkManager* mgr, const QString & text = QString::null, bool emitSignal = true ); + /** + * Create a new bookmark separator + * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark ); + */ + KBookmark createNewSeparator(); + + /** + * Create a new bookmark, as the last child of this group + * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark ); + * @param mgr the manager of the bookmark + * @param bm the bookmark to add + * @param emitSignal if true emit KBookmarkNotifier signal + * @since 3.4 + */ + KBookmark addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal = true ); + + /** + * Create a new bookmark, as the last child of this group + * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark ); + * @param mgr the manager of the bookmark + * @param text for the bookmark + * @param url the URL that the bookmark points to + * @param icon the name of the icon to associate with the bookmark. A suitable default + * will be determined from the URL if not specified. + * @param emitSignal if true emit KBookmarkNotifier signal + */ + KBookmark addBookmark( KBookmarkManager* mgr, const QString & text, const KURL & url, const QString & icon = QString::null, bool emitSignal = true ); + + /** + * Moves @p item after @p after (which should be a child of ours). + * If item is null, @p item is moved as the first child. + * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark ); + */ + bool moveItem( const KBookmark & item, const KBookmark & after ); + + /** + * Delete a bookmark - it has to be one of our children ! + * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark ); + */ + void deleteBookmark( KBookmark bk ); + + /** + * @return true if this is the toolbar group + */ + bool isToolbarGroup() const; + /** + * @internal + */ + QDomElement findToolbar() const; + + /** + * @return the list of urls of bookmarks at top level of the group + * @since 3.2 + */ + QValueList<KURL> groupUrlList() const; + +protected: + QDomElement nextKnownTag( QDomElement start, bool goNext ) const; + +private: + mutable QString m_address; + // Note: you can't add other member variables here, except for caching info. + // The KBookmarks are created on the fly, as wrappers + // around internal QDomElements. Any additional information + // has to be implemented as an attribute of the QDomElement. +}; + +/** + * @since 3.2 + */ +class KIO_EXPORT KBookmarkGroupTraverser { +protected: + virtual ~KBookmarkGroupTraverser() { ; } + void traverse(const KBookmarkGroup &); + virtual void visit(const KBookmark &) { ; } + virtual void visitEnter(const KBookmarkGroup &) { ; } + virtual void visitLeave(const KBookmarkGroup &) { ; } +private: + class KBookmarkGroupTraverserPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkbar.cc b/kio/bookmarks/kbookmarkbar.cc new file mode 100644 index 000000000..d71069014 --- /dev/null +++ b/kio/bookmarks/kbookmarkbar.cc @@ -0,0 +1,554 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 1999 Kurt Granroth <granroth@kde.org> + Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include <qregexp.h> +#include <qfile.h> + +#include <kbookmarkbar.h> +#include <kbookmarkdrag.h> + +#include <kbookmarkmenu.h> +#include <kdebug.h> + +#include <ktoolbar.h> +#include <ktoolbarbutton.h> + +#include <kconfig.h> +#include <kpopupmenu.h> + +#include "kbookmarkdrag.h" +#include "kbookmarkmenu_p.h" +#include "kbookmarkdombuilder.h" + +#include "dptrtemplate.h" + +#include <qapplication.h> + +class KBookmarkBarPrivate : public dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate> +{ +public: + QPtrList<KAction> m_actions; + bool m_readOnly; + KBookmarkManager* m_filteredMgr; + KToolBar* m_sepToolBar; + int m_sepIndex; + bool m_atFirst; + QString m_dropAddress; + QString m_highlightedAddress; +public: + KBookmarkBarPrivate() { + m_readOnly = false; + m_filteredMgr = 0; + m_sepToolBar = 0; + m_sepIndex = -1; + m_atFirst = false; + } +}; +template<> QPtrDict<KBookmarkBarPrivate>* dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>::d_ptr = 0; + +KBookmarkBarPrivate* KBookmarkBar::dptr() const +{ + return KBookmarkBarPrivate::d( this ); +} + +// usage of KXBELBookmarkImporterImpl is just plain evil, but it reduces code dup. so... +class ToolbarFilter : public KXBELBookmarkImporterImpl +{ +public: + ToolbarFilter() : m_visible(false) { ; } + void filter( const KBookmarkGroup &grp ) { traverse(grp); } +private: + virtual void visit( const KBookmark & ); + virtual void visitEnter( const KBookmarkGroup & ); + virtual void visitLeave( const KBookmarkGroup & ); +private: + bool m_visible; + KBookmarkGroup m_visibleStart; +}; + +KBookmarkBar::KBookmarkBar( KBookmarkManager* mgr, + KBookmarkOwner *_owner, KToolBar *_toolBar, + KActionCollection *coll, + QObject *parent, const char *name ) + : QObject( parent, name ), m_pOwner(_owner), m_toolBar(_toolBar), + m_actionCollection( coll ), m_pManager(mgr) +{ + m_lstSubMenus.setAutoDelete( true ); + + m_toolBar->setAcceptDrops( true ); + m_toolBar->installEventFilter( this ); // for drops + + dptr()->m_actions.setAutoDelete( true ); + + connect( mgr, SIGNAL( changed(const QString &, const QString &) ), + SLOT( slotBookmarksChanged(const QString &) ) ); + + KBookmarkGroup toolbar = getToolbar(); + fillBookmarkBar( toolbar ); +} + +QString KBookmarkBar::parentAddress() +{ + return dptr()->m_filteredMgr ? QString::null : m_pManager->toolbar().address(); +} + +#define CURRENT_TOOLBAR() ( \ + dptr()->m_filteredMgr ? dptr()->m_filteredMgr->root() \ + : m_pManager->toolbar() ) + +#define CURRENT_MANAGER() ( \ + dptr()->m_filteredMgr ? dptr()->m_filteredMgr \ + : m_pManager ) + +KBookmarkGroup KBookmarkBar::getToolbar() +{ + if ( KBookmarkSettings::self()->m_filteredtoolbar ) + { + if ( !dptr()->m_filteredMgr ) { + dptr()->m_filteredMgr = KBookmarkManager::createTempManager(); + } else { + KBookmarkGroup bkRoot = dptr()->m_filteredMgr->root(); + QValueList<KBookmark> bks; + for (KBookmark bm = bkRoot.first(); !bm.isNull(); bm = bkRoot.next(bm)) + bks << bm; + for ( QValueListConstIterator<KBookmark> it = bks.begin(); it != bks.end(); ++it ) + bkRoot.deleteBookmark( (*it) ); + } + ToolbarFilter filter; + KBookmarkDomBuilder builder( dptr()->m_filteredMgr->root(), + dptr()->m_filteredMgr ); + builder.connectImporter( &filter ); + filter.filter( m_pManager->root() ); + } + + return CURRENT_TOOLBAR(); +} + +KBookmarkBar::~KBookmarkBar() +{ + //clear(); + KBookmarkBarPrivate::delete_d(this); +} + +void KBookmarkBar::clear() +{ + QPtrListIterator<KAction> it( dptr()->m_actions ); + m_toolBar->clear(); + for (; it.current(); ++it ) { + (*it)->unplugAll(); + } + dptr()->m_actions.clear(); + m_lstSubMenus.clear(); +} + +void KBookmarkBar::slotBookmarksChanged( const QString & group ) +{ + KBookmarkGroup tb = getToolbar(); // heavy for non cached toolbar version + kdDebug(7043) << "slotBookmarksChanged( " << group << " )" << endl; + + if ( tb.isNull() ) + return; + + if ( KBookmark::commonParent(group, tb.address()) == group // Is group a parent of tb.address? + || KBookmarkSettings::self()->m_filteredtoolbar ) + { + clear(); + fillBookmarkBar( tb ); + } + else + { + // Iterate recursively into child menus + QPtrListIterator<KBookmarkMenu> it( m_lstSubMenus ); + for (; it.current(); ++it ) + { + it.current()->slotBookmarksChanged( group ); + } + } +} + +void KBookmarkBar::fillBookmarkBar(KBookmarkGroup & parent) +{ + if (parent.isNull()) + return; + + for (KBookmark bm = parent.first(); !bm.isNull(); bm = parent.next(bm)) + { + QString text = bm.text(); + text.replace( '&', "&&" ); + if (!bm.isGroup()) + { + if ( bm.isSeparator() ) + m_toolBar->insertLineSeparator(); + else + { + KAction *action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 ); + connect(action, SIGNAL( activated ( KAction::ActivationReason, Qt::ButtonState )), + this, SLOT( slotBookmarkSelected( KAction::ActivationReason, Qt::ButtonState ) )); + + action->setProperty( "url", bm.url().url() ); + action->setProperty( "address", bm.address() ); + + action->setToolTip( bm.url().pathOrURL() ); + + action->plug(m_toolBar); + + dptr()->m_actions.append( action ); + } + } + else + { + KActionMenu *action = new KBookmarkActionMenu( text, bm.icon(), + m_actionCollection, + "bookmarkbar-actionmenu"); + action->setProperty( "address", bm.address() ); + action->setProperty( "readOnly", dptr()->m_readOnly ); + action->setDelayed( false ); + + // this flag doesn't have any UI yet + KGlobal::config()->setGroup( "Settings" ); + bool addEntriesBookmarkBar = KGlobal::config()->readBoolEntry("AddEntriesBookmarkBar",true); + + KBookmarkMenu *menu = new KBookmarkMenu(CURRENT_MANAGER(), m_pOwner, action->popupMenu(), + m_actionCollection, false, addEntriesBookmarkBar, + bm.address()); + connect(menu, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ), + this, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) )); + connect(menu, SIGNAL( openBookmark( const QString &, Qt::ButtonState) ), + this, SIGNAL( openBookmark( const QString &, Qt::ButtonState) )); + menu->fillBookmarkMenu(); + action->plug(m_toolBar); + m_lstSubMenus.append( menu ); + + dptr()->m_actions.append( action ); + } + } +} + +void KBookmarkBar::setReadOnly(bool readOnly) +{ + dptr()->m_readOnly = readOnly; +} + +bool KBookmarkBar::isReadOnly() const +{ + return dptr()->m_readOnly; +} + +void KBookmarkBar::slotBookmarkSelected( KAction::ActivationReason /*reason*/, Qt::ButtonState state ) +{ + if (!m_pOwner) return; // this view doesn't handle bookmarks... + + const KAction* action = dynamic_cast<const KAction *>(sender()); + if(action) + { + const QString & url = sender()->property("url").toString(); + m_pOwner->openBookmarkURL(url); + emit openBookmark( url, state ); + } +} + +void KBookmarkBar::slotBookmarkSelected() +{ + slotBookmarkSelected(KAction::ToolBarActivation, Qt::NoButton); +} + +static const int const_sepId = -9999; // FIXME this is ugly, + // surely there is another + // way of doing this... + +static void removeTempSep(KBookmarkBarPrivate* p) +{ + if (p->m_sepToolBar) { + p->m_sepToolBar->removeItem(const_sepId); + p->m_sepToolBar = 0; // needed? + } +} + +static KAction* findPluggedAction(QPtrList<KAction> actions, KToolBar *tb, int id) +{ + QPtrListIterator<KAction> it( actions ); + for (; (*it); ++it ) + if ((*it)->isPlugged(tb, id)) + return (*it); + return 0; +} + +/** + * Handle a QDragMoveEvent event on a toolbar drop + * @return the address of the bookmark to be dropped after/before + * else a QString::null if event should be ignored + * @param pos the current QDragMoveEvent position + * @param the toolbar + * @param actions the list of actions plugged into the bar + * @param atFirst bool reference, when true the position before the + * returned action was dropped on + */ +static QString handleToolbarDragMoveEvent( + KBookmarkBarPrivate *p, KToolBar *tb, QPoint pos, QPtrList<KAction> actions, + bool &atFirst, KBookmarkManager *mgr +) { + Q_UNUSED( mgr ); + Q_ASSERT( actions.isEmpty() || (tb == dynamic_cast<KToolBar*>(actions.first()->container(0))) ); + p->m_sepToolBar = tb; + p->m_sepToolBar->removeItemDelayed(const_sepId); + + int index = 0; + KToolBarButton* b; + + b = dynamic_cast<KToolBarButton*>(tb->childAt(pos)); + KAction *a = 0; + QString address; + atFirst = false; + + if (b) + { + index = tb->itemIndex(b->id()); + QRect r = b->geometry(); + if (pos.x() < ((r.left() + r.right())/2)) + { + // if in first half of button then + // we jump to previous index + if ( index == 0 ) + atFirst = true; + else { + index--; + b = tb->getButton(tb->idAt(index)); + } + } + } + else if (actions.isEmpty()) + { + atFirst = true; + index = 0; + // we skip the action related stuff + // and do what it should have... + // FIXME - here we want to get the + // parent address of the bookmark + // bar itself and return that + "/0" + p->m_sepIndex = 0; + goto skipact; + } + else // (!b) + { + index = actions.count() - 1; + b = tb->getButton(tb->idAt(index)); + // if !b and not past last button, we didn't find button + if (pos.x() <= b->geometry().left()) + goto skipact; // TODO - rename + } + + if ( !b ) + return QString::null; // TODO Make it works for that case + + a = findPluggedAction(actions, tb, b->id()); + Q_ASSERT(a); + address = a->property("address").toString(); + p->m_sepIndex = index + (atFirst ? 0 : 1); + +#if 0 + { // ugly workaround to fix the goto scoping problems... + KBookmark bk = mgr->findByAddress( address ); + if (bk.isGroup()) // TODO - fix this ****!!!, manhatten distance should be used!!! + { + kdDebug() << "kbookmarkbar:: popping up " << bk.text() << endl; + KBookmarkActionMenu *menu = dynamic_cast<KBookmarkActionMenu*>(a); + Q_ASSERT(menu); + menu->popup(tb->mapToGlobal(b->geometry().center())); + } + } +#endif + +skipact: + tb->insertLineSeparator(p->m_sepIndex, const_sepId); + return address; +} + +// TODO - document!!!! +static KAction* handleToolbarMouseButton(QPoint pos, QPtrList<KAction> actions, + KBookmarkManager * /*mgr*/, QPoint & pt) +{ + KAction *act = actions.first(); + if (!act) { + return 0; + } + + KToolBar *tb = dynamic_cast<KToolBar*>(act->container(0)); + Q_ASSERT(tb); + + KToolBarButton *b; + b = dynamic_cast<KToolBarButton*>(tb->childAt(pos)); + if (!b) + return 0; + + KAction *a = 0; + a = findPluggedAction(actions, tb, b->id()); + Q_ASSERT(a); + pt = tb->mapToGlobal(pos); + + return a; +} + +// TODO *** drop improvements *** +// open submenus on drop interactions + +// TODO *** generic rmb improvements *** +// don't *ever* show the rmb on press, always relase, possible??? + +class KBookmarkBarRMBAssoc : public dPtrTemplate<KBookmarkBar, RMB> { }; +template<> QPtrDict<RMB>* dPtrTemplate<KBookmarkBar, RMB>::d_ptr = 0; + +static RMB* rmbSelf(KBookmarkBar *m) { return KBookmarkBarRMBAssoc::d(m); } + +void RMB::begin_rmb_action(KBookmarkBar *self) +{ + RMB *s = rmbSelf(self); + s->recv = self; + s->m_parentAddress = self->parentAddress(); + s->s_highlightedAddress = self->dptr()->m_highlightedAddress; // rename in RMB + s->m_pManager = self->m_pManager; + s->m_pOwner = self->m_pOwner; + s->m_parentMenu = 0; +} + +void KBookmarkBar::slotRMBActionEditAt( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); } + +void KBookmarkBar::slotRMBActionProperties( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); } + +void KBookmarkBar::slotRMBActionInsert( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); } + +void KBookmarkBar::slotRMBActionRemove( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); } + +void KBookmarkBar::slotRMBActionCopyLocation( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); } + +bool KBookmarkBar::eventFilter( QObject *o, QEvent *e ) +{ + if (dptr()->m_readOnly || dptr()->m_filteredMgr) // note, we assume m_pManager in various places, + // this shouldn't really be the case + return false; // todo: make this limit the actions + + if ( (e->type() == QEvent::MouseButtonRelease) || (e->type() == QEvent::MouseButtonPress) ) // FIXME, which one? + { + QMouseEvent *mev = (QMouseEvent*)e; + + QPoint pt; + KAction *_a; + + // FIXME, see how this holds up on an empty toolbar + _a = handleToolbarMouseButton( mev->pos(), dptr()->m_actions, m_pManager, pt ); + if (_a && mev->button() == Qt::RightButton) + { + dptr()->m_highlightedAddress = _a->property("address").toString(); + KBookmark bookmark = m_pManager->findByAddress( dptr()->m_highlightedAddress ); + RMB::begin_rmb_action(this); + KPopupMenu *pm = new KPopupMenu; + rmbSelf(this)->fillContextMenu( pm, dptr()->m_highlightedAddress, 0 ); + emit aboutToShowContextMenu( rmbSelf(this)->atAddress( dptr()->m_highlightedAddress ), pm ); + rmbSelf(this)->fillContextMenu2( pm, dptr()->m_highlightedAddress, 0 ); + pm->popup( pt ); + mev->accept(); + } + + return !!_a; // ignore the event if we didn't find the button + } + else if ( e->type() == QEvent::DragLeave ) + { + removeTempSep(dptr()); + dptr()->m_dropAddress = QString::null; + } + else if ( e->type() == QEvent::Drop ) + { + removeTempSep(dptr()); + QDropEvent *dev = (QDropEvent*)e; + if ( !KBookmarkDrag::canDecode( dev ) ) + return false; + QValueList<KBookmark> list = KBookmarkDrag::decode( dev ); + if (list.count() > 1) + kdWarning(7043) << "Sorry, currently you can only drop one address " + "onto the bookmark bar!" << endl; + KBookmark toInsert = list.first(); + KBookmark bookmark = m_pManager->findByAddress( dptr()->m_dropAddress ); + Q_ASSERT(!bookmark.isNull()); + kdDebug(7043) << "inserting " + << QString(dptr()->m_atFirst ? "before" : "after") + << " dptr()->m_dropAddress == " << dptr()->m_dropAddress << endl; + KBookmarkGroup parentBookmark = bookmark.parentGroup(); + Q_ASSERT(!parentBookmark.isNull()); + KBookmark newBookmark = parentBookmark.addBookmark( + m_pManager, toInsert.fullText(), + toInsert.url() ); + parentBookmark.moveItem( newBookmark, dptr()->m_atFirst ? KBookmark() : bookmark ); + m_pManager->emitChanged( parentBookmark ); + return true; + } + else if ( e->type() == QEvent::DragMove ) + { + QDragMoveEvent *dme = (QDragMoveEvent*)e; + if (!KBookmarkDrag::canDecode( dme )) + return false; + bool _atFirst; + QString dropAddress; + KToolBar *tb = (KToolBar*)o; + dropAddress = handleToolbarDragMoveEvent(dptr(), tb, dme->pos(), dptr()->m_actions, _atFirst, m_pManager); + if (!dropAddress.isNull()) + { + dptr()->m_dropAddress = dropAddress; + dptr()->m_atFirst = _atFirst; + dme->accept(); + } + } + return false; +} + +static bool showInToolbar( const KBookmark &bk ) { + return (bk.internalElement().attributes().namedItem("showintoolbar").toAttr().value() == "yes"); +} + +void ToolbarFilter::visit( const KBookmark &bk ) { + //kdDebug() << "visit(" << bk.text() << ")" << endl; + if ( m_visible || showInToolbar(bk) ) + KXBELBookmarkImporterImpl::visit(bk); +} + +void ToolbarFilter::visitEnter( const KBookmarkGroup &grp ) { + //kdDebug() << "visitEnter(" << grp.text() << ")" << endl; + if ( !m_visible && showInToolbar(grp) ) + { + m_visibleStart = grp; + m_visible = true; + } + if ( m_visible ) + KXBELBookmarkImporterImpl::visitEnter(grp); +} + +void ToolbarFilter::visitLeave( const KBookmarkGroup &grp ) { + //kdDebug() << "visitLeave()" << endl; + if ( m_visible ) + KXBELBookmarkImporterImpl::visitLeave(grp); + if ( m_visible && grp.address() == m_visibleStart.address() ) + m_visible = false; +} + +#include "kbookmarkbar.moc" diff --git a/kio/bookmarks/kbookmarkbar.h b/kio/bookmarks/kbookmarkbar.h new file mode 100644 index 000000000..162d045bb --- /dev/null +++ b/kio/bookmarks/kbookmarkbar.h @@ -0,0 +1,130 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 1999 Kurt Granroth <granroth@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KBOOKMARKBAR_H +#define KBOOKMARKBAR_H + +#include <qobject.h> +#include <qguardedptr.h> +#include <qptrlist.h> +#include <kbookmark.h> +#include <kaction.h> + +class KToolBar; +class KBookmarkMenu; +class KBookmarkOwner; +class KActionCollection; +class KAction; +class QPopupMenu; + +/** + * This class provides a bookmark toolbar. Using this class is nearly + * identical to using KBookmarkMenu so follow the directions + * there. + */ +class KIO_EXPORT KBookmarkBar : public QObject +{ + Q_OBJECT + friend class RMB; +public: + /** + * Fills a bookmark toolbar + * + * @param manager the bookmark manager + * @param owner implementation of the KBookmarkOwner interface (callbacks) + * @param toolBar toolbar to fill + * + * The KActionCollection pointer argument is now obsolete. + * + * @param parent the parent widget for the bookmark toolbar + * @param name the internal name for the bookmark toolbar + */ + KBookmarkBar( KBookmarkManager* manager, + KBookmarkOwner *owner, KToolBar *toolBar, + KActionCollection *, + QObject *parent = 0L, const char *name = 0L); + + virtual ~KBookmarkBar(); + + /** + * @since 3.2 + */ + bool isReadOnly() const; + + /** + * @since 3.2 + */ + void setReadOnly(bool); + + /** + * @since 3.2 + */ + QString parentAddress(); + +signals: + /** + * @since 3.2 + */ + void aboutToShowContextMenu( const KBookmark &, QPopupMenu * ); + /** + * @since 3.4 + */ + void openBookmark( const QString& url, Qt::ButtonState state ); + +public slots: + void clear(); + + void slotBookmarksChanged( const QString & ); + void slotBookmarkSelected(); + + /** + * @since 3.4 + */ + void slotBookmarkSelected( KAction::ActivationReason reason, Qt::ButtonState state ); + + /// @since 3.2 + void slotRMBActionRemove( int ); + /// @since 3.2 + void slotRMBActionInsert( int ); + /// @since 3.2 + void slotRMBActionCopyLocation( int ); + /// @since 3.2 + void slotRMBActionEditAt( int ); + /// @since 3.2 + void slotRMBActionProperties( int ); + +protected: + void fillBookmarkBar( KBookmarkGroup & parent ); + virtual bool eventFilter( QObject *o, QEvent *e ); + +private: + KBookmarkGroup getToolbar(); + + KBookmarkOwner *m_pOwner; + QGuardedPtr<KToolBar> m_toolBar; + KActionCollection *m_actionCollection; + KBookmarkManager *m_pManager; + QPtrList<KBookmarkMenu> m_lstSubMenus; + +private: + class KBookmarkBarPrivate* dptr() const; +}; + +#endif // KBOOKMARKBAR_H diff --git a/kio/bookmarks/kbookmarkdombuilder.cc b/kio/bookmarks/kbookmarkdombuilder.cc new file mode 100644 index 000000000..7b6bad4e6 --- /dev/null +++ b/kio/bookmarks/kbookmarkdombuilder.cc @@ -0,0 +1,81 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure <faure@kde.org> + Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kbookmarkmanager.h> +#include <kdebug.h> + +#include "kbookmarkdombuilder.h" + +KBookmarkDomBuilder::KBookmarkDomBuilder( + const KBookmarkGroup &bkGroup, KBookmarkManager *manager +) { + m_manager = manager; + m_stack.push(bkGroup); +} + +KBookmarkDomBuilder::~KBookmarkDomBuilder() { + m_list.clear(); + m_stack.clear(); +} + +void KBookmarkDomBuilder::connectImporter(const QObject *importer) { + connect(importer, SIGNAL( newBookmark(const QString &, const QCString &, const QString &) ), + SLOT( newBookmark(const QString &, const QCString &, const QString &) )); + connect(importer, SIGNAL( newFolder(const QString &, bool, const QString &) ), + SLOT( newFolder(const QString &, bool, const QString &) )); + connect(importer, SIGNAL( newSeparator() ), + SLOT( newSeparator() ) ); + connect(importer, SIGNAL( endFolder() ), + SLOT( endFolder() ) ); +} + +void KBookmarkDomBuilder::newBookmark( + const QString &text, const QCString &url, const QString &additionalInfo +) { + KBookmark bk = m_stack.top().addBookmark( + m_manager, text, + KURL( QString::fromUtf8(url), 106 /*utf8*/ ), + QString::null, false); + // store additional info + bk.internalElement().setAttribute("netscapeinfo", additionalInfo); +} + +void KBookmarkDomBuilder::newFolder( + const QString & text, bool open, const QString & additionalInfo +) { + // we use a qvaluelist so that we keep pointers to valid objects in the stack + KBookmarkGroup gp = m_stack.top().createNewFolder(m_manager, text, false); + m_list.append(gp); + m_stack.push(m_list.last()); + // store additional info + QDomElement element = m_list.last().internalElement(); + element.setAttribute("netscapeinfo", additionalInfo); + element.setAttribute("folded", (open?"no":"yes")); +} + +void KBookmarkDomBuilder::newSeparator() { + m_stack.top().createNewSeparator(); +} + +void KBookmarkDomBuilder::endFolder() { + m_stack.pop(); +} + +#include "kbookmarkdombuilder.moc" diff --git a/kio/bookmarks/kbookmarkdombuilder.h b/kio/bookmarks/kbookmarkdombuilder.h new file mode 100644 index 000000000..f570525f6 --- /dev/null +++ b/kio/bookmarks/kbookmarkdombuilder.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkdombuilder_h +#define __kbookmarkdombuilder_h + +#include <qvaluestack.h> +#include <qobject.h> +#include <kbookmark.h> + +/** + * @since 3.2 + */ +class KIO_EXPORT KBookmarkDomBuilder : public QObject { + Q_OBJECT +public: + KBookmarkDomBuilder(const KBookmarkGroup &group, KBookmarkManager *); + virtual ~KBookmarkDomBuilder(); + void connectImporter(const QObject *); +protected slots: + void newBookmark(const QString &text, const QCString &url, const QString &additionalInfo); + void newFolder(const QString &text, bool open, const QString &additionalInfo); + void newSeparator(); + void endFolder(); +private: + QValueStack<KBookmarkGroup> m_stack; + QValueList<KBookmarkGroup> m_list; + KBookmarkManager *m_manager; + class KBookmarkDomBuilderPrivate *p; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkdrag.cc b/kio/bookmarks/kbookmarkdrag.cc new file mode 100644 index 000000000..3e1db9c15 --- /dev/null +++ b/kio/bookmarks/kbookmarkdrag.cc @@ -0,0 +1,169 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkdrag.h" +#include <kurldrag.h> +#include <kdebug.h> + +KBookmarkDrag * KBookmarkDrag::newDrag( const QValueList<KBookmark> & bookmarks, QWidget * dragSource, const char * name ) +{ + KURL::List urls; + + for ( QValueListConstIterator<KBookmark> it = bookmarks.begin(); it != bookmarks.end(); ++it ) { + urls.append( (*it).url() ); + } + + // See KURLDrag::newDrag + QStrList uris; + KURL::List::ConstIterator uit = urls.begin(); + KURL::List::ConstIterator uEnd = urls.end(); + // Get each URL encoded in utf8 - and since we get it in escaped + // form on top of that, .latin1() is fine. + for ( ; uit != uEnd ; ++uit ) + uris.append( KURLDrag::urlToString(*uit).latin1() ); + + return new KBookmarkDrag( bookmarks, uris, dragSource, name ); +} + +KBookmarkDrag * KBookmarkDrag::newDrag( const KBookmark & bookmark, QWidget * dragSource, const char * name ) +{ + QValueList<KBookmark> bookmarks; + bookmarks.append( KBookmark(bookmark) ); + return newDrag(bookmarks, dragSource, name); +} + +KBookmarkDrag::KBookmarkDrag( const QValueList<KBookmark> & bookmarks, const QStrList & urls, + QWidget * dragSource, const char * name ) + : QUriDrag( urls, dragSource, name ), m_bookmarks( bookmarks ), m_doc("xbel") +{ + // We need to create the XML for this drag right now and not + // in encodedData because when cutting a folder, the children + // wouldn't be part of the bookmarks anymore, when encodedData + // is requested. + QDomElement elem = m_doc.createElement("xbel"); + m_doc.appendChild( elem ); + for ( QValueListConstIterator<KBookmark> it = bookmarks.begin(); it != bookmarks.end(); ++it ) { + elem.appendChild( (*it).internalElement().cloneNode( true /* deep */ ) ); + } + //kdDebug(7043) << "KBookmarkDrag::KBookmarkDrag " << m_doc.toString() << endl; +} + +const char* KBookmarkDrag::format( int i ) const +{ + if ( i == 0 ) + return "application/x-xbel"; + else if ( i == 1 ) + return "text/uri-list"; + else if ( i == 2 ) + return "text/plain"; + else return 0; +} + +QByteArray KBookmarkDrag::encodedData( const char* mime ) const +{ + QByteArray a; + QCString mimetype( mime ); + if ( mimetype == "text/uri-list" ) + return QUriDrag::encodedData( mime ); + else if ( mimetype == "application/x-xbel" ) + { + a = m_doc.toCString(); + //kdDebug(7043) << "KBookmarkDrag::encodedData " << m_doc.toCString() << endl; + } + else if ( mimetype == "text/plain" ) + { + KURL::List m_lstDragURLs; + if ( KURLDrag::decode( this, m_lstDragURLs ) ) + { + QStringList uris; + KURL::List::ConstIterator uit = m_lstDragURLs.begin(); + KURL::List::ConstIterator uEnd = m_lstDragURLs.end(); + for ( ; uit != uEnd ; ++uit ) + uris.append( (*uit).prettyURL() ); + + QCString s = uris.join( "\n" ).local8Bit(); + a.resize( s.length() + 1 ); // trailing zero + memcpy( a.data(), s.data(), s.length() + 1 ); + } + } + return a; +} + +bool KBookmarkDrag::canDecode( const QMimeSource * e ) +{ + return e->provides("text/uri-list") || e->provides("application/x-xbel") || + e->provides("text/plain"); +} + +QValueList<KBookmark> KBookmarkDrag::decode( const QMimeSource * e ) +{ + QValueList<KBookmark> bookmarks; + if ( e->provides("application/x-xbel") ) + { + QByteArray s( e->encodedData("application/x-xbel") ); + //kdDebug(7043) << "KBookmarkDrag::decode s=" << QCString(s) << endl; + QDomDocument doc; + doc.setContent( s ); + QDomElement elem = doc.documentElement(); + QDomNodeList children = elem.childNodes(); + for ( uint childno = 0; childno < children.count(); childno++) + { + bookmarks.append( KBookmark( children.item(childno).cloneNode(true).toElement() )); + } + return bookmarks; + } + if ( e->provides("text/uri-list") ) + { + KURL::List m_lstDragURLs; + //kdDebug(7043) << "KBookmarkDrag::decode uri-list" << endl; + if ( KURLDrag::decode( e, m_lstDragURLs ) ) + { + KURL::List::ConstIterator uit = m_lstDragURLs.begin(); + KURL::List::ConstIterator uEnd = m_lstDragURLs.end(); + for ( ; uit != uEnd ; ++uit ) + { + //kdDebug(7043) << "KBookmarkDrag::decode url=" << (*uit).url() << endl; + bookmarks.append( KBookmark::standaloneBookmark( + (*uit).prettyURL(), (*uit) )); + } + return bookmarks; + } + } + if( e->provides("text/plain") ) + { + //kdDebug(7043) << "KBookmarkDrag::decode text/plain" << endl; + QString s; + if(QTextDrag::decode( e, s )) + { + + QStringList listDragURLs = QStringList::split(QChar('\n'), s); + QStringList::ConstIterator it = listDragURLs.begin(); + QStringList::ConstIterator end = listDragURLs.end(); + for( ; it!=end; ++it) + { + //kdDebug(7043)<<"KBookmarkDrag::decode string"<<(*it)<<endl; + bookmarks.append( KBookmark::standaloneBookmark( KURL(*it).prettyURL(), KURL(*it))); + } + return bookmarks; + } + } + bookmarks.append( KBookmark() ); + return bookmarks; +} diff --git a/kio/bookmarks/kbookmarkdrag.h b/kio/bookmarks/kbookmarkdrag.h new file mode 100644 index 000000000..fdaaf23f3 --- /dev/null +++ b/kio/bookmarks/kbookmarkdrag.h @@ -0,0 +1,57 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kebdrag_h +#define __kebdrag_h + +#include <qdragobject.h> +#include <kbookmark.h> + +// Clipboard/dnd data : URLs + XML for bookmarks +class KIO_EXPORT KBookmarkDrag : public QUriDrag +{ +public: + static KBookmarkDrag * newDrag( const QValueList<KBookmark> & bookmarks, + QWidget * dragSource = 0, + const char * name = 0 ); + static KBookmarkDrag * newDrag( const KBookmark & bookmark, + QWidget * dragSource = 0, + const char * name = 0 ); +protected: + KBookmarkDrag( const QValueList<KBookmark> & bookmarks, + const QStrList & urls, + QWidget * dragSource, + const char * name ); +public: + virtual ~KBookmarkDrag() {} + + virtual const char* format( int i ) const; + virtual QByteArray encodedData( const char* mime ) const; + + static bool canDecode( const QMimeSource * e ); + static QValueList<KBookmark> decode( const QMimeSource * e ); + +protected: + QValueList<KBookmark> m_bookmarks; + QDomDocument m_doc; + class KBookmarkDragPrivate; + KBookmarkDragPrivate * d; +}; +#endif diff --git a/kio/bookmarks/kbookmarkexporter.cc b/kio/bookmarks/kbookmarkexporter.cc new file mode 100644 index 000000000..8ed394ad1 --- /dev/null +++ b/kio/bookmarks/kbookmarkexporter.cc @@ -0,0 +1,32 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include <stdio.h> + +#include <qfile.h> +#include <qtextcodec.h> +#include <qstylesheet.h> + +#include <kdebug.h> +#include <klocale.h> + +#include "kbookmarkmanager.h" +#include "kbookmarkexporter.h" + +// todo - put stuff in here :) diff --git a/kio/bookmarks/kbookmarkexporter.h b/kio/bookmarks/kbookmarkexporter.h new file mode 100644 index 000000000..19978b3dd --- /dev/null +++ b/kio/bookmarks/kbookmarkexporter.h @@ -0,0 +1,50 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 1996-1998 Martin R. Jones <mjones@kde.org> + Copyright (C) 2000 David Faure <faure@kde.org> + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkexporter_h +#define __kbookmarkexporter_h + +#include <qtextstream.h> +#include <kbookmark.h> + +/** + * @since 3.2 + */ +class KIO_EXPORT KBookmarkExporterBase +{ +public: + KBookmarkExporterBase(KBookmarkManager* mgr, const QString & fileName) + : m_fileName(fileName), m_pManager(mgr) + { ; } + virtual ~KBookmarkExporterBase() {} + virtual void write(KBookmarkGroup) = 0; +protected: + QString m_fileName; + KBookmarkManager* m_pManager; +private: + class KBookmarkExporterBasePrivate *d; +}; + +// for SC +#include "kbookmarkimporter_ns.h" + +#endif diff --git a/kio/bookmarks/kbookmarkimporter.cc b/kio/bookmarks/kbookmarkimporter.cc new file mode 100644 index 000000000..b646b0626 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter.cc @@ -0,0 +1,101 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <kcharsets.h> +#include <qtextcodec.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> +#include <assert.h> + +#include "kbookmarkmanager.h" + +#include "kbookmarkimporter_ns.h" +#include "kbookmarkimporter_opera.h" +#include "kbookmarkimporter_ie.h" + +#include "kbookmarkimporter.h" + +void KXBELBookmarkImporterImpl::parse() +{ + //kdDebug() << "KXBELBookmarkImporterImpl::parse()" << endl; + KBookmarkManager *manager = KBookmarkManager::managerForFile(m_fileName); + KBookmarkGroup root = manager->root(); + traverse(root); + // FIXME delete it! + // delete manager; +} + +void KXBELBookmarkImporterImpl::visit(const KBookmark &bk) +{ + //kdDebug() << "KXBELBookmarkImporterImpl::visit" << endl; + if (bk.isSeparator()) + emit newSeparator(); + else + emit newBookmark(bk.fullText(), bk.url().url().utf8(), ""); +} + +void KXBELBookmarkImporterImpl::visitEnter(const KBookmarkGroup &grp) +{ + //kdDebug() << "KXBELBookmarkImporterImpl::visitEnter" << endl; + emit newFolder(grp.fullText(), false, ""); +} + +void KXBELBookmarkImporterImpl::visitLeave(const KBookmarkGroup &) +{ + //kdDebug() << "KXBELBookmarkImporterImpl::visitLeave" << endl; + emit endFolder(); +} + +void KBookmarkImporterBase::setupSignalForwards(QObject *src, QObject *dst) +{ + connect(src, SIGNAL( newBookmark( const QString &, const QCString &, const QString & ) ), + dst, SIGNAL( newBookmark( const QString &, const QCString &, const QString & ) )); + connect(src, SIGNAL( newFolder( const QString &, bool, const QString & ) ), + dst, SIGNAL( newFolder( const QString &, bool, const QString & ) )); + connect(src, SIGNAL( newSeparator() ), + dst, SIGNAL( newSeparator() ) ); + connect(src, SIGNAL( endFolder() ), + dst, SIGNAL( endFolder() ) ); +} + +KBookmarkImporterBase* KBookmarkImporterBase::factory( const QString &type ) +{ + if (type == "netscape") + return new KNSBookmarkImporterImpl; + else if (type == "mozilla") + return new KMozillaBookmarkImporterImpl; + else if (type == "xbel") + return new KXBELBookmarkImporterImpl; + else if (type == "ie") + return new KIEBookmarkImporterImpl; + else if (type == "opera") + return new KOperaBookmarkImporterImpl; + else + return 0; +} + +#include <kbookmarkimporter.moc> diff --git a/kio/bookmarks/kbookmarkimporter.h b/kio/bookmarks/kbookmarkimporter.h new file mode 100644 index 000000000..f8f53ffa2 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter.h @@ -0,0 +1,106 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_h +#define __kbookmarkimporter_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> + +#include "kbookmark.h" + +/** + * A class for importing NS bookmarks + * KEditBookmarks uses it to insert bookmarks into its DOM tree, + * and KActionMenu uses it to create actions directly. + * @since 3.2 + */ +class KIO_EXPORT KBookmarkImporterBase : public QObject +{ + Q_OBJECT +public: + KBookmarkImporterBase() {} + virtual ~KBookmarkImporterBase() {} + + void setFilename(const QString &filename) { m_fileName = filename; } + + virtual void parse() = 0; + virtual QString findDefaultLocation(bool forSaving = false) const = 0; + + // TODO - make this static? + void setupSignalForwards(QObject *src, QObject *dst); + static KBookmarkImporterBase *factory(const QString &type); + +signals: + /** + * Notify about a new bookmark + * Use "html" for the icon + */ + void newBookmark(const QString & text, const QCString & url, const QString & additionalInfo); + + /** + * Notify about a new folder + * Use "bookmark_folder" for the icon + */ + void newFolder(const QString & text, bool open, const QString & additionalInfo); + + /** + * Notify about a new separator + */ + void newSeparator(); + + /** + * Tell the outside world that we're going down + * one menu + */ + void endFolder(); + +protected: + QString m_fileName; + +private: + class KBookmarkImporterBasePrivate *d; +}; + +/** + * A class for importing XBEL files + */ +class KIO_EXPORT KXBELBookmarkImporterImpl : public KBookmarkImporterBase, protected KBookmarkGroupTraverser +{ + Q_OBJECT +public: + KXBELBookmarkImporterImpl() {} + virtual void parse(); + virtual QString findDefaultLocation(bool = false) const { return QString::null; } +protected: + virtual void visit(const KBookmark &); + virtual void visitEnter(const KBookmarkGroup &); + virtual void visitLeave(const KBookmarkGroup &); +private: + class KXBELBookmarkImporterImplPrivate *d; +}; + +// for SC +#include "kbookmarkimporter_ns.h" +#include "kbookmarkimporter_kde1.h" + +#endif diff --git a/kio/bookmarks/kbookmarkimporter_crash.cc b/kio/bookmarks/kbookmarkimporter_crash.cc new file mode 100644 index 000000000..b585df4c7 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_crash.cc @@ -0,0 +1,215 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkimporter_crash.h" + +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <kapplication.h> +#include <kstandarddirs.h> +#include <qfile.h> +#include <qdir.h> +#include <qstring.h> +#include <qtextcodec.h> +#include <dcopclient.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> + +typedef QMap<QString, QString> ViewMap; + +// KDE 4.0: remove this BC keeping stub +void KCrashBookmarkImporter::parseCrashLog( QString /*filename*/, bool /*del*/ ) +{ + ; +} + +ViewMap KCrashBookmarkImporterImpl::parseCrashLog_noemit( const QString & filename, bool del ) +{ + static const int g_lineLimit = 16*1024; + + QFile f( filename ); + ViewMap views; + + if ( !f.open( IO_ReadOnly ) ) + return views; + + QCString s( g_lineLimit ); + + QTextCodec * codec = QTextCodec::codecForName( "UTF-8" ); + Q_ASSERT( codec ); + if ( !codec ) + return views; + + while ( f.readLine( s.data(), g_lineLimit ) >=0 ) + { + if ( s[s.length()-1] != '\n' ) + { + kdWarning() << "Crash bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl; + continue; + } + QString t = codec->toUnicode( s.stripWhiteSpace() ); + QRegExp rx( "(.*)\\((.*)\\):(.*)$" ); + rx.setMinimal( true ); + if ( !rx.exactMatch( t ) ) + continue; + if ( rx.cap(1) == "opened" ) + views[rx.cap(2)] = rx.cap(3); + else if ( rx.cap(1) == "close" ) + views.remove( rx.cap(2) ); + } + + f.close(); + + if ( del ) + f.remove(); + + return views; +} + +QStringList KCrashBookmarkImporter::getCrashLogs() +{ + return KCrashBookmarkImporterImpl::getCrashLogs(); +} + +QStringList KCrashBookmarkImporterImpl::getCrashLogs() +{ + QMap<QString, bool> activeLogs; + + DCOPClient* dcop = kapp->dcopClient(); + + QCStringList apps = dcop->registeredApplications(); + for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it ) + { + QCString &clientId = *it; + + if ( qstrncmp(clientId, "konqueror", 9) != 0 ) + continue; + + QByteArray data, replyData; + QCString replyType; + QDataStream arg( data, IO_WriteOnly ); + + if ( !dcop->call( clientId.data(), "KonquerorIface", + "crashLogFile()", data, replyType, replyData) ) + { + kdWarning() << "can't find dcop function KonquerorIface::crashLogFile()" << endl; + continue; + } + + if ( replyType != "QString" ) + continue; + + QDataStream reply( replyData, IO_ReadOnly ); + QString ret; + reply >> ret; + activeLogs[ret] = true; + } + + QDir d( KCrashBookmarkImporterImpl().findDefaultLocation() ); + d.setSorting( QDir::Time ); + d.setFilter( QDir::Files ); + d.setNameFilter( "konqueror-crash-*.log" ); + + const QFileInfoList *list = d.entryInfoList(); + QFileInfoListIterator it( *list ); + + QFileInfo *fi; + QStringList crashFiles; + + int count = 0; + for ( ; (( fi = it.current() ) != 0) && (count < 20); ++it, ++count ) + { + bool stillAlive = activeLogs.contains( fi->absFilePath() ); + if ( !stillAlive ) + crashFiles << fi->absFilePath(); + } + // Delete remaining ones + for ( ; ( fi = it.current() ) != 0; ++it ) + { + QFile::remove( fi->absFilePath() ); + } + + return crashFiles; +} + +void KCrashBookmarkImporterImpl::parse() +{ + QDict<bool> signatureMap; + QStringList crashFiles = KCrashBookmarkImporterImpl::getCrashLogs(); + int count = 1; + for ( QStringList::Iterator it = crashFiles.begin(); it != crashFiles.end(); ++it ) + { + ViewMap views; + views = parseCrashLog_noemit( *it, m_shouldDelete ); + QString signature; + for ( ViewMap::Iterator vit = views.begin(); vit != views.end(); ++vit ) + signature += "|"+vit.data(); + if (signatureMap[signature]) + { + // Duplicate... throw away and skip + QFile::remove(*it); + continue; + } + + signatureMap.insert(signature, (bool *) true); // hack + + int outerFolder = ( crashFiles.count() > 1 ) && (views.count() > 0); + if ( outerFolder ) + emit newFolder( QString("Konqueror Window %1").arg(count++), false, "" ); + for ( ViewMap::Iterator vit = views.begin(); vit != views.end(); ++vit ) + emit newBookmark( vit.data(), vit.data().latin1(), QString("") ); + if ( outerFolder ) + emit endFolder(); + } +} + +QString KCrashBookmarkImporter::crashBookmarksDir() +{ + static KCrashBookmarkImporterImpl *p = 0; + if (!p) + p = new KCrashBookmarkImporterImpl; + return p->findDefaultLocation(); +} + +void KCrashBookmarkImporterImpl::setShouldDelete( bool shouldDelete ) +{ + m_shouldDelete = shouldDelete; +} + +void KCrashBookmarkImporter::parseCrashBookmarks( bool del ) +{ + KCrashBookmarkImporterImpl importer; + importer.setFilename( m_fileName ); + importer.setShouldDelete( del ); + importer.setupSignalForwards( &importer, this ); + importer.parse(); +} + +QString KCrashBookmarkImporterImpl::findDefaultLocation( bool ) const +{ + return locateLocal( "tmp", "" ); +} + +#include "kbookmarkimporter_crash.moc" diff --git a/kio/bookmarks/kbookmarkimporter_crash.h b/kio/bookmarks/kbookmarkimporter_crash.h new file mode 100644 index 000000000..701387b4e --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_crash.h @@ -0,0 +1,74 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_crash_h +#define __kbookmarkimporter_crash_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <qmap.h> +#include <ksimpleconfig.h> +#include <kdemacros.h> + +#include "kbookmarkimporter.h" + +/** + * A class for importing all crash sessions as bookmarks + * @deprecated + */ +class KIO_EXPORT_DEPRECATED KCrashBookmarkImporter : public QObject +{ + Q_OBJECT +public: + KCrashBookmarkImporter( const QString & fileName ) : m_fileName(fileName) {} + ~KCrashBookmarkImporter() {} + void parseCrashBookmarks( bool del = true ); + static QString crashBookmarksDir( ); + static QStringList getCrashLogs(); // EMPTY! +signals: + void newBookmark( const QString & text, const QCString & url, const QString & additionalInfo ); + void newFolder( const QString & text, bool open, const QString & additionalInfo ); + void newSeparator(); + void endFolder(); +protected: + QString m_fileName; + void parseCrashLog( QString filename, bool del ); // EMPTY! +}; + +/** + * A class for importing all crash sessions as bookmarks + * @since 3.2 + */ +class KIO_EXPORT KCrashBookmarkImporterImpl : public KBookmarkImporterBase +{ +public: + KCrashBookmarkImporterImpl() : m_shouldDelete(false) { } + void setShouldDelete(bool); + virtual void parse(); + virtual QString findDefaultLocation(bool forSaving = false) const; + static QStringList getCrashLogs(); +private: + bool m_shouldDelete; + QMap<QString, QString> parseCrashLog_noemit( const QString & filename, bool del ); + class KCrashBookmarkImporterImplPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkimporter_ie.cc b/kio/bookmarks/kbookmarkimporter_ie.cc new file mode 100644 index 000000000..a2e863518 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_ie.cc @@ -0,0 +1,185 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <qtextcodec.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> + +#include "kbookmarkimporter.h" +#include "kbookmarkimporter_ie.h" + +/* antlarr: KDE 4: Make them const QString & */ +void KIEBookmarkImporter::parseIEBookmarks_url_file( QString filename, QString name ) { + static const int g_lineLimit = 16*1024; + + QFile f(filename); + + if(f.open(IO_ReadOnly)) { + + QCString s(g_lineLimit); + + while(f.readLine(s.data(), g_lineLimit)>=0) { + if ( s[s.length()-1] != '\n' ) // Gosh, this line is longer than g_lineLimit. Skipping. + { + kdWarning() << "IE bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl; + continue; + } + QCString t = s.stripWhiteSpace(); + QRegExp rx( "URL=(.*)" ); + if (rx.exactMatch(t)) { + emit newBookmark( name, rx.cap(1).latin1(), QString("") ); + } + } + + f.close(); + } +} + +/* antlarr: KDE 4: Make them const QString & */ +void KIEBookmarkImporter::parseIEBookmarks_dir( QString dirname, QString foldername ) +{ + + QDir dir(dirname); + dir.setFilter( QDir::Files | QDir::Dirs ); + dir.setSorting( QDir::Name | QDir::DirsFirst ); + dir.setNameFilter("*.url"); // AK - possibly add ";index.ini" ? + dir.setMatchAllDirs(true); + + const QFileInfoList *list = dir.entryInfoList(); + if (!list) return; + + if (dirname != m_fileName) + emit newFolder( foldername, false, "" ); + + QFileInfoListIterator it( *list ); + QFileInfo *fi; + + while ( (fi = it.current()) != 0 ) { + ++it; + + if (fi->fileName() == "." || fi->fileName() == "..") continue; + + if (fi->isDir()) { + parseIEBookmarks_dir(fi->absFilePath(), fi->fileName()); + + } else if (fi->isFile()) { + if (fi->fileName().endsWith(".url")) { + QString name = fi->fileName(); + name.truncate(name.length() - 4); // .url + parseIEBookmarks_url_file(fi->absFilePath(), name); + } + // AK - add index.ini + } + } + + if (dirname != m_fileName) + emit endFolder(); +} + + +void KIEBookmarkImporter::parseIEBookmarks( ) +{ + parseIEBookmarks_dir( m_fileName ); +} + +QString KIEBookmarkImporter::IEBookmarksDir() +{ + static KIEBookmarkImporterImpl* p = 0; + if (!p) + p = new KIEBookmarkImporterImpl; + return p->findDefaultLocation(); +} + +void KIEBookmarkImporterImpl::parse() { + KIEBookmarkImporter importer(m_fileName); + setupSignalForwards(&importer, this); + importer.parseIEBookmarks(); +} + +QString KIEBookmarkImporterImpl::findDefaultLocation(bool) const +{ + // notify user that they must give a new dir such + // as "Favourites" as otherwise it'll just place + // lots of .url files in the given dir and gui + // stuff in the exporter is ugly so that exclues + // the possibility of just writing to Favourites + // and checking if overwriting... + return KFileDialog::getExistingDirectory(); +} + +///////////////////////////////////////////////// + +class IEExporter : private KBookmarkGroupTraverser { +public: + IEExporter( const QString & ); + void write( const KBookmarkGroup &grp ) { traverse(grp); }; +private: + virtual void visit( const KBookmark & ); + virtual void visitEnter( const KBookmarkGroup & ); + virtual void visitLeave( const KBookmarkGroup & ); +private: + QDir m_currentDir; +}; + +static QString ieStyleQuote( const QString &str ) { + QString s(str); + s.replace(QRegExp("[/\\:*?\"<>|]"), "_"); + return s; +} + +IEExporter::IEExporter( const QString & dname ) { + m_currentDir.setPath( dname ); +} + +void IEExporter::visit( const KBookmark &bk ) { + QString fname = m_currentDir.path() + "/" + ieStyleQuote( bk.fullText() ) + ".url"; + // kdDebug() << "visit(" << bk.text() << "), fname == " << fname << endl; + QFile file( fname ); + file.open( IO_WriteOnly ); + QTextStream ts( &file ); + ts << "[InternetShortcut]\r\n"; + ts << "URL=" << bk.url().url().utf8() << "\r\n"; +} + +void IEExporter::visitEnter( const KBookmarkGroup &grp ) { + QString dname = m_currentDir.path() + "/" + ieStyleQuote( grp.fullText() ); + // kdDebug() << "visitEnter(" << grp.text() << "), dname == " << dname << endl; + m_currentDir.mkdir( dname ); + m_currentDir.cd( dname ); +} + +void IEExporter::visitLeave( const KBookmarkGroup & ) { + // kdDebug() << "visitLeave()" << endl; + m_currentDir.cdUp(); +} + +void KIEBookmarkExporterImpl::write(KBookmarkGroup parent) { + IEExporter exporter( m_fileName ); + exporter.write( parent ); +} + +#include "kbookmarkimporter_ie.moc" diff --git a/kio/bookmarks/kbookmarkimporter_ie.h b/kio/bookmarks/kbookmarkimporter_ie.h new file mode 100644 index 000000000..86f41a4f6 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_ie.h @@ -0,0 +1,90 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_ie_h +#define __kbookmarkimporter_ie_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> +#include <kdemacros.h> + +#include <kbookmarkimporter.h> + +/** + * A class for importing IE bookmarks + * @deprecated + */ +class KIO_EXPORT_DEPRECATED KIEBookmarkImporter : public QObject +{ + Q_OBJECT +public: + KIEBookmarkImporter( const QString & fileName ) : m_fileName(fileName) {} + ~KIEBookmarkImporter() {} + + void parseIEBookmarks(); + + // Usual place for IE bookmarks + static QString IEBookmarksDir(); + +signals: + void newBookmark( const QString & text, const QCString & url, const QString & additionalInfo ); + void newFolder( const QString & text, bool open, const QString & additionalInfo ); + void newSeparator(); + void endFolder(); + +protected: + void parseIEBookmarks_dir( QString dirname, QString name = QString::null ); + void parseIEBookmarks_url_file( QString filename, QString name ); + + QString m_fileName; +}; + +/** + * A class for importing IE bookmarks + * @since 3.2 + */ +class KIO_EXPORT KIEBookmarkImporterImpl : public KBookmarkImporterBase +{ +public: + KIEBookmarkImporterImpl() { } + virtual void parse(); + virtual QString findDefaultLocation(bool forSaving = false) const; +private: + class KIEBookmarkImporterImplPrivate *d; +}; + +/* + * @since 3.2 + */ +class KIO_EXPORT KIEBookmarkExporterImpl : public KBookmarkExporterBase +{ +public: + KIEBookmarkExporterImpl(KBookmarkManager* mgr, const QString & path) + : KBookmarkExporterBase(mgr, path) + { ; } + virtual ~KIEBookmarkExporterImpl() {} + virtual void write(KBookmarkGroup); +private: + class KIEBookmarkExporterImplPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkimporter_kde1.cc b/kio/bookmarks/kbookmarkimporter_kde1.cc new file mode 100644 index 000000000..72fe8dbb3 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_kde1.cc @@ -0,0 +1,150 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkimporter_kde1.h" +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <kcharsets.h> +#include <qtextcodec.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> +#include <assert.h> + +//////////////////// + +void KBookmarkImporter::import( const QString & path ) +{ + QDomElement elem = m_pDoc->documentElement(); + Q_ASSERT(!elem.isNull()); + scanIntern( elem, path ); +} + +void KBookmarkImporter::scanIntern( QDomElement & parentElem, const QString & _path ) +{ + kdDebug(7043) << "KBookmarkImporter::scanIntern " << _path << endl; + // Substitute all symbolic links in the path + QDir dir( _path ); + QString canonical = dir.canonicalPath(); + + if ( m_lstParsedDirs.contains(canonical) ) + { + kdWarning() << "Directory " << canonical << " already parsed" << endl; + return; + } + + m_lstParsedDirs.append( canonical ); + + DIR *dp; + struct dirent *ep; + dp = opendir( QFile::encodeName(_path) ); + if ( dp == 0L ) + return; + + // Loop thru all directory entries + while ( ( ep = readdir( dp ) ) != 0L ) + { + if ( strcmp( ep->d_name, "." ) != 0 && strcmp( ep->d_name, ".." ) != 0 ) + { + KURL file; + file.setPath( QString( _path ) + '/' + QFile::decodeName(ep->d_name) ); + + KMimeType::Ptr res = KMimeType::findByURL( file, 0, true ); + //kdDebug(7043) << " - " << file.url() << " -> " << res->name() << endl; + + if ( res->name() == "inode/directory" ) + { + // We could use KBookmarkGroup::createNewFolder, but then it + // would notify about the change, so we'd need a flag, etc. + QDomElement groupElem = m_pDoc->createElement( "folder" ); + parentElem.appendChild( groupElem ); + QDomElement textElem = m_pDoc->createElement( "title" ); + groupElem.appendChild( textElem ); + textElem.appendChild( m_pDoc->createTextNode( KIO::decodeFileName( ep->d_name ) ) ); + if ( KIO::decodeFileName( ep->d_name ) == "Toolbar" ) + groupElem.setAttribute("toolbar","yes"); + scanIntern( groupElem, file.path() ); + } + else if ( res->name() == "application/x-desktop" ) + { + KSimpleConfig cfg( file.path(), true ); + cfg.setDesktopGroup(); + QString type = cfg.readEntry( "Type" ); + // Is it really a bookmark file ? + if ( type == "Link" ) + parseBookmark( parentElem, ep->d_name, cfg, 0 /* desktop group */ ); + else + kdWarning(7043) << " Not a link ? Type=" << type << endl; + } + else if ( res->name() == "text/plain") + { + // maybe its an IE Favourite.. + KSimpleConfig cfg( file.path(), true ); + QStringList grp = cfg.groupList().grep( "internetshortcut", false ); + if ( grp.count() == 0 ) + continue; + cfg.setGroup( *grp.begin() ); + + QString url = cfg.readPathEntry("URL"); + if (!url.isEmpty() ) + parseBookmark( parentElem, ep->d_name, cfg, *grp.begin() ); + } else + kdWarning(7043) << "Invalid bookmark : found mimetype='" << res->name() << "' for file='" << file.path() << "'!" << endl; + } + } + + closedir( dp ); +} + +void KBookmarkImporter::parseBookmark( QDomElement & parentElem, QCString _text, + KSimpleConfig& _cfg, const QString &_group ) +{ + if ( !_group.isEmpty() ) + _cfg.setGroup( _group ); + else + _cfg.setDesktopGroup(); + + QString url = _cfg.readPathEntry( "URL" ); + QString icon = _cfg.readEntry( "Icon" ); + if (icon.right( 4 ) == ".xpm" ) // prevent warnings + icon.truncate( icon.length() - 4 ); + + QString text = KIO::decodeFileName( QString::fromLocal8Bit(_text) ); + if ( text.length() > 8 && text.right( 8 ) == ".desktop" ) + text.truncate( text.length() - 8 ); + if ( text.length() > 7 && text.right( 7 ) == ".kdelnk" ) + text.truncate( text.length() - 7 ); + + QDomElement elem = m_pDoc->createElement( "bookmark" ); + parentElem.appendChild( elem ); + elem.setAttribute( "href", url ); + //if ( icon != "www" ) // No need to save the default + // Hmm, after all, it makes KBookmark::pixmapFile faster, + // and it shows a nice feature to those reading the file + elem.setAttribute( "icon", icon ); + QDomElement textElem = m_pDoc->createElement( "title" ); + elem.appendChild( textElem ); + textElem.appendChild( m_pDoc->createTextNode( text ) ); + kdDebug(7043) << "KBookmarkImporter::parseBookmark text=" << text << endl; +} diff --git a/kio/bookmarks/kbookmarkimporter_kde1.h b/kio/bookmarks/kbookmarkimporter_kde1.h new file mode 100644 index 000000000..9811cce55 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_kde1.h @@ -0,0 +1,49 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_kde1_h +#define __kbookmarkimporter_kde1_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> + +/** + * A class for importing the previous bookmarks (desktop files) + * Separated from KBookmarkManager to save memory (we throw this one + * out once the import is done) + */ +class KIO_EXPORT KBookmarkImporter +{ +public: + KBookmarkImporter( QDomDocument * doc ) : m_pDoc(doc) {} + + void import( const QString & path ); + +private: + void scanIntern( QDomElement & parentElem, const QString & _path ); + void parseBookmark( QDomElement & parentElem, QCString _text, + KSimpleConfig& _cfg, const QString &_group ); + QDomDocument * m_pDoc; + QStringList m_lstParsedDirs; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkimporter_ns.cc b/kio/bookmarks/kbookmarkimporter_ns.cc new file mode 100644 index 000000000..23f37e4cb --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_ns.cc @@ -0,0 +1,243 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 1996-1998 Martin R. Jones <mjones@kde.org> + Copyright (C) 2000 David Faure <faure@kde.org> + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkimporter.h" +#include "kbookmarkexporter.h" +#include "kbookmarkmanager.h" +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <kcharsets.h> +#include <qtextcodec.h> +#include <qstylesheet.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> +#include <assert.h> + +void KNSBookmarkImporterImpl::parse() +{ + QFile f(m_fileName); + QTextCodec * codec = m_utf8 ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale(); + Q_ASSERT(codec); + if (!codec) + return; + + if(f.open(IO_ReadOnly)) { + + static const int g_lineLimit = 16*1024; + QCString s(g_lineLimit); + // skip header + while(f.readLine(s.data(), g_lineLimit) >= 0 && !s.contains("<DL>")); + + while(f.readLine(s.data(), g_lineLimit)>=0) { + if ( s[s.length()-1] != '\n' ) // Gosh, this line is longer than g_lineLimit. Skipping. + { + kdWarning() << "Netscape bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl; + continue; + } + QCString t = s.stripWhiteSpace(); + if(t.left(12).upper() == "<DT><A HREF=" || + t.left(16).upper() == "<DT><H3><A HREF=") { + int firstQuotes = t.find('"')+1; + int secondQuotes = t.find('"', firstQuotes); + if (firstQuotes != -1 && secondQuotes != -1) + { + QCString link = t.mid(firstQuotes, secondQuotes-firstQuotes); + int endTag = t.find('>', secondQuotes+1); + QCString name = t.mid(endTag+1); + name = name.left(name.findRev('<')); + if ( name.right(4) == "</A>" ) + name = name.left( name.length() - 4 ); + QString qname = KCharsets::resolveEntities( codec->toUnicode( name ) ); + QCString additionalInfo = t.mid( secondQuotes+1, endTag-secondQuotes-1 ); + + emit newBookmark( qname, + link, codec->toUnicode(additionalInfo) ); + } + } + else if(t.left(7).upper() == "<DT><H3") { + int endTag = t.find('>', 7); + QCString name = t.mid(endTag+1); + name = name.left(name.findRev('<')); + QString qname = KCharsets::resolveEntities( codec->toUnicode( name ) ); + QCString additionalInfo = t.mid( 8, endTag-8 ); + bool folded = (additionalInfo.left(6) == "FOLDED"); + if (folded) additionalInfo.remove(0,7); + + emit newFolder( qname, + !folded, + codec->toUnicode(additionalInfo) ); + } + else if(t.left(4).upper() == "<HR>") + emit newSeparator(); + else if(t.left(8).upper() == "</DL><P>") + emit endFolder(); + } + + f.close(); + } +} + +QString KNSBookmarkImporterImpl::findDefaultLocation(bool forSaving) const +{ + if (m_utf8) + { + if ( forSaving ) + return KFileDialog::getSaveFileName( QDir::homeDirPath() + "/.mozilla", + i18n("*.html|HTML Files (*.html)") ); + else + return KFileDialog::getOpenFileName( QDir::homeDirPath() + "/.mozilla", + i18n("*.html|HTML Files (*.html)") ); + } + else + { + return QDir::homeDirPath() + "/.netscape/bookmarks.html"; + } +} + +//////////////////////////////////////////////////////////////// + + +void KNSBookmarkImporter::parseNSBookmarks( bool utf8 ) +{ + KNSBookmarkImporterImpl importer; + importer.setFilename(m_fileName); + importer.setUtf8(utf8); + importer.setupSignalForwards(&importer, this); + importer.parse(); +} + +QString KNSBookmarkImporter::netscapeBookmarksFile( bool forSaving ) +{ + static KNSBookmarkImporterImpl *p = 0; + if (!p) + { + p = new KNSBookmarkImporterImpl; + p->setUtf8(false); + } + return p->findDefaultLocation(forSaving); +} + +QString KNSBookmarkImporter::mozillaBookmarksFile( bool forSaving ) +{ + static KNSBookmarkImporterImpl *p = 0; + if (!p) + { + p = new KNSBookmarkImporterImpl; + p->setUtf8(true); + } + return p->findDefaultLocation(forSaving); +} + + +//////////////////////////////////////////////////////////////// +// compat only +//////////////////////////////////////////////////////////////// + +void KNSBookmarkExporter::write(bool utf8) { + KNSBookmarkExporterImpl exporter(m_pManager, m_fileName); + exporter.setUtf8(utf8); + exporter.write(m_pManager->root()); +} + +void KNSBookmarkExporter::writeFolder(QTextStream &/*stream*/, KBookmarkGroup /*gp*/) { + // TODO - requires a d pointer workaround hack? +} + +//////////////////////////////////////////////////////////////// + +void KNSBookmarkExporterImpl::setUtf8(bool utf8) { + m_utf8 = utf8; +} + +void KNSBookmarkExporterImpl::write(KBookmarkGroup parent) { + if (QFile::exists(m_fileName)) { + ::rename( + QFile::encodeName(m_fileName), + QFile::encodeName(m_fileName + ".beforekde")); + } + + QFile file(m_fileName); + + if (!file.open(IO_WriteOnly)) { + kdError(7043) << "Can't write to file " << m_fileName << endl; + return; + } + + QTextStream fstream(&file); + fstream.setEncoding(m_utf8 ? QTextStream::UnicodeUTF8 : QTextStream::Locale); + + QString charset + = m_utf8 ? "UTF-8" : QString::fromLatin1(QTextCodec::codecForLocale()->name()).upper(); + + fstream << "<!DOCTYPE NETSCAPE-Bookmark-file-1>" << endl + << i18n("<!-- This file was generated by Konqueror -->") << endl + << "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=" + << charset << "\">" << endl + << "<TITLE>" << i18n("Bookmarks") << "</TITLE>" << endl + << "<H1>" << i18n("Bookmarks") << "</H1>" << endl + << "<DL><p>" << endl + << folderAsString(parent) + << "</DL><P>" << endl; +} + +QString KNSBookmarkExporterImpl::folderAsString(KBookmarkGroup parent) const { + QString str; + QTextStream fstream(&str, IO_WriteOnly); + + for (KBookmark bk = parent.first(); !bk.isNull(); bk = parent.next(bk)) { + if (bk.isSeparator()) { + fstream << "<HR>" << endl; + continue; + } + + QString text = QStyleSheet::escape(bk.fullText()); + + if (bk.isGroup() ) { + fstream << "<DT><H3 " + << (!bk.toGroup().isOpen() ? "FOLDED " : "") + << bk.internalElement().attribute("netscapeinfo") << ">" + << text << "</H3>" << endl + << "<DL><P>" << endl + << folderAsString(bk.toGroup()) + << "</DL><P>" << endl; + continue; + + } else { + // note - netscape seems to use local8bit for url... + fstream << "<DT><A HREF=\"" << bk.url().url() << "\"" + << bk.internalElement().attribute("netscapeinfo") << ">" + << text << "</A>" << endl; + continue; + } + } + + return str; +} + +//// + +#include "kbookmarkimporter_ns.moc" diff --git a/kio/bookmarks/kbookmarkimporter_ns.h b/kio/bookmarks/kbookmarkimporter_ns.h new file mode 100644 index 000000000..48f6705aa --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_ns.h @@ -0,0 +1,132 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_ns_h +#define __kbookmarkimporter_ns_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> +#include <kdemacros.h> + +#include "kbookmarkimporter.h" +#include "kbookmarkexporter.h" + +/** + * A class for importing NS bookmarks + * @deprecated + */ +class KIO_EXPORT_DEPRECATED KNSBookmarkImporter : public QObject +{ + Q_OBJECT +public: + KNSBookmarkImporter( const QString & fileName ) : m_fileName(fileName) {} + ~KNSBookmarkImporter() {} + + // for compat reasons only + void parseNSBookmarks() { parseNSBookmarks(false); } + // go for it. Set utf8 to true for Mozilla, false for Netscape. + void parseNSBookmarks( bool utf8 ); + + static QString netscapeBookmarksFile( bool forSaving=false ); + static QString mozillaBookmarksFile( bool forSaving=false ); + +signals: + void newBookmark( const QString & text, const QCString & url, const QString & additionalInfo ); + void newFolder( const QString & text, bool open, const QString & additionalInfo ); + void newSeparator(); + void endFolder(); + +protected: + QString m_fileName; +}; + +/** + * A class for importing NS bookmarks + * utf8 defaults to off + * @since 3.2 + */ +class KIO_EXPORT KNSBookmarkImporterImpl : public KBookmarkImporterBase +{ +public: + KNSBookmarkImporterImpl() : m_utf8(false) { } + void setUtf8(bool utf8) { m_utf8 = utf8; } + virtual void parse(); + virtual QString findDefaultLocation(bool forSaving = false) const; +private: + bool m_utf8; + class KNSBookmarkImporterImplPrivate *d; +}; + +/** + * A class for importing Mozilla bookmarks + * utf8 defaults to on + * @since 3.2 + */ +class KIO_EXPORT KMozillaBookmarkImporterImpl : public KNSBookmarkImporterImpl +{ +public: + KMozillaBookmarkImporterImpl() { setUtf8(true); } +private: + class KMozillaBookmarkImporterImplPrivate *d; +}; + +/** + * A class that exports all the current bookmarks to Netscape/Mozilla bookmarks + * Warning, it overwrites the existing bookmarks.html file ! + * @deprecated + */ +class KIO_EXPORT_DEPRECATED KNSBookmarkExporter +{ +public: + KNSBookmarkExporter(KBookmarkManager* mgr, const QString & fileName) + : m_fileName(fileName), m_pManager(mgr) { } + ~KNSBookmarkExporter() {} + + void write() { write(false); } // deprecated + void write( bool utf8 ); + +protected: + void writeFolder(QTextStream &stream, KBookmarkGroup parent); + QString m_fileName; + KBookmarkManager* m_pManager; +}; + +/** + * @since 3.2 + */ +class KIO_EXPORT KNSBookmarkExporterImpl : public KBookmarkExporterBase +{ +public: + KNSBookmarkExporterImpl(KBookmarkManager* mgr, const QString & fileName) + : KBookmarkExporterBase(mgr, fileName) + { ; } + virtual ~KNSBookmarkExporterImpl() {} + virtual void write(KBookmarkGroup); + void setUtf8(bool); +protected: + QString folderAsString(KBookmarkGroup) const; +private: + bool m_utf8; + class KNSBookmarkExporterImplPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkimporter_opera.cc b/kio/bookmarks/kbookmarkimporter_opera.cc new file mode 100644 index 000000000..6e2a90570 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_opera.cc @@ -0,0 +1,170 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kfiledialog.h> +#include <kstringhandler.h> +#include <klocale.h> +#include <kdebug.h> +#include <qtextcodec.h> + +#include <sys/types.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/stat.h> + +#include "kbookmarkimporter.h" +#include "kbookmarkimporter_opera.h" + +void KOperaBookmarkImporter::parseOperaBookmarks( ) +{ + QFile file(m_fileName); + if(!file.open(IO_ReadOnly)) { + return; + } + + QTextCodec * codec = QTextCodec::codecForName("UTF-8"); + Q_ASSERT(codec); + if (!codec) + return; + + int lineno = 0; + QString url, name, type; + static const int g_lineLimit = 16*1024; + QCString line(g_lineLimit); + + while ( file.readLine(line.data(), g_lineLimit) >=0 ) { + lineno++; + + // skip lines that didn't fit in buffer and first two headers lines + if ( line[line.length()-1] != '\n' || lineno <= 2 ) + continue; + + QString currentLine = codec->toUnicode(line).stripWhiteSpace(); + + if (currentLine.isEmpty()) { + // end of data block + if (type.isNull()) + continue; + else if ( type == "URL") + emit newBookmark( name, url.latin1(), "" ); + else if (type == "FOLDER" ) + emit newFolder( name, false, "" ); + + type = QString::null; + name = QString::null; + url = QString::null; + + } else if (currentLine == "-") { + // end of folder + emit endFolder(); + + } else { + // data block line + QString tag; + if ( tag = "#", currentLine.startsWith( tag ) ) + type = currentLine.remove( 0, tag.length() ); + else if ( tag = "NAME=", currentLine.startsWith( tag ) ) + name = currentLine.remove(0, tag.length()); + else if ( tag = "URL=", currentLine.startsWith( tag ) ) + url = currentLine.remove(0, tag.length()); + } + } + +} + +QString KOperaBookmarkImporter::operaBookmarksFile() +{ + static KOperaBookmarkImporterImpl *p = 0; + if (!p) + p = new KOperaBookmarkImporterImpl; + return p->findDefaultLocation(); +} + +void KOperaBookmarkImporterImpl::parse() { + KOperaBookmarkImporter importer(m_fileName); + setupSignalForwards(&importer, this); + importer.parseOperaBookmarks(); +} + +QString KOperaBookmarkImporterImpl::findDefaultLocation(bool saving) const +{ + return saving ? KFileDialog::getSaveFileName( + QDir::homeDirPath() + "/.opera", + i18n("*.adr|Opera Bookmark Files (*.adr)") ) + : KFileDialog::getOpenFileName( + QDir::homeDirPath() + "/.opera", + i18n("*.adr|Opera Bookmark Files (*.adr)") ); +} + +///////////////////////////////////////////////// + +class OperaExporter : private KBookmarkGroupTraverser { +public: + OperaExporter(); + QString generate( const KBookmarkGroup &grp ) { traverse(grp); return m_string; }; +private: + virtual void visit( const KBookmark & ); + virtual void visitEnter( const KBookmarkGroup & ); + virtual void visitLeave( const KBookmarkGroup & ); +private: + QString m_string; + QTextStream m_out; +}; + +OperaExporter::OperaExporter() : m_out(&m_string, IO_WriteOnly) { + m_out << "Opera Hotlist version 2.0" << endl; + m_out << "Options: encoding = utf8, version=3" << endl; +} + +void OperaExporter::visit( const KBookmark &bk ) { + // kdDebug() << "visit(" << bk.text() << ")" << endl; + m_out << "#URL" << endl; + m_out << "\tNAME=" << bk.fullText() << endl; + m_out << "\tURL=" << bk.url().url().utf8() << endl; + m_out << endl; +} + +void OperaExporter::visitEnter( const KBookmarkGroup &grp ) { + // kdDebug() << "visitEnter(" << grp.text() << ")" << endl; + m_out << "#FOLDER" << endl; + m_out << "\tNAME="<< grp.fullText() << endl; + m_out << endl; +} + +void OperaExporter::visitLeave( const KBookmarkGroup & ) { + // kdDebug() << "visitLeave()" << endl; + m_out << "-" << endl; + m_out << endl; +} + +void KOperaBookmarkExporterImpl::write(KBookmarkGroup parent) { + OperaExporter exporter; + QString content = exporter.generate( parent ); + QFile file(m_fileName); + if (!file.open(IO_WriteOnly)) { + kdError(7043) << "Can't write to file " << m_fileName << endl; + return; + } + QTextStream fstream(&file); + fstream.setEncoding(QTextStream::UnicodeUTF8); + fstream << content; +} + +#include "kbookmarkimporter_opera.moc" diff --git a/kio/bookmarks/kbookmarkimporter_opera.h b/kio/bookmarks/kbookmarkimporter_opera.h new file mode 100644 index 000000000..b179f2f93 --- /dev/null +++ b/kio/bookmarks/kbookmarkimporter_opera.h @@ -0,0 +1,86 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2002 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkimporter_opera_h +#define __kbookmarkimporter_opera_h + +#include <qdom.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <ksimpleconfig.h> + +#include <kbookmarkimporter.h> + +/** + * A class for importing Opera bookmarks + * @deprecated + */ +class KIO_EXPORT_DEPRECATED KOperaBookmarkImporter : public QObject +{ + Q_OBJECT +public: + KOperaBookmarkImporter( const QString & fileName ) : m_fileName(fileName) {} + ~KOperaBookmarkImporter() {} + + void parseOperaBookmarks(); + + // Usual place for Opera bookmarks + static QString operaBookmarksFile(); + +signals: + void newBookmark( const QString & text, const QCString & url, const QString & additionalInfo ); + void newFolder( const QString & text, bool open, const QString & additionalInfo ); + void newSeparator(); + void endFolder(); + +protected: + QString m_fileName; +}; + +/** + * A class for importing Opera bookmarks + * @since 3.2 + */ +class KIO_EXPORT KOperaBookmarkImporterImpl : public KBookmarkImporterBase +{ +public: + KOperaBookmarkImporterImpl() { } + virtual void parse(); + virtual QString findDefaultLocation(bool forSaving = false) const; +private: + class KOperaBookmarkImporterImplPrivate *d; +}; + +/** + * @since 3.2 + */ +class KIO_EXPORT KOperaBookmarkExporterImpl : public KBookmarkExporterBase +{ +public: + KOperaBookmarkExporterImpl(KBookmarkManager* mgr, const QString & filename) + : KBookmarkExporterBase(mgr, filename) + { ; } + virtual ~KOperaBookmarkExporterImpl() {} + virtual void write(KBookmarkGroup); +private: + class KOperaBookmarkExporterImplPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkmanager.cc b/kio/bookmarks/kbookmarkmanager.cc new file mode 100644 index 000000000..d101c1f7f --- /dev/null +++ b/kio/bookmarks/kbookmarkmanager.cc @@ -0,0 +1,727 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkmanager.h" +#include "kbookmarkmenu.h" +#include "kbookmarkmenu_p.h" +#include "kbookmarkimporter.h" +#include <kdebug.h> +#include <krun.h> +#include <kstandarddirs.h> +#include <ksavefile.h> +#include <dcopref.h> +#include <qregexp.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <klocale.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <kstaticdeleter.h> +#include <qptrstack.h> + +#include "dptrtemplate.h" + +class KBookmarkManagerPrivate : public dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate> { +public: + KBookmarkManagerPrivate() + { m_browserEditor = true; } + QString m_editorCaption; + bool m_browserEditor; +}; +template<> QPtrDict<KBookmarkManagerPrivate>* dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate>::d_ptr = 0; + +KBookmarkManagerPrivate* KBookmarkManager::dptr() const { + return KBookmarkManagerPrivate::d( this ); +} + +// TODO - clean this stuff up by just using the above dptrtemplate? +QPtrList<KBookmarkManager>* KBookmarkManager::s_pSelf; +static KStaticDeleter<QPtrList<KBookmarkManager> > sdbm; + +class KBookmarkMap : private KBookmarkGroupTraverser { +public: + KBookmarkMap( KBookmarkManager * ); + void update(); + QValueList<KBookmark> find( const QString &url ) const + { return m_bk_map[url]; } +private: + virtual void visit(const KBookmark &); + virtual void visitEnter(const KBookmarkGroup &) { ; } + virtual void visitLeave(const KBookmarkGroup &) { ; } +private: + typedef QValueList<KBookmark> KBookmarkList; + QMap<QString, KBookmarkList> m_bk_map; + KBookmarkManager *m_manager; +}; + +static KBookmarkMap *s_bk_map = 0; + +KBookmarkMap::KBookmarkMap( KBookmarkManager *manager ) { + m_manager = manager; +} + +void KBookmarkMap::update() +{ + m_bk_map.clear(); + KBookmarkGroup root = m_manager->root(); + traverse(root); +} + +void KBookmarkMap::visit(const KBookmark &bk) +{ + if (!bk.isSeparator()) { + // add bookmark to url map + m_bk_map[bk.internalElement().attribute("href")].append(bk); + } +} + + +KBookmarkManager* KBookmarkManager::managerForFile( const QString& bookmarksFile, bool bImportDesktopFiles ) +{ + if ( !s_pSelf ) { + sdbm.setObject( s_pSelf, new QPtrList<KBookmarkManager> ); + s_pSelf->setAutoDelete( true ); + } + QPtrListIterator<KBookmarkManager> it ( *s_pSelf ); + for ( ; it.current() ; ++it ) + if ( it.current()->path() == bookmarksFile ) + return it.current(); + + KBookmarkManager* mgr = new KBookmarkManager( bookmarksFile, bImportDesktopFiles ); + s_pSelf->append( mgr ); + return mgr; +} + +// principally used for filtered toolbars +KBookmarkManager* KBookmarkManager::createTempManager() +{ + if ( !s_pSelf ) { + sdbm.setObject( s_pSelf, new QPtrList<KBookmarkManager> ); + s_pSelf->setAutoDelete( true ); + } + KBookmarkManager* mgr = new KBookmarkManager(); + s_pSelf->append( mgr ); + return mgr; +} + +#define PI_DATA "version=\"1.0\" encoding=\"UTF-8\"" + +KBookmarkManager::KBookmarkManager( const QString & bookmarksFile, bool bImportDesktopFiles ) + : DCOPObject(QCString("KBookmarkManager-")+bookmarksFile.utf8()), m_doc("xbel"), m_docIsLoaded(false) +{ + m_toolbarDoc.clear(); + + m_update = true; + m_showNSBookmarks = true; + + Q_ASSERT( !bookmarksFile.isEmpty() ); + m_bookmarksFile = bookmarksFile; + + if ( !QFile::exists(m_bookmarksFile) ) + { + QDomElement topLevel = m_doc.createElement("xbel"); + m_doc.appendChild( topLevel ); + m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel ); + if ( bImportDesktopFiles ) + importDesktopFiles(); + m_docIsLoaded = true; + } + + connectDCOPSignal(0, objId(), "bookmarksChanged(QString)", "notifyChanged(QString)", false); + connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false); +} + +KBookmarkManager::KBookmarkManager( ) + : DCOPObject(QCString("KBookmarkManager-generated")), m_doc("xbel"), m_docIsLoaded(true) +{ + m_toolbarDoc.clear(); // strange ;-) + + m_update = false; // TODO - make it read/write + m_showNSBookmarks = true; + + m_bookmarksFile = QString::null; // AK - check all codepaths for this one + + QDomElement topLevel = m_doc.createElement("xbel"); + m_doc.appendChild( topLevel ); + m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel ); + + // TODO - enable this via some sort of api and fix the above DCOPObject script somehow +#if 0 + connectDCOPSignal(0, objId(), "bookmarksChanged(QString)", "notifyChanged(QString)", false); + connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false); +#endif +} + +KBookmarkManager::~KBookmarkManager() +{ + if ( s_pSelf ) + s_pSelf->removeRef( this ); +} + +void KBookmarkManager::setUpdate( bool update ) +{ + m_update = update; +} + +const QDomDocument &KBookmarkManager::internalDocument() const +{ + if(!m_docIsLoaded) + { + parse(); + m_toolbarDoc.clear(); + } + return m_doc; +} + + +void KBookmarkManager::parse() const +{ + m_docIsLoaded = true; + //kdDebug(7043) << "KBookmarkManager::parse " << m_bookmarksFile << endl; + QFile file( m_bookmarksFile ); + if ( !file.open( IO_ReadOnly ) ) + { + kdWarning() << "Can't open " << m_bookmarksFile << endl; + return; + } + m_doc = QDomDocument("xbel"); + m_doc.setContent( &file ); + + QDomElement docElem = m_doc.documentElement(); + if ( docElem.isNull() ) + kdWarning() << "KBookmarkManager::parse : can't parse " << m_bookmarksFile << endl; + else + { + QString mainTag = docElem.tagName(); + if ( mainTag == "BOOKMARKS" ) + { + kdWarning() << "Old style bookmarks found. Calling convertToXBEL." << endl; + docElem.setTagName("xbel"); + if ( docElem.hasAttribute( "HIDE_NSBK" ) && m_showNSBookmarks ) // non standard either, but we need it + { + docElem.setAttribute( "hide_nsbk", docElem.attribute( "HIDE_NSBK" ) == "1" ? "yes" : "no" ); + docElem.removeAttribute( "HIDE_NSBK" ); + } + + convertToXBEL( docElem ); + save(); + } + else if ( mainTag != "xbel" ) + kdWarning() << "KBookmarkManager::parse : unknown main tag " << mainTag << endl; + + QDomNode n = m_doc.documentElement().previousSibling(); + if ( n.isProcessingInstruction() ) + { + QDomProcessingInstruction pi = n.toProcessingInstruction(); + pi.parentNode().removeChild(pi); + } + + QDomProcessingInstruction pi; + pi = m_doc.createProcessingInstruction( "xml", PI_DATA ); + m_doc.insertBefore( pi, docElem ); + } + + file.close(); + if ( !s_bk_map ) + s_bk_map = new KBookmarkMap( const_cast<KBookmarkManager*>( this ) ); + s_bk_map->update(); +} + +void KBookmarkManager::convertToXBEL( QDomElement & group ) +{ + QDomNode n = group.firstChild(); + while( !n.isNull() ) + { + QDomElement e = n.toElement(); + if ( !e.isNull() ) + if ( e.tagName() == "TEXT" ) + { + e.setTagName("title"); + } + else if ( e.tagName() == "SEPARATOR" ) + { + e.setTagName("separator"); // so close... + } + else if ( e.tagName() == "GROUP" ) + { + e.setTagName("folder"); + convertAttribute(e, "ICON","icon"); // non standard, but we need it + if ( e.hasAttribute( "TOOLBAR" ) ) // non standard either, but we need it + { + e.setAttribute( "toolbar", e.attribute( "TOOLBAR" ) == "1" ? "yes" : "no" ); + e.removeAttribute( "TOOLBAR" ); + } + + convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem + bool open = (e.attribute("OPEN") == "1"); + e.removeAttribute("OPEN"); + e.setAttribute("folded", open ? "no" : "yes"); + convertToXBEL( e ); + } + else + if ( e.tagName() == "BOOKMARK" ) + { + e.setTagName("bookmark"); // so much difference :-) + convertAttribute(e, "ICON","icon"); // non standard, but we need it + convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem + convertAttribute(e, "URL","href"); + QString text = e.text(); + while ( !e.firstChild().isNull() ) // clean up the old contained text + e.removeChild(e.firstChild()); + QDomElement titleElem = e.ownerDocument().createElement("title"); + e.appendChild( titleElem ); // should be the only child anyway + titleElem.appendChild( e.ownerDocument().createTextNode( text ) ); + } + else + kdWarning(7043) << "Unknown tag " << e.tagName() << endl; + n = n.nextSibling(); + } +} + +void KBookmarkManager::convertAttribute( QDomElement elem, const QString & oldName, const QString & newName ) +{ + if ( elem.hasAttribute( oldName ) ) + { + elem.setAttribute( newName, elem.attribute( oldName ) ); + elem.removeAttribute( oldName ); + } +} + +void KBookmarkManager::importDesktopFiles() +{ + KBookmarkImporter importer( const_cast<QDomDocument *>(&internalDocument()) ); + QString path(KGlobal::dirs()->saveLocation("data", "kfm/bookmarks", true)); + importer.import( path ); + //kdDebug(7043) << internalDocument().toCString() << endl; + + save(); +} + +bool KBookmarkManager::save( bool toolbarCache ) const +{ + return saveAs( m_bookmarksFile, toolbarCache ); +} + +bool KBookmarkManager::saveAs( const QString & filename, bool toolbarCache ) const +{ + kdDebug(7043) << "KBookmarkManager::save " << filename << endl; + + // Save the bookmark toolbar folder for quick loading + // but only when it will actually make things quicker + const QString cacheFilename = filename + QString::fromLatin1(".tbcache"); + if(toolbarCache && !root().isToolbarGroup()) + { + KSaveFile cacheFile( cacheFilename ); + if ( cacheFile.status() == 0 ) + { + QString str; + QTextStream stream(&str, IO_WriteOnly); + stream << root().findToolbar(); + QCString cstr = str.utf8(); + cacheFile.file()->writeBlock( cstr.data(), cstr.length() ); + cacheFile.close(); + } + } + else // remove any (now) stale cache + { + QFile::remove( cacheFilename ); + } + + KSaveFile file( filename ); + if ( file.status() == 0 ) + { + file.backupFile( file.name(), QString::null, ".bak" ); + QCString cstr; + cstr = internalDocument().toCString(); // is in UTF8 + file.file()->writeBlock( cstr.data(), cstr.length() ); + if ( file.close() ) + return true; + } + + static int hadSaveError = false; + file.abort(); + if ( !hadSaveError ) { + QString error = i18n("Unable to save bookmarks in %1. Reported error was: %2. " + "This error message will only be shown once. The cause " + "of the error needs to be fixed as quickly as possible, " + "which is most likely a full hard drive.") + .arg(filename).arg(QString::fromLocal8Bit(strerror(file.status()))); + if (qApp->type() != QApplication::Tty) + KMessageBox::error( 0L, error ); + else + kdError() << error << endl; + } + hadSaveError = true; + return false; +} + +KBookmarkGroup KBookmarkManager::root() const +{ + return KBookmarkGroup(internalDocument().documentElement()); +} + +KBookmarkGroup KBookmarkManager::toolbar() +{ + kdDebug(7043) << "KBookmarkManager::toolbar begin" << endl; + // Only try to read from a toolbar cache if the full document isn't loaded + if(!m_docIsLoaded) + { + kdDebug(7043) << "KBookmarkManager::toolbar trying cache" << endl; + const QString cacheFilename = m_bookmarksFile + QString::fromLatin1(".tbcache"); + QFileInfo bmInfo(m_bookmarksFile); + QFileInfo cacheInfo(cacheFilename); + if (m_toolbarDoc.isNull() && + QFile::exists(cacheFilename) && + bmInfo.lastModified() < cacheInfo.lastModified()) + { + kdDebug(7043) << "KBookmarkManager::toolbar reading file" << endl; + QFile file( cacheFilename ); + + if ( file.open( IO_ReadOnly ) ) + { + m_toolbarDoc = QDomDocument("cache"); + m_toolbarDoc.setContent( &file ); + kdDebug(7043) << "KBookmarkManager::toolbar opened" << endl; + } + } + if (!m_toolbarDoc.isNull()) + { + kdDebug(7043) << "KBookmarkManager::toolbar returning element" << endl; + QDomElement elem = m_toolbarDoc.firstChild().toElement(); + return KBookmarkGroup(elem); + } + } + + // Fallback to the normal way if there is no cache or if the bookmark file + // is already loaded + QDomElement elem = root().findToolbar(); + if (elem.isNull()) + return root(); // Root is the bookmark toolbar if none has been set. + else + return KBookmarkGroup(root().findToolbar()); +} + +KBookmark KBookmarkManager::findByAddress( const QString & address, bool tolerant ) +{ + //kdDebug(7043) << "KBookmarkManager::findByAddress " << address << endl; + KBookmark result = root(); + // The address is something like /5/10/2+ + QStringList addresses = QStringList::split(QRegExp("[/+]"),address); + // kdWarning() << addresses.join(",") << endl; + for ( QStringList::Iterator it = addresses.begin() ; it != addresses.end() ; ) + { + bool append = ((*it) == "+"); + uint number = (*it).toUInt(); + Q_ASSERT(result.isGroup()); + KBookmarkGroup group = result.toGroup(); + KBookmark bk = group.first(), lbk = bk; // last non-null bookmark + for ( uint i = 0 ; ( (i<number) || append ) && !bk.isNull() ; ++i ) { + lbk = bk; + bk = group.next(bk); + //kdWarning() << i << endl; + } + it++; + int shouldBeGroup = !bk.isGroup() && (it != addresses.end()); + if ( tolerant && ( bk.isNull() || shouldBeGroup ) ) { + if (!lbk.isNull()) result = lbk; + //kdWarning() << "break" << endl; + break; + } + //kdWarning() << "found section" << endl; + result = bk; + } + if (result.isNull()) { + kdWarning() << "KBookmarkManager::findByAddress: couldn't find item " << address << endl; + Q_ASSERT(!tolerant); + } + //kdWarning() << "found " << result.address() << endl; + return result; + } + +static QString pickUnusedTitle( KBookmarkGroup parentBookmark, + const QString &title, const QString &url +) { + // If this title is already used, we'll try to find something unused. + KBookmark ch = parentBookmark.first(); + int count = 1; + QString uniqueTitle = title; + do + { + while ( !ch.isNull() ) + { + if ( uniqueTitle == ch.text() ) + { + // Title already used ! + if ( url != ch.url().url() ) + { + uniqueTitle = title + QString(" (%1)").arg(++count); + // New title -> restart search from the beginning + ch = parentBookmark.first(); + break; + } + else + { + // this exact URL already exists + return QString::null; + } + } + ch = parentBookmark.next( ch ); + } + } while ( !ch.isNull() ); + + return uniqueTitle; +} + +KBookmarkGroup KBookmarkManager::addBookmarkDialog( + const QString & _url, const QString & _title, + const QString & _parentBookmarkAddress +) { + QString url = _url; + QString title = _title; + QString parentBookmarkAddress = _parentBookmarkAddress; + + if ( url.isEmpty() ) + { + KMessageBox::error( 0L, i18n("Cannot add bookmark with empty URL.")); + return KBookmarkGroup(); + } + + if ( title.isEmpty() ) + title = url; + + if ( KBookmarkSettings::self()->m_advancedaddbookmark) + { + KBookmarkEditDialog dlg( title, url, this, KBookmarkEditDialog::InsertionMode, parentBookmarkAddress ); + if ( dlg.exec() != KDialogBase::Accepted ) + return KBookmarkGroup(); + title = dlg.finalTitle(); + url = dlg.finalUrl(); + parentBookmarkAddress = dlg.finalAddress(); + } + + KBookmarkGroup parentBookmark; + parentBookmark = findByAddress( parentBookmarkAddress ).toGroup(); + Q_ASSERT( !parentBookmark.isNull() ); + + QString uniqueTitle = pickUnusedTitle( parentBookmark, title, url ); + if ( !uniqueTitle.isNull() ) + parentBookmark.addBookmark( this, uniqueTitle, KURL( url )); + + return parentBookmark; +} + + +void KBookmarkManager::emitChanged( /*KDE4 const*/ KBookmarkGroup & group ) +{ + save(); + + // Tell the other processes too + // kdDebug(7043) << "KBookmarkManager::emitChanged : broadcasting change " << group.address() << endl; + + QByteArray data; + QDataStream ds( data, IO_WriteOnly ); + ds << group.address(); + + emitDCOPSignal("bookmarksChanged(QString)", data); + + // We do get our own broadcast, so no need for this anymore + //emit changed( group ); +} + +void KBookmarkManager::emitConfigChanged() +{ + emitDCOPSignal("bookmarkConfigChanged()", QByteArray()); +} + +void KBookmarkManager::notifyCompleteChange( QString caller ) // DCOP call +{ + if (!m_update) return; + + //kdDebug(7043) << "KBookmarkManager::notifyCompleteChange" << endl; + // The bk editor tells us we should reload everything + // Reparse + parse(); + // Tell our GUI + // (emit where group is "" to directly mark the root menu as dirty) + emit changed( "", caller ); +} + +void KBookmarkManager::notifyConfigChanged() // DCOP call +{ + kdDebug() << "reloaded bookmark config!" << endl; + KBookmarkSettings::self()->readSettings(); + parse(); // reload, and thusly recreate the menus +} + +void KBookmarkManager::notifyChanged( QString groupAddress ) // DCOP call +{ + if (!m_update) return; + + // Reparse (the whole file, no other choice) + // if someone else notified us + if (callingDcopClient()->senderId() != DCOPClient::mainClient()->appId()) + parse(); + + //kdDebug(7043) << "KBookmarkManager::notifyChanged " << groupAddress << endl; + //KBookmarkGroup group = findByAddress( groupAddress ).toGroup(); + //Q_ASSERT(!group.isNull()); + emit changed( groupAddress, QString::null ); +} + +bool KBookmarkManager::showNSBookmarks() const +{ + return KBookmarkMenu::showDynamicBookmarks("netscape").show; +} + +void KBookmarkManager::setShowNSBookmarks( bool show ) +{ + m_showNSBookmarks = show; + if (this->path() != userBookmarksFile()) + return; + KBookmarkMenu::DynMenuInfo info + = KBookmarkMenu::showDynamicBookmarks("netscape"); + info.show = show; + KBookmarkMenu::setDynamicBookmarks("netscape", info); +} + +void KBookmarkManager::setEditorOptions( const QString& caption, bool browser ) +{ + dptr()->m_editorCaption = caption; + dptr()->m_browserEditor = browser; +} + +void KBookmarkManager::slotEditBookmarks() +{ + KProcess proc; + proc << QString::fromLatin1("keditbookmarks"); + if (!dptr()->m_editorCaption.isNull()) + proc << QString::fromLatin1("--customcaption") << dptr()->m_editorCaption; + if (!dptr()->m_browserEditor) + proc << QString::fromLatin1("--nobrowser"); + proc << m_bookmarksFile; + proc.start(KProcess::DontCare); +} + +void KBookmarkManager::slotEditBookmarksAtAddress( const QString& address ) +{ + KProcess proc; + proc << QString::fromLatin1("keditbookmarks") + << QString::fromLatin1("--address") << address + << m_bookmarksFile; + proc.start(KProcess::DontCare); +} + +/////// + +void KBookmarkOwner::openBookmarkURL( const QString& url ) +{ + (void) new KRun(KURL( url )); +} + +void KBookmarkOwner::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +bool KBookmarkManager::updateAccessMetadata( const QString & url, bool emitSignal ) +{ + if (!s_bk_map) { + s_bk_map = new KBookmarkMap(this); + s_bk_map->update(); + } + + QValueList<KBookmark> list = s_bk_map->find(url); + if ( list.count() == 0 ) + return false; + + for ( QValueList<KBookmark>::iterator it = list.begin(); + it != list.end(); ++it ) + (*it).updateAccessMetadata(); + + if (emitSignal) + emit notifier().updatedAccessMetadata( path(), url ); + + return true; +} + +void KBookmarkManager::updateFavicon( const QString &url, const QString &faviconurl, bool emitSignal ) +{ + Q_UNUSED(faviconurl); + + if (!s_bk_map) { + s_bk_map = new KBookmarkMap(this); + s_bk_map->update(); + } + + QValueList<KBookmark> list = s_bk_map->find(url); + for ( QValueList<KBookmark>::iterator it = list.begin(); + it != list.end(); ++it ) + { + // TODO - update favicon data based on faviconurl + // but only when the previously used icon + // isn't a manually set one. + } + + if (emitSignal) + { + // TODO + // emit notifier().updatedFavicon( path(), url, faviconurl ); + } +} + +QString KBookmarkManager::userBookmarksFile() +{ + return locateLocal("data", QString::fromLatin1("konqueror/bookmarks.xml")); +} + +KBookmarkManager* KBookmarkManager::userBookmarksManager() +{ + return KBookmarkManager::managerForFile( userBookmarksFile() ); +} + +KBookmarkSettings* KBookmarkSettings::s_self = 0; + +void KBookmarkSettings::readSettings() +{ + KConfig config("kbookmarkrc", false, false); + config.setGroup("Bookmarks"); + + // add bookmark dialog usage - no reparse + s_self->m_advancedaddbookmark = config.readBoolEntry("AdvancedAddBookmarkDialog", false); + + // these three alter the menu, therefore all need a reparse + s_self->m_contextmenu = config.readBoolEntry("ContextMenuActions", true); + s_self->m_quickactions = config.readBoolEntry("QuickActionSubmenu", false); + s_self->m_filteredtoolbar = config.readBoolEntry("FilteredToolbar", false); +} + +KBookmarkSettings *KBookmarkSettings::self() +{ + if (!s_self) + { + s_self = new KBookmarkSettings; + readSettings(); + } + return s_self; +} + +#include "kbookmarkmanager.moc" diff --git a/kio/bookmarks/kbookmarkmanager.h b/kio/bookmarks/kbookmarkmanager.h new file mode 100644 index 000000000..03d0ac0c6 --- /dev/null +++ b/kio/bookmarks/kbookmarkmanager.h @@ -0,0 +1,367 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __kbookmarkmanager_h +#define __kbookmarkmanager_h + +#include <qstring.h> +#include <qstringlist.h> +#include <qobject.h> +#include <qdom.h> +#include <dcopobject.h> +#include "kbookmark.h" +#include "kbookmarknotifier.h" + +/** + * This class implements the reading/writing of bookmarks in XML. + * The bookmarks file is read and written using the XBEL standard + * (http://pyxml.sourceforge.net/topics/xbel/) + * + * A sample file looks like this : + * \code + * <xbel> + * <bookmark href="http://developer.kde.org"><title>Developer Web Site</title></bookmark> + * <folder folded="no"> + * <title>Title of this folder</title> + * <bookmark icon="kde" href="http://www.kde.org"><title>KDE Web Site</title></bookmark> + * <folder toolbar="yes"> + * <title>My own bookmarks</title> + * <bookmark href="http://www.koffice.org"><title>KOffice Web Site</title></bookmark> + * <separator/> + * <bookmark href="http://www.kdevelop.org"><title>KDevelop Web Site</title></bookmark> + * </folder> + * </folder> + * </xbel> + * \endcode + */ +class KIO_EXPORT KBookmarkManager : public QObject, public DCOPObject +{ + Q_OBJECT + K_DCOP +protected: + /** + * Creates a bookmark manager with a path to the bookmarks. By + * default, it will use the KDE standard dirs to find and create the + * correct location. If you are using your own app-specific + * bookmarks directory, you must instantiate this class with your + * own path <em>before</em> KBookmarkManager::managerForFile() is ever + * called. + * + * @param bookmarksFile full path to the bookmarks file, + * Use ~/.kde/share/apps/konqueror/bookmarks.xml for the konqueror bookmarks + * + * @param bImportDesktopFiles if true, and if the bookmarksFile + * doesn't already exist, import bookmarks from desktop files + */ + KBookmarkManager( const QString & bookmarksFile, bool bImportDesktopFiles = true ); + + /** + * @since 3.2 + */ + KBookmarkManager(); + +public: + /** + * Destructor + */ + ~KBookmarkManager(); + + /** + * Set the update flag. Defaults to true. TODO - check + * @param update if true then KBookmarkManager will listen to DCOP update requests. + */ + void setUpdate( bool update ); + + /** + * Save the bookmarks to the default konqueror XML file on disk. + * You should use emitChanged() instead of this function, it saves + * and notifies everyone that the file has changed. + * @param toolbarCache iff true save a cache of the toolbar folder, too + * @return true if saving was successful + */ + bool save( bool toolbarCache = true ) const; + + /** + * Save the bookmarks to the given XML file on disk. + * @param filename full path to the desired bookmarks file location + * @param toolbarCache iff true save a cache of the toolbar folder, too + * @return true if saving was successful + */ + bool saveAs( const QString & filename, bool toolbarCache = true ) const; + + /** + * Update access time stamps for a given url. + * @param url the viewed url + * @param emitSignal iff true emit KBookmarkNotifier signal + * @since 3.2 + * @return true if any metadata was modified (bookmarks file is not saved automatically) + */ + bool updateAccessMetadata( const QString &url, bool emitSignal = true ); + + /* + * NB. currently *unimplemented* + * + * Update favicon url for a given url. + * @param url the viewed url + * @param faviconurl the favicion url + * @emitSignal iff true emit KBookmarkNotifier signal + * @since 3.3 + */ + void updateFavicon( const QString &url, const QString &faviconurl, bool emitSignal = true ); + + /** + * This will return the path that this manager is using to read + * the bookmarks. + * @internal + * @return the path containing the bookmarks + */ + QString path() { return m_bookmarksFile; } + + /** + * This will return the root bookmark. It is used to iterate + * through the bookmarks manually. It is mostly used internally. + * + * @return the root (top-level) bookmark + */ + KBookmarkGroup root() const; + + /** + * This returns the root of the toolbar menu. + * In the XML, this is the group with the attribute TOOLBAR=1 + * + * @return the toolbar group + */ + KBookmarkGroup toolbar(); + + /** + * @return the bookmark designated by @p address + * @param address the address belonging to the bookmark you're looking for + * @param tolerate when true tries to find the most tolerable bookmark position + * @see KBookmark::address + */ + KBookmark findByAddress( const QString & address, bool tolerate = false ); + + /** + * Saves the bookmark file and notifies everyone. + * @param group the parent of all changed bookmarks + */ + void emitChanged( KBookmarkGroup & group ); + + void emitConfigChanged(); + + /** + * @return true if the NS bookmarks should be dynamically shown + * in the toplevel kactionmenu + * @deprecated + */ + bool showNSBookmarks() const; + + /** + * Shows an extra menu for NS bookmarks. Set this to false, if you don't + * want this. + */ + void setShowNSBookmarks( bool show ); + + /** + * Set options with which slotEditBookmarks called keditbookmarks + * this can be used to change the appearance of the keditbookmarks + * in order to provide a slightly differing outer shell depending + * on the bookmarks file / app which calls it. + * @param caption the --caption string, for instance "Konsole" + * @param browser iff false display no browser specific + * menu items in keditbookmarks :: --nobrowser + * @since 3.2 + */ + void setEditorOptions( const QString& caption, bool browser ); + + /** + * This static function will return an instance of the + * KBookmarkManager, responsible for the given @p bookmarksFile. + * If you do not instantiate this class either + * natively or in a derived class, then it will return an object + * with the default behaviors. If you wish to use different + * behaviors, you <em>must</em> derive your own class and + * instantiate it before this method is ever called. + * + * @param bookmarksFile full path to the bookmarks file, + * Use ~/.kde/share/apps/konqueror/bookmarks.xml for the konqueror bookmarks + * + * @param bImportDesktopFiles if true, and if the bookmarksFile + * doesn't already exist, import bookmarks from desktop files + * @return a pointer to an instance of the KBookmarkManager. + */ + static KBookmarkManager* managerForFile( const QString& bookmarksFile, + bool bImportDesktopFiles = true ); + + + static KBookmarkManager* createTempManager(); + + /** + * Returns a pointer to the users main bookmark collection. + * @since 3.2 + */ + static KBookmarkManager* userBookmarksManager(); + + /** + * Returns the path to the user's main bookmark collection file. + * @since 3.5.5 + */ + static QString userBookmarksFile(); + + /** + * @internal + */ + const QDomDocument & internalDocument() const; + + /** + * Access to bookmark notifier, for emitting signals. + * We need this object to exist in one instance only, so we could + * connectDCOP to it by name. + */ + KBookmarkNotifier& notifier() { return m_notifier; } + + /** + * @since 3.2 + */ + KBookmarkGroup addBookmarkDialog( const QString & _url, const QString & _title, + const QString & _parentBookmarkAddress = QString::null ); + +public slots: + void slotEditBookmarks(); + void slotEditBookmarksAtAddress( const QString& address ); + +public: +k_dcop: + /** + * Reparse the whole bookmarks file and notify about the change + * (Called by the bookmark editor) + */ + ASYNC notifyCompleteChange( QString caller ); + + /** + * Emit the changed signal for the group whose address is given + * @see KBookmark::address() + * Called by the instance of konqueror that saved the file after + * a small change (new bookmark or new folder). + */ + ASYNC notifyChanged( QString groupAddress ); + + ASYNC notifyConfigChanged(); + +signals: + /** + * Signals that the group (or any of its children) with the address + * @p groupAddress (e.g. "/4/5") + * has been modified by the caller @p caller. + */ + void changed( const QString & groupAddress, const QString & caller ); + +protected: + // consts added to avoid a copy-and-paste of internalDocument + void parse() const; + void importDesktopFiles(); + static void convertToXBEL( QDomElement & group ); + static void convertAttribute( QDomElement elem, const QString & oldName, const QString & newName ); + +private: + KBookmarkNotifier m_notifier; + QString m_bookmarksFile; + mutable QDomDocument m_doc; + mutable QDomDocument m_toolbarDoc; + mutable bool m_docIsLoaded; + bool m_update; + static QPtrList<KBookmarkManager>* s_pSelf; + bool m_showNSBookmarks; + +private: + class KBookmarkManagerPrivate* dptr() const; +}; + +/** + * The KBookmarkMenu and KBookmarkBar classes gives the user + * the ability to either edit bookmarks or add their own. In the + * first case, the app may want to open the bookmark in a special way. + * In the second case, the app <em>must</em> supply the name and the + * URL for the bookmark. + * + * This class gives the app this callback-like ability. + * + * If your app does not give the user the ability to add bookmarks and + * you don't mind using the default bookmark editor to edit your + * bookmarks, then you don't need to overload this class at all. + * Rather, just use something like: + * + * <CODE> + * bookmarks = new KBookmarkMenu(new KBookmarkOwner(), ...) + * </CODE> + * + * If you wish to use your own editor or allow the user to add + * bookmarks, you must overload this class. + */ +class KIO_EXPORT KBookmarkOwner +{ +public: + /** + * This function is called if the user selects a bookmark. It will + * open up the bookmark in a default fashion unless you override it. + */ + virtual void openBookmarkURL(const QString& _url); + + /** + * This function is called whenever the user wants to add the + * current page to the bookmarks list. The title will become the + * "name" of the bookmark. You must overload this function if you + * wish to give your users the ability to add bookmarks. + * + * @return the title of the current page. + */ + virtual QString currentTitle() const { return QString::null; } + + /** + * This function is called whenever the user wants to add the + * current page to the bookmarks list. The URL will become the URL + * of the bookmark. You must overload this function if you wish to + * give your users the ability to add bookmarks. + * + * @return the URL of the current page. + */ + virtual QString currentURL() const { return QString::null; } + +protected: + virtual void virtual_hook( int id, void* data ); +}; + +/** + * @since 3.2 + */ +class KIO_EXPORT KExtendedBookmarkOwner : public QObject, virtual public KBookmarkOwner +{ + Q_OBJECT +public: + typedef QValueList<QPair<QString,QString> > QStringPairList; +public slots: + void fillBookmarksList( KExtendedBookmarkOwner::QStringPairList & list ) { emit signalFillBookmarksList( list ); }; +signals: + void signalFillBookmarksList( KExtendedBookmarkOwner::QStringPairList & list ); +private: + class KExtendedBookmarkOwnerPrivate; + KExtendedBookmarkOwnerPrivate *d; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkmenu.cc b/kio/bookmarks/kbookmarkmenu.cc new file mode 100644 index 000000000..0e1dfe35c --- /dev/null +++ b/kio/bookmarks/kbookmarkmenu.cc @@ -0,0 +1,1187 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kbookmarkmenu.h" +#include "kbookmarkmenu_p.h" +#include "kbookmarkimporter.h" +#include "kbookmarkimporter_opera.h" +#include "kbookmarkimporter_ie.h" +#include "kbookmarkdrag.h" + +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kstdaccel.h> +#include <kstdaction.h> +#include <kstringhandler.h> + +#include <qclipboard.h> +#include <qfile.h> +#include <qheader.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qpushbutton.h> + +#include <dptrtemplate.h> + +template class QPtrList<KBookmarkMenu>; + +static QString makeTextNodeMod(KBookmark bk, const QString &m_nodename, const QString &m_newText) { + QDomNode subnode = bk.internalElement().namedItem(m_nodename); + if (subnode.isNull()) { + subnode = bk.internalElement().ownerDocument().createElement(m_nodename); + bk.internalElement().appendChild(subnode); + } + + if (subnode.firstChild().isNull()) { + QDomText domtext = subnode.ownerDocument().createTextNode(""); + subnode.appendChild(domtext); + } + + QDomText domtext = subnode.firstChild().toText(); + + QString m_oldText = domtext.data(); + domtext.setData(m_newText); + + return m_oldText; +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +KBookmarkMenu::KBookmarkMenu( KBookmarkManager* mgr, + KBookmarkOwner * _owner, KPopupMenu * _parentMenu, + KActionCollection *collec, bool _isRoot, bool _add, + const QString & parentAddress ) + : QObject(), + m_bIsRoot(_isRoot), m_bAddBookmark(_add), + m_bAddShortcuts(true), + m_pManager(mgr), m_pOwner(_owner), + m_parentMenu( _parentMenu ), + m_actionCollection( collec ), + m_parentAddress( parentAddress ) +{ + m_parentMenu->setKeyboardShortcutsEnabled( true ); + + m_lstSubMenus.setAutoDelete( true ); + m_actions.setAutoDelete( true ); + + if (m_actionCollection) + { + m_actionCollection->setHighlightingEnabled(true); + disconnect( m_actionCollection, SIGNAL( actionHighlighted( KAction * ) ), 0, 0 ); + connect( m_actionCollection, SIGNAL( actionHighlighted( KAction * ) ), + this, SLOT( slotActionHighlighted( KAction * ) ) ); + } + + m_bNSBookmark = m_parentAddress.isNull(); + if ( !m_bNSBookmark ) // not for the netscape bookmark + { + //kdDebug(7043) << "KBookmarkMenu::KBookmarkMenu " << this << " address : " << m_parentAddress << endl; + + connect( _parentMenu, SIGNAL( aboutToShow() ), + SLOT( slotAboutToShow() ) ); + + if ( KBookmarkSettings::self()->m_contextmenu ) + { + (void) _parentMenu->contextMenu(); + connect( _parentMenu, SIGNAL( aboutToShowContextMenu(KPopupMenu*, int, QPopupMenu*) ), + this, SLOT( slotAboutToShowContextMenu(KPopupMenu*, int, QPopupMenu*) )); + } + + if ( m_bIsRoot ) + { + connect( m_pManager, SIGNAL( changed(const QString &, const QString &) ), + SLOT( slotBookmarksChanged(const QString &) ) ); + } + } + + // add entries that possibly have a shortcut, so they are available _before_ first popup + if ( m_bIsRoot ) + { + if ( m_bAddBookmark ) + { + addAddBookmark(); + if ( extOwner() ) + addAddBookmarksList(); // FIXME + } + + addEditBookmarks(); + } + + m_bDirty = true; +} + +KBookmarkMenu::~KBookmarkMenu() +{ + //kdDebug(7043) << "KBookmarkMenu::~KBookmarkMenu() " << this << endl; + QPtrListIterator<KAction> it( m_actions ); + for (; it.current(); ++it ) + it.current()->unplugAll(); + + m_lstSubMenus.clear(); + m_actions.clear(); +} + +void KBookmarkMenu::ensureUpToDate() +{ + slotAboutToShow(); +} + +void KBookmarkMenu::slotAboutToShow() +{ + // Did the bookmarks change since the last time we showed them ? + if ( m_bDirty ) + { + m_bDirty = false; + refill(); + } +} + +QString KBookmarkMenu::s_highlightedAddress; +QString KBookmarkMenu::s_highlightedImportType; +QString KBookmarkMenu::s_highlightedImportLocation; + +void KBookmarkMenu::slotActionHighlighted( KAction* action ) +{ + if (action->isA("KBookmarkActionMenu") || action->isA("KBookmarkAction")) + { + s_highlightedAddress = action->property("address").toString(); + //kdDebug() << "KBookmarkMenu::slotActionHighlighted" << s_highlightedAddress << endl; + } + else if (action->isA("KImportedBookmarksActionMenu")) + { + s_highlightedImportType = action->property("type").toString(); + s_highlightedImportLocation = action->property("location").toString(); + } + else + { + s_highlightedAddress = QString::null; + s_highlightedImportType = QString::null; + s_highlightedImportLocation = QString::null; + } +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +class KBookmarkMenuRMBAssoc : public dPtrTemplate<KBookmarkMenu, RMB> { }; +template<> QPtrDict<RMB>* dPtrTemplate<KBookmarkMenu, RMB>::d_ptr = 0; + +static RMB* rmbSelf(KBookmarkMenu *m) { return KBookmarkMenuRMBAssoc::d(m); } + +// TODO check via dcop before making any changes to the bookmarks file??? + +void RMB::begin_rmb_action(KBookmarkMenu *self) +{ + RMB *s = rmbSelf(self); + s->recv = self; + s->m_parentAddress = self->m_parentAddress; + s->s_highlightedAddress = KBookmarkMenu::s_highlightedAddress; + s->m_pManager = self->m_pManager; + s->m_pOwner = self->m_pOwner; + s->m_parentMenu = self->m_parentMenu; +} + +bool RMB::invalid( int val ) +{ + bool valid = true; + + if (val == 1) + s_highlightedAddress = m_parentAddress; + + if (s_highlightedAddress.isNull()) + valid = false; + + return !valid; +} + +KBookmark RMB::atAddress(const QString & address) +{ + KBookmark bookmark = m_pManager->findByAddress( address ); + Q_ASSERT(!bookmark.isNull()); + return bookmark; +} + +void KBookmarkMenu::slotAboutToShowContextMenu( KPopupMenu*, int, QPopupMenu* contextMenu ) +{ + //kdDebug(7043) << "KBookmarkMenu::slotAboutToShowContextMenu" << s_highlightedAddress << endl; + if (s_highlightedAddress.isNull()) + { + KPopupMenu::contextMenuFocus()->hideContextMenu(); + return; + } + contextMenu->clear(); + fillContextMenu( contextMenu, s_highlightedAddress, 0 ); +} + +void RMB::fillContextMenu( QPopupMenu* contextMenu, const QString & address, int val ) +{ + KBookmark bookmark = atAddress(address); + + int id; + + // binner: + // "Add Bookmark Here" when pointing at a bookmark looks strange and if you + // call it you have to close and reopen the menu to see an entry was added? + // + // TODO rename these, but, message freeze... umm... + +// if (bookmark.isGroup()) { + id = contextMenu->insertItem( SmallIcon("bookmark_add"), i18n( "Add Bookmark Here" ), recv, SLOT(slotRMBActionInsert(int)) ); + contextMenu->setItemParameter( id, val ); +/* } + else + { + id = contextMenu->insertItem( SmallIcon("bookmark_add"), i18n( "Add Bookmark Here" ), recv, SLOT(slotRMBActionInsert(int)) ); + contextMenu->setItemParameter( id, val ); + }*/ +} + +void RMB::fillContextMenu2( QPopupMenu* contextMenu, const QString & address, int val ) +{ + KBookmark bookmark = atAddress(address); + + int id; + + if (bookmark.isGroup()) { + id = contextMenu->insertItem( i18n( "Open Folder in Bookmark Editor" ), recv, SLOT(slotRMBActionEditAt(int)) ); + contextMenu->setItemParameter( id, val ); + contextMenu->insertSeparator(); + id = contextMenu->insertItem( SmallIcon("editdelete"), i18n( "Delete Folder" ), recv, SLOT(slotRMBActionRemove(int)) ); + contextMenu->setItemParameter( id, val ); + contextMenu->insertSeparator(); + id = contextMenu->insertItem( i18n( "Properties" ), recv, SLOT(slotRMBActionProperties(int)) ); + contextMenu->setItemParameter( id, val ); + } + else + { + id = contextMenu->insertItem( i18n( "Copy Link Address" ), recv, SLOT(slotRMBActionCopyLocation(int)) ); + contextMenu->setItemParameter( id, val ); + contextMenu->insertSeparator(); + id = contextMenu->insertItem( SmallIcon("editdelete"), i18n( "Delete Bookmark" ), recv, SLOT(slotRMBActionRemove(int)) ); + contextMenu->setItemParameter( id, val ); + contextMenu->insertSeparator(); + id = contextMenu->insertItem( i18n( "Properties" ), recv, SLOT(slotRMBActionProperties(int)) ); + contextMenu->setItemParameter( id, val ); + } +} + +void RMB::slotRMBActionEditAt( int val ) +{ + kdDebug(7043) << "KBookmarkMenu::slotRMBActionEditAt" << s_highlightedAddress << endl; + if (invalid(val)) { hidePopup(); return; } + + KBookmark bookmark = atAddress(s_highlightedAddress); + + m_pManager->slotEditBookmarksAtAddress( s_highlightedAddress ); +} + +void RMB::slotRMBActionProperties( int val ) +{ + kdDebug(7043) << "KBookmarkMenu::slotRMBActionProperties" << s_highlightedAddress << endl; + if (invalid(val)) { hidePopup(); return; } + + KBookmark bookmark = atAddress(s_highlightedAddress); + + QString folder = bookmark.isGroup() ? QString::null : bookmark.url().pathOrURL(); + KBookmarkEditDialog dlg( bookmark.fullText(), folder, + m_pManager, KBookmarkEditDialog::ModifyMode, 0, + 0, 0, i18n("Bookmark Properties") ); + if ( dlg.exec() != KDialogBase::Accepted ) + return; + + makeTextNodeMod(bookmark, "title", dlg.finalTitle()); + if ( !dlg.finalUrl().isNull() ) + { + KURL u = KURL::fromPathOrURL(dlg.finalUrl()); + bookmark.internalElement().setAttribute("href", u.url(0, 106)); + } + + kdDebug(7043) << "Requested move to " << dlg.finalAddress() << "!" << endl; + + KBookmarkGroup parentBookmark = atAddress(m_parentAddress).toGroup(); + m_pManager->emitChanged( parentBookmark ); +} + +void RMB::slotRMBActionInsert( int val ) +{ + kdDebug(7043) << "KBookmarkMenu::slotRMBActionInsert" << s_highlightedAddress << endl; + if (invalid(val)) { hidePopup(); return; } + + QString url = m_pOwner->currentURL(); + if (url.isEmpty()) + { + KMessageBox::error( 0L, i18n("Cannot add bookmark with empty URL.")); + return; + } + QString title = m_pOwner->currentTitle(); + if (title.isEmpty()) + title = url; + + KBookmark bookmark = atAddress( s_highlightedAddress ); + + // TODO use unique title + + if (bookmark.isGroup()) + { + KBookmarkGroup parentBookmark = bookmark.toGroup(); + Q_ASSERT(!parentBookmark.isNull()); + parentBookmark.addBookmark( m_pManager, title, KURL( url ) ); + m_pManager->emitChanged( parentBookmark ); + } + else + { + KBookmarkGroup parentBookmark = bookmark.parentGroup(); + Q_ASSERT(!parentBookmark.isNull()); + KBookmark newBookmark = parentBookmark.addBookmark( m_pManager, title, KURL( url ) ); + parentBookmark.moveItem( newBookmark, parentBookmark.previous(bookmark) ); + m_pManager->emitChanged( parentBookmark ); + } +} + +void RMB::slotRMBActionRemove( int val ) +{ + //kdDebug(7043) << "KBookmarkMenu::slotRMBActionRemove" << s_highlightedAddress << endl; + if (invalid(val)) { hidePopup(); return; } + + KBookmark bookmark = atAddress( s_highlightedAddress ); + bool folder = bookmark.isGroup(); + + if (KMessageBox::warningContinueCancel( + m_parentMenu, + folder ? i18n("Are you sure you wish to remove the bookmark folder\n\"%1\"?").arg(bookmark.text()) + : i18n("Are you sure you wish to remove the bookmark\n\"%1\"?").arg(bookmark.text()), + folder ? i18n("Bookmark Folder Deletion") + : i18n("Bookmark Deletion"), + KStdGuiItem::del()) + != KMessageBox::Continue + ) + return; + + KBookmarkGroup parentBookmark = atAddress( m_parentAddress ).toGroup(); + parentBookmark.deleteBookmark( bookmark ); + m_pManager->emitChanged( parentBookmark ); + if (m_parentMenu) + m_parentMenu->hide(); +} + +void RMB::slotRMBActionCopyLocation( int val ) +{ + //kdDebug(7043) << "KBookmarkMenu::slotRMBActionCopyLocation" << s_highlightedAddress << endl; + if (invalid(val)) { hidePopup(); return; } + + KBookmark bookmark = atAddress( s_highlightedAddress ); + + if ( !bookmark.isGroup() ) + { + kapp->clipboard()->setData( KBookmarkDrag::newDrag(bookmark, 0), + QClipboard::Selection ); + kapp->clipboard()->setData( KBookmarkDrag::newDrag(bookmark, 0), + QClipboard::Clipboard ); + } +} + +void RMB::hidePopup() { + KPopupMenu::contextMenuFocus()->hideContextMenu(); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +void KBookmarkMenu::fillContextMenu( QPopupMenu* contextMenu, const QString & address, int val ) +{ + RMB::begin_rmb_action(this); + rmbSelf(this)->fillContextMenu(contextMenu, address, val); + emit aboutToShowContextMenu( rmbSelf(this)->atAddress(address), contextMenu); + rmbSelf(this)->fillContextMenu2(contextMenu, address, val); +} + +void KBookmarkMenu::slotRMBActionEditAt( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); } + +void KBookmarkMenu::slotRMBActionProperties( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); } + +void KBookmarkMenu::slotRMBActionInsert( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); } + +void KBookmarkMenu::slotRMBActionRemove( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); } + +void KBookmarkMenu::slotRMBActionCopyLocation( int val ) +{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); } + +void KBookmarkMenu::slotBookmarksChanged( const QString & groupAddress ) +{ + if (m_bNSBookmark) + return; + + if ( groupAddress == m_parentAddress ) + { + //kdDebug(7043) << "KBookmarkMenu::slotBookmarksChanged -> setting m_bDirty on " << groupAddress << endl; + m_bDirty = true; + } + else + { + // Iterate recursively into child menus + QPtrListIterator<KBookmarkMenu> it( m_lstSubMenus ); + for (; it.current(); ++it ) + { + it.current()->slotBookmarksChanged( groupAddress ); + } + } +} + +void KBookmarkMenu::refill() +{ + //kdDebug(7043) << "KBookmarkMenu::refill()" << endl; + m_lstSubMenus.clear(); + + QPtrListIterator<KAction> it( m_actions ); + for (; it.current(); ++it ) + it.current()->unplug( m_parentMenu ); + + m_parentMenu->clear(); + m_actions.clear(); + + fillBookmarkMenu(); + m_parentMenu->adjustSize(); +} + +void KBookmarkMenu::addAddBookmarksList() +{ + if (!kapp->authorizeKAction("bookmarks")) + return; + + QString title = i18n( "Bookmark Tabs as Folder..." ); + + KAction * paAddBookmarksList = new KAction( title, + "bookmarks_list_add", + 0, + this, + SLOT( slotAddBookmarksList() ), + m_actionCollection, m_bIsRoot ? "add_bookmarks_list" : 0 ); + + paAddBookmarksList->setToolTip( i18n( "Add a folder of bookmarks for all open tabs." ) ); + + paAddBookmarksList->plug( m_parentMenu ); + m_actions.append( paAddBookmarksList ); +} + +void KBookmarkMenu::addAddBookmark() +{ + if (!kapp->authorizeKAction("bookmarks")) + return; + + QString title = i18n( "Add Bookmark" ); + + KAction * paAddBookmarks = new KAction( title, + "bookmark_add", + m_bIsRoot && m_bAddShortcuts ? KStdAccel::addBookmark() : KShortcut(), + this, + SLOT( slotAddBookmark() ), + m_actionCollection, m_bIsRoot ? "add_bookmark" : 0 ); + + paAddBookmarks->setToolTip( i18n( "Add a bookmark for the current document" ) ); + + paAddBookmarks->plug( m_parentMenu ); + m_actions.append( paAddBookmarks ); +} + +void KBookmarkMenu::addEditBookmarks() +{ + if (!kapp->authorizeKAction("bookmarks")) + return; + + KAction * m_paEditBookmarks = KStdAction::editBookmarks( m_pManager, SLOT( slotEditBookmarks() ), + m_actionCollection, "edit_bookmarks" ); + m_paEditBookmarks->plug( m_parentMenu ); + m_paEditBookmarks->setToolTip( i18n( "Edit your bookmark collection in a separate window" ) ); + m_actions.append( m_paEditBookmarks ); +} + +void KBookmarkMenu::addNewFolder() +{ + if (!kapp->authorizeKAction("bookmarks")) + return; + + QString title = i18n( "&New Bookmark Folder..." ); + int p; + while ( ( p = title.find( '&' ) ) >= 0 ) + title.remove( p, 1 ); + + KAction * paNewFolder = new KAction( title, + "folder_new", //"folder", + 0, + this, + SLOT( slotNewFolder() ), + m_actionCollection ); + + paNewFolder->setToolTip( i18n( "Create a new bookmark folder in this menu" ) ); + + paNewFolder->plug( m_parentMenu ); + m_actions.append( paNewFolder ); +} + +void KBookmarkMenu::fillBookmarkMenu() +{ + if (!kapp->authorizeKAction("bookmarks")) + return; + + if ( m_bIsRoot ) + { + if ( m_bAddBookmark ) + { + addAddBookmark(); + if ( extOwner() ) + addAddBookmarksList(); // FIXME + } + + addEditBookmarks(); + + if ( m_bAddBookmark && !KBookmarkSettings::self()->m_advancedaddbookmark ) + addNewFolder(); + } + + if ( m_bIsRoot + && KBookmarkManager::userBookmarksFile() == m_pManager->path() ) + { + bool haveSep = false; + + QValueList<QString> keys = KBookmarkMenu::dynamicBookmarksList(); + QValueList<QString>::const_iterator it; + for ( it = keys.begin(); it != keys.end(); ++it ) + { + DynMenuInfo info; + info = showDynamicBookmarks((*it)); + + if ( !info.show || !QFile::exists( info.location ) ) + continue; + + if (!haveSep) + { + m_parentMenu->insertSeparator(); + haveSep = true; + } + + KActionMenu * actionMenu; + actionMenu = new KImportedBookmarksActionMenu( + info.name, info.type, + m_actionCollection, "kbookmarkmenu" ); + + actionMenu->setProperty( "type", info.type ); + actionMenu->setProperty( "location", info.location ); + + actionMenu->plug( m_parentMenu ); + m_actions.append( actionMenu ); + + KBookmarkMenu *subMenu = + new KBookmarkMenu( m_pManager, m_pOwner, actionMenu->popupMenu(), + m_actionCollection, false, + m_bAddBookmark, QString::null ); + connect( subMenu, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) ), + this, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) )); + m_lstSubMenus.append(subMenu); + + connect(actionMenu->popupMenu(), SIGNAL(aboutToShow()), subMenu, SLOT(slotNSLoad())); + } + } + + KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup(); + Q_ASSERT(!parentBookmark.isNull()); + bool separatorInserted = false; + for ( KBookmark bm = parentBookmark.first(); !bm.isNull(); bm = parentBookmark.next(bm) ) + { + QString text = KStringHandler::csqueeze(bm.fullText(), 60); + text.replace( '&', "&&" ); + if ( !separatorInserted && m_bIsRoot) { + // inserted before the first konq bookmark, to avoid the separator if no konq bookmark + m_parentMenu->insertSeparator(); + separatorInserted = true; + } + if ( !bm.isGroup() ) + { + if ( bm.isSeparator() ) + { + m_parentMenu->insertSeparator(); + } + else + { + //kdDebug(7043) << "Creating URL bookmark menu item for " << bm.text() << endl; + KAction * action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 ); + connect(action, SIGNAL( activated ( KAction::ActivationReason, Qt::ButtonState )), + this, SLOT( slotBookmarkSelected( KAction::ActivationReason, Qt::ButtonState ) )); + + action->setProperty( "url", bm.url().url() ); + action->setProperty( "address", bm.address() ); + + action->setToolTip( bm.url().pathOrURL() ); + + action->plug( m_parentMenu ); + m_actions.append( action ); + } + } + else + { + //kdDebug(7043) << "Creating bookmark submenu named " << bm.text() << endl; + KActionMenu * actionMenu = new KBookmarkActionMenu( text, bm.icon(), + m_actionCollection, + "kbookmarkmenu" ); + actionMenu->setProperty( "address", bm.address() ); + actionMenu->plug( m_parentMenu ); + m_actions.append( actionMenu ); + + KBookmarkMenu *subMenu = new KBookmarkMenu( m_pManager, m_pOwner, actionMenu->popupMenu(), + m_actionCollection, false, + m_bAddBookmark, + bm.address() ); + + connect(subMenu, SIGNAL( aboutToShowContextMenu( const KBookmark &, QPopupMenu * ) ), + this, SIGNAL( aboutToShowContextMenu( const KBookmark &, QPopupMenu * ) )); + connect(subMenu, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) ), + this, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) )); + m_lstSubMenus.append( subMenu ); + } + } + + if ( !m_bIsRoot && m_bAddBookmark ) + { + if ( m_parentMenu->count() > 0 ) + m_parentMenu->insertSeparator(); + + if ( KBookmarkSettings::self()->m_quickactions ) + { + KActionMenu * actionMenu = new KActionMenu( i18n("Quick Actions"), m_actionCollection, 0L ); + fillContextMenu( actionMenu->popupMenu(), m_parentAddress, 1 ); + actionMenu->plug( m_parentMenu ); + m_actions.append( actionMenu ); + } + else + { + addAddBookmark(); + if ( extOwner() ) + addAddBookmarksList(); // FIXME + addNewFolder(); + } + } +} + +void KBookmarkMenu::slotAddBookmarksList() +{ + KExtendedBookmarkOwner *extOwner = dynamic_cast<KExtendedBookmarkOwner*>(m_pOwner); + if (!extOwner) + { + kdWarning() << "erm, sorry ;-)" << endl; + return; + } + + KExtendedBookmarkOwner::QStringPairList list; + extOwner->fillBookmarksList( list ); + + KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup(); + Q_ASSERT(!parentBookmark.isNull()); + KBookmarkGroup group = parentBookmark.createNewFolder( m_pManager ); + if ( group.isNull() ) + return; // user canceled i guess + + KExtendedBookmarkOwner::QStringPairList::const_iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + group.addBookmark( m_pManager, (*it).first, KURL((*it).second) ); + + m_pManager->emitChanged( parentBookmark ); +} + + +void KBookmarkMenu::slotAddBookmark() +{ + KBookmarkGroup parentBookmark; + parentBookmark = m_pManager->addBookmarkDialog(m_pOwner->currentURL(), m_pOwner->currentTitle(), m_parentAddress); + if (!parentBookmark.isNull()) + m_pManager->emitChanged( parentBookmark ); +} + +void KBookmarkMenu::slotNewFolder() +{ + if ( !m_pOwner ) return; // this view doesn't handle bookmarks... + KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup(); + Q_ASSERT(!parentBookmark.isNull()); + KBookmarkGroup group = parentBookmark.createNewFolder( m_pManager ); + if ( !group.isNull() ) + { + KBookmarkGroup parentGroup = group.parentGroup(); + m_pManager->emitChanged( parentGroup ); + } +} + +void KBookmarkMenu::slotBookmarkSelected( KAction::ActivationReason /*reason*/, Qt::ButtonState state ) +{ + kdDebug(7043) << "KBookmarkMenu::slotBookmarkSelected()" << endl; + if ( !m_pOwner ) return; // this view doesn't handle bookmarks... + const KAction* action = dynamic_cast<const KAction *>(sender()); + if(action) + { + const QString& url = sender()->property("url").toString(); + m_pOwner->openBookmarkURL( url ); + emit openBookmark( url, state ); + } +} + +void KBookmarkMenu::slotBookmarkSelected() +{ + slotBookmarkSelected(KAction::PopupMenuActivation, Qt::NoButton); +} + +KExtendedBookmarkOwner* KBookmarkMenu::extOwner() +{ + return dynamic_cast<KExtendedBookmarkOwner*>(m_pOwner); +} + +void KBookmarkMenu::slotNSLoad() +{ + // only fill menu once + m_parentMenu->disconnect(SIGNAL(aboutToShow())); + + // not NSImporter, but kept old name for BC reasons + KBookmarkMenuNSImporter importer( m_pManager, this, m_actionCollection ); + importer.openBookmarks(s_highlightedImportLocation, s_highlightedImportType); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +KBookmarkEditFields::KBookmarkEditFields(QWidget *main, QBoxLayout *vbox, FieldsSet fieldsSet) +{ + bool isF = (fieldsSet != FolderFieldsSet); + + QGridLayout *grid = new QGridLayout( vbox, 2, isF ? 2 : 1 ); + + m_title = new KLineEdit( main ); + grid->addWidget( m_title, 0, 1 ); + grid->addWidget( new QLabel( m_title, i18n( "Name:" ), main ), 0, 0 ); + m_title->setFocus(); + if (isF) + { + m_url = new KLineEdit( main ); + grid->addWidget( m_url, 1, 1 ); + grid->addWidget( new QLabel( m_url, i18n( "Location:" ), main ), 1, 0 ); + } + else + { + m_url = 0; + } + + main->setMinimumSize( 300, 0 ); +} + +void KBookmarkEditFields::setName(const QString &str) +{ + m_title->setText(str); +} + +void KBookmarkEditFields::setLocation(const QString &str) +{ + m_url->setText(str); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +// TODO - make the dialog use Properties as a title when in Modify mode... (dirk noticed the bug...) +KBookmarkEditDialog::KBookmarkEditDialog(const QString& title, const QString& url, KBookmarkManager * mgr, BookmarkEditType editType, const QString& address, + QWidget * parent, const char * name, const QString& caption ) + : KDialogBase(parent, name, true, caption, + (editType == InsertionMode) ? (User1|Ok|Cancel) : (Ok|Cancel), + Ok, false, KGuiItem()), + m_folderTree(0), m_mgr(mgr), m_editType(editType), m_address(address) +{ + setButtonOK( (editType == InsertionMode) ? KGuiItem( i18n( "&Add" ), "bookmark_add") : i18n( "&Update" ) ); + if (editType == InsertionMode) { + setButtonGuiItem( User1, KGuiItem( i18n( "&New Folder..." ), "folder_new") ); + } + + bool folder = url.isNull(); + + m_main = new QWidget( this ); + setMainWidget( m_main ); + + QBoxLayout *vbox = new QVBoxLayout( m_main, 0, spacingHint() ); + KBookmarkEditFields::FieldsSet fs = + folder ? KBookmarkEditFields::FolderFieldsSet + : KBookmarkEditFields::BookmarkFieldsSet; + m_fields = new KBookmarkEditFields(m_main, vbox, fs); + m_fields->setName(title); + if ( !folder ) + m_fields->setLocation(url); + + if ( editType == InsertionMode ) + { + m_folderTree = KBookmarkFolderTree::createTree( m_mgr, m_main, name, m_address ); + connect( m_folderTree, SIGNAL( doubleClicked(QListViewItem*) ), + this, SLOT( slotDoubleClicked(QListViewItem*) ) ); + vbox->addWidget( m_folderTree ); + connect( this, SIGNAL( user1Clicked() ), SLOT( slotUser1() ) ); + } +} + +void KBookmarkEditDialog::slotDoubleClicked( QListViewItem* item ) +{ + Q_ASSERT( m_folderTree ); + m_folderTree->setCurrentItem( item ); + accept(); +} + +void KBookmarkEditDialog::slotOk() +{ + accept(); +} + +void KBookmarkEditDialog::slotCancel() +{ + reject(); +} + +QString KBookmarkEditDialog::finalAddress() const +{ + Q_ASSERT( m_folderTree ); + return KBookmarkFolderTree::selectedAddress( m_folderTree ); +} + +QString KBookmarkEditDialog::finalUrl() const +{ + return m_fields->m_url ? m_fields->m_url->text() : QString::null; +} + +QString KBookmarkEditDialog::finalTitle() const +{ + return m_fields->m_title ? m_fields->m_title->text() : QString::null; +} + +void KBookmarkEditDialog::slotUser1() +{ + // kdDebug(7043) << "KBookmarkEditDialog::slotUser1" << endl; + Q_ASSERT( m_folderTree ); + + QString address = KBookmarkFolderTree::selectedAddress( m_folderTree ); + if ( address.isNull() ) return; + KBookmarkGroup bm = m_mgr->findByAddress( address ).toGroup(); + Q_ASSERT(!bm.isNull()); + Q_ASSERT(m_editType == InsertionMode); + + KBookmarkGroup group = bm.createNewFolder( m_mgr ); + if ( !group.isNull() ) + { + KBookmarkGroup parentGroup = group.parentGroup(); + m_mgr->emitChanged( parentGroup ); + } + KBookmarkFolderTree::fillTree( m_folderTree, m_mgr ); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +static void fillGroup( QListView* listview, KBookmarkFolderTreeItem * parentItem, KBookmarkGroup group, bool expandOpenGroups = true, const QString& address = QString::null ) +{ + bool noSubGroups = true; + KBookmarkFolderTreeItem * lastItem = 0L; + KBookmarkFolderTreeItem * item = 0L; + for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk) ) + { + if ( bk.isGroup() ) + { + KBookmarkGroup grp = bk.toGroup(); + item = new KBookmarkFolderTreeItem( parentItem, lastItem, grp ); + fillGroup( listview, item, grp, expandOpenGroups, address ); + if ( expandOpenGroups && grp.isOpen() ) + item->setOpen( true ); + lastItem = item; + noSubGroups = false; + } + if (bk.address() == address) { + listview->setCurrentItem( lastItem ); + listview->ensureItemVisible( item ); + } + } + if ( noSubGroups ) { + parentItem->setOpen( true ); + } +} + +QListView* KBookmarkFolderTree::createTree( KBookmarkManager* mgr, QWidget* parent, const char* name, const QString& address ) +{ + QListView *listview = new QListView( parent, name ); + + listview->setRootIsDecorated( false ); + listview->header()->hide(); + listview->addColumn( i18n("Bookmark"), 200 ); + listview->setSorting( -1, false ); + listview->setSelectionMode( QListView::Single ); + listview->setAllColumnsShowFocus( true ); + listview->setResizeMode( QListView::AllColumns ); + listview->setMinimumSize( 60, 100 ); + + fillTree( listview, mgr, address ); + + return listview; +} + +void KBookmarkFolderTree::fillTree( QListView *listview, KBookmarkManager* mgr, const QString& address ) +{ + listview->clear(); + + KBookmarkGroup root = mgr->root(); + KBookmarkFolderTreeItem * rootItem = new KBookmarkFolderTreeItem( listview, root ); + listview->setCurrentItem( rootItem ); + rootItem->setSelected( true ); + fillGroup( listview, rootItem, root, (address == root.groupAddress() || address.isNull()) ? true : false, address ); + rootItem->setOpen( true ); +} + +static KBookmarkFolderTreeItem* ft_cast( QListViewItem *i ) +{ + return static_cast<KBookmarkFolderTreeItem*>( i ); +} + +QString KBookmarkFolderTree::selectedAddress( QListView *listview ) +{ + if ( !listview) + return QString::null; + KBookmarkFolderTreeItem *item = ft_cast( listview->currentItem() ); + return item ? item->m_bookmark.address() : QString::null; +} + +void KBookmarkFolderTree::setAddress( QListView *listview, const QString & address ) +{ + KBookmarkFolderTreeItem* it = ft_cast( listview->firstChild() ); + while ( true ) { + kdDebug(7043) << it->m_bookmark.address() << endl; + it = ft_cast( it->itemBelow() ); + if ( !it ) + return; + if ( it->m_bookmark.address() == address ) + break; + } + it->setSelected( true ); + listview->setCurrentItem( it ); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +// toplevel item +KBookmarkFolderTreeItem::KBookmarkFolderTreeItem( QListView *parent, const KBookmark & gp ) + : QListViewItem(parent, i18n("Bookmarks")), m_bookmark(gp) +{ + setPixmap(0, SmallIcon("bookmark")); + setExpandable(true); +} + +// group +KBookmarkFolderTreeItem::KBookmarkFolderTreeItem( KBookmarkFolderTreeItem *parent, QListViewItem *after, const KBookmarkGroup & gp ) + : QListViewItem(parent, after, gp.fullText()), m_bookmark(gp) +{ + setPixmap(0, SmallIcon( gp.icon() ) ); + setExpandable(true); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +// NOTE - KBookmarkMenuNSImporter is really === KBookmarkMenuImporter +// i.e, it is _not_ ns specific. and in KDE4 it should be renamed. + +void KBookmarkMenuNSImporter::openNSBookmarks() +{ + openBookmarks( KNSBookmarkImporter::netscapeBookmarksFile(), "netscape" ); +} + +void KBookmarkMenuNSImporter::openBookmarks( const QString &location, const QString &type ) +{ + mstack.push(m_menu); + + KBookmarkImporterBase *importer = KBookmarkImporterBase::factory(type); + if (!importer) + return; + importer->setFilename(location); + connectToImporter(*importer); + importer->parse(); + + delete importer; +} + +void KBookmarkMenuNSImporter::connectToImporter(const QObject &importer) +{ + connect( &importer, SIGNAL( newBookmark( const QString &, const QCString &, const QString & ) ), + SLOT( newBookmark( const QString &, const QCString &, const QString & ) ) ); + connect( &importer, SIGNAL( newFolder( const QString &, bool, const QString & ) ), + SLOT( newFolder( const QString &, bool, const QString & ) ) ); + connect( &importer, SIGNAL( newSeparator() ), SLOT( newSeparator() ) ); + connect( &importer, SIGNAL( endFolder() ), SLOT( endFolder() ) ); +} + +void KBookmarkMenuNSImporter::newBookmark( const QString & text, const QCString & url, const QString & ) +{ + QString _text = KStringHandler::csqueeze(text); + _text.replace( '&', "&&" ); + KAction * action = new KBookmarkAction(_text, "html", 0, 0, "", m_actionCollection, 0); + connect(action, SIGNAL( activated ( KAction::ActivationReason, Qt::ButtonState )), + m_menu, SLOT( slotBookmarkSelected( KAction::ActivationReason, Qt::ButtonState ) )); + action->setProperty( "url", url ); + action->setToolTip( url ); + action->plug( mstack.top()->m_parentMenu ); + mstack.top()->m_actions.append( action ); +} + +void KBookmarkMenuNSImporter::newFolder( const QString & text, bool, const QString & ) +{ + QString _text = KStringHandler::csqueeze(text); + _text.replace( '&', "&&" ); + KActionMenu * actionMenu = new KActionMenu( _text, "folder", m_actionCollection, 0L ); + actionMenu->plug( mstack.top()->m_parentMenu ); + mstack.top()->m_actions.append( actionMenu ); + KBookmarkMenu *subMenu = new KBookmarkMenu( m_pManager, m_menu->m_pOwner, actionMenu->popupMenu(), + m_actionCollection, false, + m_menu->m_bAddBookmark, QString::null ); + connect( subMenu, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) ), + m_menu, SIGNAL( openBookmark( const QString &, Qt::ButtonState ) )); + mstack.top()->m_lstSubMenus.append( subMenu ); + + mstack.push(subMenu); +} + +void KBookmarkMenuNSImporter::newSeparator() +{ + mstack.top()->m_parentMenu->insertSeparator(); +} + +void KBookmarkMenuNSImporter::endFolder() +{ + mstack.pop(); +} + +/********************************************************************/ +/********************************************************************/ +/********************************************************************/ + +KBookmarkMenu::DynMenuInfo KBookmarkMenu::showDynamicBookmarks( const QString &id ) +{ + KConfig config("kbookmarkrc", false, false); + config.setGroup("Bookmarks"); + + DynMenuInfo info; + info.show = false; + + if (!config.hasKey("DynamicMenus")) { + // upgrade path + if (id == "netscape") { + KBookmarkManager *manager = KBookmarkManager::userBookmarksManager(); + info.show = manager->root().internalElement().attribute("hide_nsbk") != "yes"; + info.location = KNSBookmarkImporter::netscapeBookmarksFile(); + info.type = "netscape"; + info.name = i18n("Netscape Bookmarks"); + } // else, no show + + } else { + // have new version config + if (config.hasGroup("DynamicMenu-" + id)) { + config.setGroup("DynamicMenu-" + id); + info.show = config.readBoolEntry("Show"); + info.location = config.readPathEntry("Location"); + info.type = config.readEntry("Type"); + info.name = config.readEntry("Name"); + } // else, no show + } + + return info; +} + +QStringList KBookmarkMenu::dynamicBookmarksList() +{ + KConfig config("kbookmarkrc", false, false); + config.setGroup("Bookmarks"); + + QStringList mlist; + if (config.hasKey("DynamicMenus")) + mlist = config.readListEntry("DynamicMenus"); + else + mlist << "netscape"; + + return mlist; +} + +void KBookmarkMenu::setDynamicBookmarks(const QString &id, const DynMenuInfo &newMenu) +{ + KConfig config("kbookmarkrc", false, false); + + // add group unconditionally + config.setGroup("DynamicMenu-" + id); + config.writeEntry("Show", newMenu.show); + config.writePathEntry("Location", newMenu.location); + config.writeEntry("Type", newMenu.type); + config.writeEntry("Name", newMenu.name); + + QStringList elist; + + config.setGroup("Bookmarks"); + if (!config.hasKey("DynamicMenus")) { + if (newMenu.type != "netscape") { + // update from old xbel method to new rc method + // though only if not writing the netscape setting + config.setGroup("DynamicMenu-" "netscape"); + DynMenuInfo xbelSetting; + xbelSetting = showDynamicBookmarks("netscape"); + config.writeEntry("Show", xbelSetting.show); + config.writePathEntry("Location", xbelSetting.location); + config.writeEntry("Type", xbelSetting.type); + config.writeEntry("Name", xbelSetting.name); + } + } else { + elist = config.readListEntry("DynamicMenus"); + } + + // make sure list includes type + config.setGroup("Bookmarks"); + if (elist.contains(id) < 1) { + elist << id; + config.writeEntry("DynamicMenus", elist); + } + + config.sync(); +} + +#include "kbookmarkmenu.moc" +#include "kbookmarkmenu_p.moc" diff --git a/kio/bookmarks/kbookmarkmenu.h b/kio/bookmarks/kbookmarkmenu.h new file mode 100644 index 000000000..0a1ca1f24 --- /dev/null +++ b/kio/bookmarks/kbookmarkmenu.h @@ -0,0 +1,265 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkmenu_h__ +#define __kbookmarkmenu_h__ + +#include <sys/types.h> + +#include <qptrlist.h> +#include <qptrstack.h> +#include <qobject.h> +#include <qlistview.h> + +#include <kdialogbase.h> +#include <klocale.h> +#include <kaction.h> + +#include "kbookmark.h" +#include "kbookmarkmanager.h" + +class QString; +class QPopupMenu; +class QPushButton; +class QListView; +class KLineEdit; +class KBookmark; +class KBookmarkGroup; +class KAction; +class KActionMenu; +class KActionCollection; +class KBookmarkOwner; +class KBookmarkMenu; +class KPopupMenu; + +namespace KIO { class Job; } + +/** + * This class provides a bookmark menu. It is typically used in + * cooperation with KActionMenu but doesn't have to be. + * + * If you use this class by itself, then it will use KDE defaults for + * everything -- the bookmark path, bookmark editor, bookmark launcher.. + * everything. These defaults reside in the classes + * KBookmarkOwner (editing bookmarks) and KBookmarkManager + * (almost everything else). If you wish to change the defaults in + * any way, you must reimplement and instantiate those classes + * <em>before</em> this class is ever called. + * + * Using this class is very simple: + * + * 1) Create a popup menu (either KActionMenu or KPopupMenu will do) + * 2) Instantiate a new KBookmarkMenu object using the above popup + * menu as a parameter + * 3) Insert your (now full) popup menu wherever you wish + * + * Again, if you wish to modify any defaults, the procedure is: + * + * 1a) Reimplement your own KBookmarkOwner + * 1b) Reimplement and instantiate your own KBookmarkManager + */ +class KIO_EXPORT KBookmarkMenu : public QObject +{ + Q_OBJECT + friend class KBookmarkMenuNSImporter; + friend class RMB; +public: + /** + * Fills a bookmark menu + * (one instance of KBookmarkMenu is created for the toplevel menu, + * but also one per submenu). + * + * @param mgr The bookmark manager to use (i.e. for reading and writing) + * @param owner implementation of the KBookmarkOwner callback interface. + * @param parentMenu menu to be filled + * @param collec parent collection for the KActions. + * Only used for other menus than the toplevel one. + * @param root true for the toplevel menu + * @param add true to show the "Add Bookmark" and "New Folder" entries + * @param parentAddress the address of the group containing the items + * that we want to show. + * @see KBookmark::address. + * Be careful : + * A _null_ parentAddress denotes a NS-bookmark menu. + * An _empty_ parentAddress denotes the toplevel bookmark menu + */ + KBookmarkMenu( KBookmarkManager* mgr, + KBookmarkOwner * owner, KPopupMenu * parentMenu, + KActionCollection * collec, bool root, bool add = true, + const QString & parentAddress = "" ); + + ~KBookmarkMenu(); + + /** + * Even if you think you need to use this, you are probably wrong. + * It fills a bookmark menu starting a given KBookmark. + * This is public for KBookmarkBar. + */ + void fillBookmarkMenu(); + + /** + * Call ensureUpToDate() if you need KBookmarkMenu to adjust to its + * final size before it is executed. + **/ + void ensureUpToDate(); + + /** + * Structure used for storing information about + * the dynamic menu setting + * @since 3.2 + */ + // TODO - transform into class + struct DynMenuInfo { + bool show; + QString location; + QString type; + QString name; + class DynMenuInfoPrivate *d; + }; + + /** + * @return dynmenu info block for the given dynmenu name + * @since 3.2 + */ + static DynMenuInfo showDynamicBookmarks( const QString &id ); + + /** + * Shows an extra menu for the given bookmarks file and type. + * Upgrades from option inside XBEL to option in rc file + * on first call of this function. + * @param id the unique identification for the dynamic menu + * @param info a DynMenuInfo struct containing the to be added/modified data + * @since 3.2 + */ + static void setDynamicBookmarks( const QString &id, const DynMenuInfo &info ); + + /** + * @return list of dynamic menu ids + * @since 3.2 + */ + static QStringList dynamicBookmarksList(); + +signals: + void aboutToShowContextMenu( const KBookmark &, QPopupMenu * ); + /** + * @since 3.4 + */ + void openBookmark( const QString& url, Qt::ButtonState state ); + +public slots: // public for bookmark bar + void slotBookmarksChanged( const QString & ); + +protected slots: + void slotAboutToShow(); + void slotAboutToShowContextMenu( KPopupMenu *, int, QPopupMenu * ); + void slotActionHighlighted( KAction * ); + + void slotRMBActionRemove( int ); + void slotRMBActionInsert( int ); + void slotRMBActionCopyLocation( int ); + void slotRMBActionEditAt( int ); + void slotRMBActionProperties( int ); + + void slotBookmarkSelected(); + /** + * @ since 3.4 + */ + void slotBookmarkSelected( KAction::ActivationReason reason, Qt::ButtonState state ); + void slotAddBookmarksList(); + void slotAddBookmark(); + void slotNewFolder(); + + /** + * load Netscape's bookmarks + */ + void slotNSLoad(); + +protected: + KExtendedBookmarkOwner* extOwner(); + void refill(); + void addAddBookmark(); + void addAddBookmarksList(); + void addEditBookmarks(); + void addNewFolder(); + + void fillContextMenu( QPopupMenu *, const QString &, int ); + + bool m_bIsRoot:1; + bool m_bAddBookmark:1; + bool m_bDirty:1; + bool m_bNSBookmark:1; + bool m_bAddShortcuts:1; + + KBookmarkManager * m_pManager; + KBookmarkOwner *m_pOwner; + /** + * The menu in which we plug our actions. + * Supplied in the constructor. + */ + KPopupMenu * m_parentMenu; + /** + * List of our sub menus + */ + QPtrList<KBookmarkMenu> m_lstSubMenus; + KActionCollection * m_actionCollection; + /** + * List of our actions. + */ + QPtrList<KAction> m_actions; + /** + * Parent bookmark for this menu. + */ + QString m_parentAddress; + + // TODO make non static! + static QString s_highlightedAddress; + static QString s_highlightedImportLocation; + static QString s_highlightedImportType; +}; + +/** + * A class connected to KNSBookmarkImporter, to fill KActionMenus. + */ +class KIO_EXPORT KBookmarkMenuNSImporter : public QObject +{ + Q_OBJECT +public: + KBookmarkMenuNSImporter( KBookmarkManager* mgr, KBookmarkMenu * menu, KActionCollection * act ) : + m_menu(menu), m_actionCollection(act), m_pManager(mgr) {} + + void openNSBookmarks(); + void openBookmarks( const QString &location, const QString &type ); + void connectToImporter( const QObject &importer ); + +protected slots: + void newBookmark( const QString & text, const QCString & url, const QString & ); + void newFolder( const QString & text, bool, const QString & ); + void newSeparator(); + void endFolder(); + +protected: + QPtrStack<KBookmarkMenu> mstack; + KBookmarkMenu * m_menu; + KActionCollection * m_actionCollection; + KBookmarkManager* m_pManager; +}; + +#endif diff --git a/kio/bookmarks/kbookmarkmenu_p.h b/kio/bookmarks/kbookmarkmenu_p.h new file mode 100644 index 000000000..1c3f15ba8 --- /dev/null +++ b/kio/bookmarks/kbookmarkmenu_p.h @@ -0,0 +1,224 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE project + Copyright (C) 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarkmenu_p_h__ +#define __kbookmarkmenu_p_h__ + +#include <sys/types.h> + +#include <qptrlist.h> +#include <qptrstack.h> +#include <qobject.h> +#include <qlistview.h> + +#include <kdialogbase.h> +#include <klocale.h> +#include <kaction.h> + +#include "kbookmark.h" +#include "kbookmarkimporter.h" +#include "kbookmarkmanager.h" + +class QString; +class QPopupMenu; +class QPushButton; +class QListView; +class KLineEdit; +class KBookmark; +class KBookmarkGroup; +class KAction; +class KActionMenu; +class KActionCollection; +class KBookmarkOwner; +class KBookmarkMenu; +class KBookmarkBar; +class KPopupMenu; + +class KImportedBookmarksActionMenu : public KActionMenu { + Q_OBJECT + Q_PROPERTY( QString type READ type WRITE setType ) + Q_PROPERTY( QString location READ location WRITE setLocation ) +public: + const QString type() const { return m_type; } + void setType(const QString &type) { m_type = type; } + const QString location() const { return m_location; } + void setLocation(const QString &location) { m_location = location; } +private: + QString m_type; + QString m_location; +public: + KImportedBookmarksActionMenu( + const QString &text, const QString& sIconName, + KActionCollection* parent, const char* name) + : KActionMenu(text, sIconName, parent, name) { + ; + } +}; + +class KBookmarkActionMenu : public KActionMenu { + Q_OBJECT + Q_PROPERTY( QString url READ url WRITE setUrl ) + Q_PROPERTY( QString address READ address WRITE setAddress ) + Q_PROPERTY( bool readOnly READ readOnly WRITE setReadOnly ) +public: + const QString url() const { return m_url; } + void setUrl(const QString &url) { m_url = url; } + const QString address() const { return m_address; } + void setAddress(const QString &address) { m_address = address; } + bool readOnly() const { return m_readOnly; } + void setReadOnly(bool readOnly) { m_readOnly = readOnly; } +private: + QString m_url; + QString m_address; + bool m_readOnly; +public: + KBookmarkActionMenu( + const QString &text, const QString& sIconName, + KActionCollection* parent, const char* name) + : KActionMenu(text, sIconName, parent, name) { + ; + } +}; + +class KBookmarkAction : public KAction { + Q_OBJECT + Q_PROPERTY( QString url READ url WRITE setUrl ) + Q_PROPERTY( QString address READ address WRITE setAddress ) +public: + const QString url() const { return m_url; } + void setUrl(const QString &url) { m_url = url; } + const QString address() const { return m_address; } + void setAddress(const QString &address) { m_address = address; } +private: + QString m_url; + QString m_address; +public: + // KDE4: remove + KBookmarkAction( + const QString& text, const QString& sIconName, const KShortcut& cut, + const QObject* receiver, const char* slot, + KActionCollection* parent, const char* name) + : KAction(text, sIconName, cut, receiver, slot, parent, name) { + } + KBookmarkAction( + const QString& text, const QString& sIconName, const KShortcut& cut, + KActionCollection* parent, const char* name) + : KAction(text, sIconName, cut, parent, name) { + } +}; + +class KBookmarkEditFields { +public: + typedef enum { FolderFieldsSet, BookmarkFieldsSet } FieldsSet; + KLineEdit * m_url; + KLineEdit * m_title; + KBookmarkEditFields(QWidget *main, QBoxLayout *vbox, FieldsSet isFolder); + void setName(const QString &str); + void setLocation(const QString &str); +}; + +class KBookmarkEditDialog : public KDialogBase +{ + Q_OBJECT + +public: + typedef enum { ModifyMode, InsertionMode } BookmarkEditType; + + KBookmarkEditDialog( const QString& title, const QString& url, KBookmarkManager *, BookmarkEditType editType, const QString& address = QString::null, + QWidget * = 0, const char * = 0, const QString& caption = i18n( "Add Bookmark" ) ); + + QString finalUrl() const; + QString finalTitle() const; + QString finalAddress() const; + +protected slots: + void slotOk(); + void slotCancel(); + void slotUser1(); + void slotDoubleClicked(QListViewItem* item); + +private: + QWidget * m_main; + KBookmarkEditFields * m_fields; + QListView * m_folderTree; + QPushButton * m_button; + KBookmarkManager * m_mgr; + BookmarkEditType m_editType; + QString m_address; +}; + +class KBookmarkFolderTreeItem : public QListViewItem +{ + // make this an accessor + friend class KBookmarkFolderTree; +public: + KBookmarkFolderTreeItem( QListView *, const KBookmark & ); + KBookmarkFolderTreeItem( KBookmarkFolderTreeItem *, QListViewItem *, const KBookmarkGroup & ); +private: + KBookmark m_bookmark; +}; + +class KBookmarkFolderTree +{ +public: + static QListView* createTree( KBookmarkManager *, QWidget * = 0, const char * = 0, const QString& = QString::null ); + static void fillTree( QListView*, KBookmarkManager *, const QString& = QString::null ); + static QString selectedAddress( QListView* ); + static void setAddress( QListView *, const QString & ); +}; + +class KBookmarkSettings +{ +public: + bool m_advancedaddbookmark; + bool m_contextmenu; + bool m_quickactions; + bool m_filteredtoolbar; + static KBookmarkSettings *s_self; + static void readSettings(); + static KBookmarkSettings *self(); +}; + +class RMB +{ +public: + static void begin_rmb_action(KBookmarkMenu *); + static void begin_rmb_action(KBookmarkBar *); + bool invalid( int val ); + KBookmark atAddress(const QString & address); + void fillContextMenu( QPopupMenu* contextMenu, const QString & address, int val ); + void fillContextMenu2( QPopupMenu* contextMenu, const QString & address, int val ); + void slotRMBActionEditAt( int val ); + void slotRMBActionProperties( int val ); + void slotRMBActionInsert( int val ); + void slotRMBActionRemove( int val ); + void slotRMBActionCopyLocation( int val ); + void hidePopup(); +public: + QObject *recv; + KBookmarkManager *m_pManager; + QString s_highlightedAddress; + QString m_parentAddress; + KBookmarkOwner *m_pOwner; + QWidget *m_parentMenu; +}; + +#endif diff --git a/kio/bookmarks/kbookmarknotifier.h b/kio/bookmarks/kbookmarknotifier.h new file mode 100644 index 000000000..6a16fa052 --- /dev/null +++ b/kio/bookmarks/kbookmarknotifier.h @@ -0,0 +1,45 @@ +// -*- c-basic-offset:4; indent-tabs-mode:nil -*- +// vim: set ts=4 sts=4 sw=4 et: +/* This file is part of the KDE libraries + Copyright (C) 2001, 2003 Alexander Kellett <lypanov@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kbookmarknotifier_h__ +#define __kbookmarknotifier_h__ + +#include <dcopobject.h> + +/** + * DCOP interface for a bookmark notifier (an object which emits signals + * upon changes to the bookmarks) + */ +class KIO_EXPORT KBookmarkNotifier : virtual public DCOPObject +{ + K_DCOP + +public: + KBookmarkNotifier(QCString objId = "KBookmarkNotifier") : DCOPObject(objId) {} + +k_dcop_signals: + void addedBookmark( QString filename, QString url, QString text, QString address, QString icon ); + void createdNewFolder( QString filename, QString text, QString address ); + void updatedAccessMetadata( QString filename, QString url ); +}; + +#endif + |