• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KHTML

khtml_ext.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2000-2003 Simon Hausmann <hausmann@kde.org>
00004  *               2001-2003 George Staikos <staikos@kde.org>
00005  *               2001-2003 Laurent Montel <montel@kde.org>
00006  *               2001-2003 Dirk Mueller <mueller@kde.org>
00007  *               2001-2003 Waldo Bastian <bastian@kde.org>
00008  *               2001-2003 David Faure <faure@kde.org>
00009  *               2001-2003 Daniel Naber <dnaber@kde.org>
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Library General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Library General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Library General Public License
00022  * along with this library; see the file COPYING.LIB.  If not, write to
00023  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024  * Boston, MA 02110-1301, USA.
00025  */
00026 
00027 #include "khtml_ext.h"
00028 #include "khtmlview.h"
00029 #include "khtml_pagecache.h"
00030 #include "rendering/render_form.h"
00031 #include "rendering/render_image.h"
00032 #include "html/html_imageimpl.h"
00033 #include "misc/loader.h"
00034 #include "dom/html_form.h"
00035 #include "dom/html_image.h"
00036 #include <QtGui/QClipboard>
00037 #include <QtCore/QFileInfo>
00038 #include <QtGui/QMenu>
00039 #include <QtCore/QUrl>
00040 #include <QtCore/QMetaEnum>
00041 #include <assert.h>
00042 
00043 #include <kdebug.h>
00044 #include <klocale.h>
00045 #include <kfiledialog.h>
00046 #include <kjobuidelegate.h>
00047 #include <kio/job.h>
00048 #include <kshell.h>
00049 #include <ktoolbar.h>
00050 #include <ksavefile.h>
00051 #include <kstringhandler.h>
00052 #include <ktoolinvocation.h>
00053 #include <kmessagebox.h>
00054 #include <kstandarddirs.h>
00055 #include <krun.h>
00056 #include <kurifilter.h>
00057 #include <kicon.h>
00058 #include <kiconloader.h>
00059 #include <kdesktopfile.h>
00060 #include <kinputdialog.h>
00061 #include <ktemporaryfile.h>
00062 #include "khtml_global.h"
00063 #include <kstandardaction.h>
00064 #include <kactioncollection.h>
00065 #include <kactionmenu.h>
00066 
00067 #include "dom/dom_element.h"
00068 #include "misc/htmltags.h"
00069 
00070 #include "khtmlpart_p.h"
00071 
00072 KHTMLPartBrowserExtension::KHTMLPartBrowserExtension( KHTMLPart *parent )
00073 : KParts::BrowserExtension( parent )
00074 {
00075     m_part = parent;
00076     setURLDropHandlingEnabled( true );
00077 
00078     enableAction( "cut", false );
00079     enableAction( "copy", false );
00080     enableAction( "paste", false );
00081 
00082     m_connectedToClipboard = false;
00083 }
00084 
00085 int KHTMLPartBrowserExtension::xOffset()
00086 {
00087     return m_part->view()->contentsX();
00088 }
00089 
00090 int KHTMLPartBrowserExtension::yOffset()
00091 {
00092   return m_part->view()->contentsY();
00093 }
00094 
00095 void KHTMLPartBrowserExtension::saveState( QDataStream &stream )
00096 {
00097   //kDebug( 6050 ) << "saveState!";
00098   m_part->saveState( stream );
00099 }
00100 
00101 void KHTMLPartBrowserExtension::restoreState( QDataStream &stream )
00102 {
00103   //kDebug( 6050 ) << "restoreState!";
00104   m_part->restoreState( stream );
00105 }
00106 
00107 void KHTMLPartBrowserExtension::editableWidgetFocused( QWidget *widget )
00108 {
00109     m_editableFormWidget = widget;
00110     updateEditActions();
00111 
00112     if ( !m_connectedToClipboard && m_editableFormWidget )
00113     {
00114         connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
00115                  this, SLOT( updateEditActions() ) );
00116 
00117         if ( m_editableFormWidget->inherits( "QLineEdit" ) || m_editableFormWidget->inherits( "QTextEdit" ) )
00118             connect( m_editableFormWidget, SIGNAL( selectionChanged() ),
00119                      this, SLOT( updateEditActions() ) );
00120 
00121         m_connectedToClipboard = true;
00122     }
00123     editableWidgetFocused();
00124 }
00125 
00126 void KHTMLPartBrowserExtension::editableWidgetBlurred( QWidget * /*widget*/ )
00127 {
00128     QWidget *oldWidget = m_editableFormWidget;
00129 
00130     m_editableFormWidget = 0;
00131     enableAction( "cut", false );
00132     enableAction( "paste", false );
00133     m_part->emitSelectionChanged();
00134 
00135     if ( m_connectedToClipboard )
00136     {
00137         disconnect( QApplication::clipboard(), SIGNAL( dataChanged() ),
00138                     this, SLOT( updateEditActions() ) );
00139 
00140         if ( oldWidget )
00141         {
00142             if ( oldWidget->inherits( "QLineEdit" ) || oldWidget->inherits( "QTextEdit" ) )
00143                 disconnect( oldWidget, SIGNAL( selectionChanged() ),
00144                             this, SLOT( updateEditActions() ) );
00145         }
00146 
00147         m_connectedToClipboard = false;
00148     }
00149     editableWidgetBlurred();
00150 }
00151 
00152 void KHTMLPartBrowserExtension::setExtensionProxy( KParts::BrowserExtension *proxy )
00153 {
00154     if ( m_extensionProxy )
00155     {
00156         disconnect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
00157                     this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );
00158         if ( m_extensionProxy->inherits( "KHTMLPartBrowserExtension" ) )
00159         {
00160             disconnect( m_extensionProxy, SIGNAL( editableWidgetFocused() ),
00161                         this, SLOT( extensionProxyEditableWidgetFocused() ) );
00162             disconnect( m_extensionProxy, SIGNAL( editableWidgetBlurred() ),
00163                         this, SLOT( extensionProxyEditableWidgetBlurred() ) );
00164         }
00165     }
00166 
00167     m_extensionProxy = proxy;
00168 
00169     if ( m_extensionProxy )
00170     {
00171         connect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
00172                  this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );
00173         if ( m_extensionProxy->inherits( "KHTMLPartBrowserExtension" ) )
00174         {
00175             connect( m_extensionProxy, SIGNAL( editableWidgetFocused() ),
00176                      this, SLOT( extensionProxyEditableWidgetFocused() ) );
00177             connect( m_extensionProxy, SIGNAL( editableWidgetBlurred() ),
00178                      this, SLOT( extensionProxyEditableWidgetBlurred() ) );
00179         }
00180 
00181         enableAction( "cut", m_extensionProxy->isActionEnabled( "cut" ) );
00182         enableAction( "copy", m_extensionProxy->isActionEnabled( "copy" ) );
00183         enableAction( "paste", m_extensionProxy->isActionEnabled( "paste" ) );
00184     }
00185     else
00186     {
00187         updateEditActions();
00188         enableAction( "copy", false ); // ### re-check this
00189     }
00190 }
00191 
00192 void KHTMLPartBrowserExtension::cut()
00193 {
00194     if ( m_extensionProxy )
00195     {
00196         callExtensionProxyMethod( "cut()" );
00197         return;
00198     }
00199 
00200     if ( !m_editableFormWidget )
00201         return;
00202 
00203     if ( m_editableFormWidget->inherits( "QLineEdit" ) )
00204         static_cast<QLineEdit *>( &(*m_editableFormWidget) )->cut();
00205     else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
00206         static_cast<QTextEdit *>( &(*m_editableFormWidget) )->cut();
00207 }
00208 
00209 void KHTMLPartBrowserExtension::copy()
00210 {
00211     if ( m_extensionProxy )
00212     {
00213         callExtensionProxyMethod( "copy()" );
00214         return;
00215     }
00216 
00217     kDebug( 6050 ) << "************! KHTMLPartBrowserExtension::copy()";
00218     if ( !m_editableFormWidget )
00219     {
00220         // get selected text and paste to the clipboard
00221         QString text = m_part->selectedText();
00222         text.replace( QChar( 0xa0 ), ' ' );
00223 
00224         QClipboard *cb = QApplication::clipboard();
00225         disconnect( cb, SIGNAL( selectionChanged() ), m_part, SLOT( slotClearSelection() ) );
00226 #ifndef QT_NO_MIMECLIPBOARD
00227     QString htmltext;
00228     /*
00229      * When selectionModeEnabled, that means the user has just selected
00230      * the text, not ctrl+c to copy it.  The selection clipboard
00231      * doesn't seem to support mime type, so to save time, don't calculate
00232      * the selected text as html.
00233      * optomisation disabled for now until everything else works.
00234     */
00235     //if(!cb->selectionModeEnabled())
00236         htmltext = m_part->selectedTextAsHTML();
00237     QMimeData *mimeData = new QMimeData;
00238     mimeData->setText(text);
00239     if(!htmltext.isEmpty()) {
00240         htmltext.replace( QChar( 0xa0 ), ' ' );
00241         mimeData->setHtml(htmltext);
00242     }
00243         cb->setMimeData(mimeData);
00244 #else
00245     cb->setText(text);
00246 #endif
00247 
00248         connect( cb, SIGNAL( selectionChanged() ), m_part, SLOT( slotClearSelection() ) );
00249     }
00250     else
00251     {
00252         if ( m_editableFormWidget->inherits( "QLineEdit" ) )
00253             static_cast<QLineEdit *>( &(*m_editableFormWidget) )->copy();
00254         else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
00255             static_cast<QTextEdit *>( &(*m_editableFormWidget) )->copy();
00256     }
00257 }
00258 
00259 void KHTMLPartBrowserExtension::searchProvider()
00260 {
00261     // action name is of form "previewProvider[<searchproviderprefix>:]"
00262     const QString searchProviderPrefix = QString( sender()->objectName() ).mid( 14 );
00263 
00264     const QString text = m_part->simplifiedSelectedText();
00265     KUriFilterData data;
00266     QStringList list;
00267     data.setData( searchProviderPrefix + text );
00268     list << "kurisearchfilter" << "kuriikwsfilter";
00269 
00270     if( !KUriFilter::self()->filterUri(data, list) )
00271     {
00272         KDesktopFile file("services", "searchproviders/google.desktop");
00273         QString encodedSearchTerm = QUrl::toPercentEncoding(text);
00274         KConfigGroup cg(file.desktopGroup());
00275         data.setData(cg.readEntry("Query").replace("\\{@}", encodedSearchTerm));
00276     }
00277 
00278     KParts::BrowserArguments browserArgs;
00279     browserArgs.frameName = "_blank";
00280 
00281     emit m_part->browserExtension()->openUrlRequest( data.uri(), KParts::OpenUrlArguments(), browserArgs );
00282 }
00283 
00284 void KHTMLPartBrowserExtension::paste()
00285 {
00286     if ( m_extensionProxy )
00287     {
00288         callExtensionProxyMethod( "paste()" );
00289         return;
00290     }
00291 
00292     if ( !m_editableFormWidget )
00293         return;
00294 
00295     if ( m_editableFormWidget->inherits( "QLineEdit" ) )
00296         static_cast<QLineEdit *>( &(*m_editableFormWidget) )->paste();
00297     else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
00298         static_cast<QTextEdit *>( &(*m_editableFormWidget) )->paste();
00299 }
00300 
00301 void KHTMLPartBrowserExtension::callExtensionProxyMethod( const char *method )
00302 {
00303     if ( !m_extensionProxy )
00304         return;
00305 
00306     int slot = m_extensionProxy->metaObject()->indexOfSlot( method );
00307     if ( slot == -1 )
00308         return;
00309 
00310     QMetaObject::invokeMethod(m_extensionProxy, method, Qt::DirectConnection);
00311 }
00312 
00313 void KHTMLPartBrowserExtension::updateEditActions()
00314 {
00315     if ( !m_editableFormWidget )
00316     {
00317         enableAction( "cut", false );
00318         enableAction( "copy", false );
00319         enableAction( "paste", false );
00320         return;
00321     }
00322 
00323     // ### duplicated from KonqMainWindow::slotClipboardDataChanged
00324 #ifndef QT_NO_MIMECLIPBOARD // Handle minimalized versions of Qt Embedded
00325     const QMimeData *data = QApplication::clipboard()->mimeData();
00326     enableAction( "paste", data->hasFormat( "text/plain" ) );
00327 #else
00328     QString data=QApplication::clipboard()->text();
00329     enableAction( "paste", data.contains("://"));
00330 #endif
00331     bool hasSelection = false;
00332 
00333     if( m_editableFormWidget) {
00334         if ( qobject_cast<QLineEdit*>(m_editableFormWidget))
00335             hasSelection = static_cast<QLineEdit *>( &(*m_editableFormWidget) )->hasSelectedText();
00336         else if(qobject_cast<QTextEdit*>(m_editableFormWidget))
00337             hasSelection = static_cast<QTextEdit *>( &(*m_editableFormWidget) )->textCursor().hasSelection();
00338     }
00339 
00340     enableAction( "copy", hasSelection );
00341     enableAction( "cut", hasSelection );
00342 }
00343 
00344 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetFocused() {
00345     editableWidgetFocused();
00346 }
00347 
00348 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetBlurred() {
00349     editableWidgetBlurred();
00350 }
00351 
00352 void KHTMLPartBrowserExtension::extensionProxyActionEnabled( const char *action, bool enable )
00353 {
00354     // only forward enableAction calls for actions we actually do forward
00355     if ( strcmp( action, "cut" ) == 0 ||
00356          strcmp( action, "copy" ) == 0 ||
00357          strcmp( action, "paste" ) == 0 ) {
00358         enableAction( action, enable );
00359     }
00360 }
00361 
00362 void KHTMLPartBrowserExtension::reparseConfiguration()
00363 {
00364   m_part->reparseConfiguration();
00365 }
00366 
00367 void KHTMLPartBrowserExtension::print()
00368 {
00369   m_part->view()->print();
00370 }
00371 
00372 void KHTMLPartBrowserExtension::disableScrolling()
00373 {
00374   QScrollArea *scrollArea = m_part->view();
00375   if (scrollArea) {
00376     scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00377     scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00378   }
00379 }
00380 
00381 class KHTMLPopupGUIClient::KHTMLPopupGUIClientPrivate
00382 {
00383 public:
00384   KHTMLPart *m_khtml;
00385   KUrl m_url;
00386   KUrl m_imageURL;
00387   QPixmap m_pixmap;
00388   QString m_suggestedFilename;
00389     KActionCollection* m_actionCollection;
00390     KParts::BrowserExtension::ActionGroupMap actionGroups;
00391 };
00392 
00393 
00394 KHTMLPopupGUIClient::KHTMLPopupGUIClient( KHTMLPart *khtml, const KUrl &url )
00395     : QObject( khtml ), d(new KHTMLPopupGUIClientPrivate)
00396 {
00397     d->m_khtml = khtml;
00398     d->m_url = url;
00399     d->m_actionCollection = new KActionCollection(this);
00400     bool isImage = false;
00401     bool hasSelection = khtml->hasSelection();
00402 
00403     DOM::Element e = khtml->nodeUnderMouse();
00404 
00405     if ( !e.isNull() && (e.elementId() == ID_IMG ||
00406                          (e.elementId() == ID_INPUT && !static_cast<DOM::HTMLInputElement>(e).src().isEmpty())))
00407     {
00408         if (e.elementId() == ID_IMG) {
00409             DOM::HTMLImageElementImpl *ie = static_cast<DOM::HTMLImageElementImpl*>(e.handle());
00410             khtml::RenderImage *ri = dynamic_cast<khtml::RenderImage*>(ie->renderer());
00411             if (ri && ri->contentObject()) {
00412                 d->m_suggestedFilename = static_cast<khtml::CachedImage*>(ri->contentObject())->suggestedFilename();
00413             }
00414         }
00415         isImage=true;
00416     }
00417 
00418     if (hasSelection) {
00419         QList<QAction *> editActions;
00420         QAction* copyAction = d->m_actionCollection->addAction( KStandardAction::Copy, "copy",
00421                                                                 d->m_khtml->browserExtension(), SLOT( copy() ) );
00422 
00423         copyAction->setText(i18n("&Copy Text"));
00424         copyAction->setEnabled(d->m_khtml->browserExtension()->isActionEnabled( "copy" ));
00425         editActions.append(copyAction);
00426 
00427         editActions.append(khtml->actionCollection()->action("selectAll"));
00428 
00429         addSearchActions(editActions);
00430 
00431         QString selectedTextURL = selectedTextAsOneLine();
00432         if ( selectedTextURL.contains("://") && KUrl(selectedTextURL).isValid() ) {
00433             if (selectedTextURL.length() > 18) {
00434                 selectedTextURL.truncate(15);
00435                 selectedTextURL += "...";
00436             }
00437             KAction *action = new KAction(i18n("Open '%1'", selectedTextURL), this);
00438             d->m_actionCollection->addAction( "openSelection", action );
00439             action->setIcon( KIcon( "window-new" ) );
00440             connect( action, SIGNAL(triggered(bool)), this, SLOT( openSelection() ) );
00441             editActions.append(action);
00442         }
00443 
00444         KAction* separator = new KAction(d->m_actionCollection);
00445         separator->setSeparator(true);
00446         editActions.append(separator);
00447 
00448         d->actionGroups.insert("editactions", editActions);
00449     }
00450 
00451     if (!url.isEmpty()) {
00452         QList<QAction *> linkActions;
00453         if (url.protocol() == "mailto") {
00454             KAction *action = new KAction( i18n( "&Copy Email Address" ), this );
00455             d->m_actionCollection->addAction( "copylinklocation", action );
00456             connect( action, SIGNAL(triggered(bool)), this, SLOT(slotCopyLinkLocation()) );
00457             linkActions.append(action);
00458         } else {
00459             KAction *action = new KAction( i18n( "&Save Link As..." ), this );
00460             d->m_actionCollection->addAction( "savelinkas", action );
00461             connect( action, SIGNAL(triggered(bool)), this, SLOT(slotSaveLinkAs()) );
00462             linkActions.append(action);
00463 
00464             action = new KAction( i18n( "&Copy Link Address" ), this );
00465             d->m_actionCollection->addAction( "copylinklocation", action );
00466             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyLinkLocation() ) );
00467             linkActions.append(action);
00468         }
00469         d->actionGroups.insert("linkactions", linkActions);
00470     }
00471 
00472     QList<QAction *> partActions;
00473     // frameset? -> add "Reload Frame" etc.
00474     if (!hasSelection) {
00475         if ( khtml->parentPart() ) {
00476             KActionMenu* menu = new KActionMenu( i18nc("@title:menu HTML frame/iframe", "Frame"), this);
00477             KAction *action = new KAction( i18n( "Open in New &Window" ), this );
00478             d->m_actionCollection->addAction( "frameinwindow", action );
00479             action->setIcon( KIcon( "window-new" ) );
00480             connect( action, SIGNAL(triggered(bool)), this, SLOT(slotFrameInWindow()) );
00481             menu->addAction(action);
00482 
00483             action = new KAction( i18n( "Open in &This Window" ), this );
00484             d->m_actionCollection->addAction( "frameintop", action );
00485             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotFrameInTop() ) );
00486             menu->addAction(action);
00487 
00488             action = new KAction( i18n( "Open in &New Tab" ), this );
00489             d->m_actionCollection->addAction( "frameintab", action );
00490             action->setIcon( KIcon( "tab-new" ) );
00491             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotFrameInTab() ) );
00492             menu->addAction(action);
00493 
00494             action = new KAction(d->m_actionCollection);
00495             action->setSeparator(true);
00496             menu->addAction(action);
00497 
00498             action = new KAction( i18n( "Reload Frame" ), this );
00499             d->m_actionCollection->addAction( "reloadframe", action );
00500             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotReloadFrame() ) );
00501             menu->addAction(action);
00502 
00503             action = new KAction( i18n( "Print Frame..." ), this );
00504             d->m_actionCollection->addAction( "printFrame", action );
00505             action->setIcon( KIcon( "document-print-frame" ) );
00506             connect( action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT( print() ) );
00507             menu->addAction(action);
00508 
00509             action = new KAction( i18n( "Save &Frame As..." ), this );
00510             d->m_actionCollection->addAction( "saveFrame", action );
00511             connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotSaveFrame() ) );
00512             menu->addAction(action);
00513 
00514             action = new KAction( i18n( "View Frame Source" ), this );
00515             d->m_actionCollection->addAction( "viewFrameSource", action );
00516             connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotViewDocumentSource() ) );
00517             menu->addAction(action);
00518 
00519             action = new KAction( i18n( "View Frame Information" ), this );
00520             d->m_actionCollection->addAction( "viewFrameInfo", action );
00521             connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotViewPageInfo() ) );
00522 
00523             action = new KAction(d->m_actionCollection);
00524             action->setSeparator(true);
00525             menu->addAction(action);
00526 
00527             if ( KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled() ) {
00528                 if ( khtml->d->m_frame->m_type == khtml::ChildFrame::IFrame ) {
00529                     action = new KAction( i18n( "Block IFrame..." ), this );
00530                     d->m_actionCollection->addAction( "blockiframe", action );
00531                     connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockIFrame() ) );
00532                     menu->addAction(action);
00533                 }
00534             }
00535 
00536             partActions.append(menu);
00537         }
00538     }
00539 
00540     if (isImage) {
00541         if ( e.elementId() == ID_IMG ) {
00542             d->m_imageURL = KUrl( static_cast<DOM::HTMLImageElement>( e ).src().string() );
00543             DOM::HTMLImageElementImpl *imageimpl = static_cast<DOM::HTMLImageElementImpl *>( e.handle() );
00544             Q_ASSERT(imageimpl);
00545             if(imageimpl) // should be true always.  right?
00546             {
00547                 if(imageimpl->complete()) {
00548                     d->m_pixmap = imageimpl->currentPixmap();
00549                 }
00550             }
00551         }
00552         else
00553             d->m_imageURL = KUrl( static_cast<DOM::HTMLInputElement>( e ).src().string() );
00554         KAction *action = new KAction( i18n( "Save Image As..." ), this );
00555         d->m_actionCollection->addAction( "saveimageas", action );
00556         connect( action, SIGNAL(triggered(bool)), this, SLOT( slotSaveImageAs() ) );
00557         partActions.append(action);
00558 
00559         action = new KAction( i18n( "Send Image..." ), this );
00560         d->m_actionCollection->addAction( "sendimage", action );
00561         connect( action, SIGNAL(triggered(bool)), this, SLOT( slotSendImage() ) );
00562         partActions.append(action);
00563 
00564 #ifndef QT_NO_MIMECLIPBOARD
00565         action = new KAction( i18n( "Copy Image" ), this );
00566         d->m_actionCollection->addAction( "copyimage", action );
00567         action->setEnabled(!d->m_pixmap.isNull());
00568         connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyImage() ) );
00569         partActions.append(action);
00570 #endif
00571 
00572         if(d->m_pixmap.isNull()) {    //fallback to image location if still loading the image.  this will always be true if ifdef QT_NO_MIMECLIPBOARD
00573             action = new KAction( i18n( "Copy Image Location" ), this );
00574             d->m_actionCollection->addAction( "copyimagelocation", action );
00575             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyImageLocation() ) );
00576             partActions.append(action);
00577         }
00578 
00579         QString actionText = d->m_suggestedFilename.isEmpty() ?
00580                                    KStringHandler::csqueeze(d->m_imageURL.fileName()+d->m_imageURL.query(), 25)
00581                                    : d->m_suggestedFilename;
00582         action = new KAction( i18n("View Image (%1)", actionText.replace("&", "&&")), this );
00583         d->m_actionCollection->addAction( "viewimage", action );
00584         connect( action, SIGNAL(triggered(bool)), this, SLOT( slotViewImage() ) );
00585         partActions.append(action);
00586 
00587         if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled()) {
00588             action = new KAction( i18n( "Block Image..." ), this );
00589             d->m_actionCollection->addAction( "blockimage", action );
00590             connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockImage() ) );
00591             partActions.append(action);
00592 
00593             if (!d->m_imageURL.host().isEmpty() &&
00594                 !d->m_imageURL.protocol().isEmpty())
00595             {
00596                 action = new KAction( i18n( "Block Images From %1" , d->m_imageURL.host()), this );
00597                 d->m_actionCollection->addAction( "blockhost", action );
00598                 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockHost() ) );
00599                 partActions.append(action);
00600             }
00601         }
00602         KAction* separator = new KAction(d->m_actionCollection);
00603         separator->setSeparator(true);
00604         partActions.append(separator);
00605     }
00606 
00607     if ( isImage || url.isEmpty() ) {
00608         KAction *action = new KAction( i18n( "Stop Animations" ), this );
00609         d->m_actionCollection->addAction( "stopanimations", action );
00610         connect( action, SIGNAL(triggered(bool)), this, SLOT(slotStopAnimations()) );
00611         partActions.append(action);
00612         KAction* separator = new KAction(d->m_actionCollection);
00613         separator->setSeparator(true);
00614         partActions.append(separator);
00615     }
00616     if (!hasSelection && url.isEmpty()) { // only when right-clicking on the page itself
00617         partActions.append(khtml->actionCollection()->action("viewDocumentSource"));
00618     }
00619     if (!hasSelection && url.isEmpty() && !isImage) {
00620         partActions.append(khtml->actionCollection()->action("setEncoding"));
00621     }
00622     d->actionGroups.insert("partactions", partActions);
00623 }
00624 
00625 KHTMLPopupGUIClient::~KHTMLPopupGUIClient()
00626 {
00627     delete d->m_actionCollection;
00628     delete d;
00629 }
00630 
00631 void KHTMLPopupGUIClient::addSearchActions(QList<QAction *>& editActions)
00632 {
00633     // Fill search provider entries
00634     KConfig config("kuriikwsfilterrc");
00635     KConfigGroup cg = config.group("General");
00636     const QString defaultEngine = cg.readEntry("DefaultSearchEngine", "google");
00637     const char keywordDelimiter = cg.readEntry("KeywordDelimiter", static_cast<int>(':'));
00638 
00639     // search text
00640     QString selectedText = d->m_khtml->simplifiedSelectedText();
00641     if (selectedText.isEmpty())
00642         return;
00643 
00644     selectedText.replace("&", "&&");
00645     if (selectedText.length() > 18) {
00646         selectedText.truncate(15);
00647         selectedText += "...";
00648     }
00649 
00650     // default search provider
00651     KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(defaultEngine));
00652 
00653     // search provider icon
00654     KIcon icon;
00655     KUriFilterData data;
00656     QStringList list;
00657     data.setData(QString("some keyword"));
00658     list << "kurisearchfilter" << "kuriikwsfilter";
00659 
00660     QString name;
00661     if (KUriFilter::self()->filterUri(data, list)) {
00662         QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png");
00663         if (iconPath.isEmpty())
00664             icon = KIcon("edit-find");
00665         else
00666             icon = KIcon(QPixmap(iconPath));
00667         name = service->name();
00668     } else {
00669         icon = KIcon("google");
00670         name = "Google";
00671     }
00672 
00673     KAction *action = new KAction(i18n("Search for '%1' with %2", selectedText, name), this);
00674     d->m_actionCollection->addAction("searchProvider", action);
00675     editActions.append(action);
00676     action->setIcon(icon);
00677     connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
00678 
00679     // favorite search providers
00680     QStringList favoriteEngines;
00681     favoriteEngines << "google" << "google_groups" << "google_news" << "webster" << "dmoz" << "wikipedia";
00682     favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines);
00683 
00684     if (!favoriteEngines.isEmpty()) {
00685         KActionMenu* providerList = new KActionMenu(i18n("Search for '%1' with", selectedText), this);
00686         d->m_actionCollection->addAction("searchProviderList", providerList);
00687         editActions.append(providerList);
00688 
00689         QStringList::ConstIterator it = favoriteEngines.begin();
00690         for (; it != favoriteEngines.end(); ++it) {
00691             if (*it==defaultEngine)
00692                 continue;
00693             service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(*it));
00694             if (!service)
00695                 continue;
00696             const QString searchProviderPrefix = *(service->property("Keys").toStringList().begin()) + keywordDelimiter;
00697             data.setData(searchProviderPrefix + "some keyword");
00698 
00699             if (KUriFilter::self()->filterUri(data, list)) {
00700                 const QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png");
00701                 if (iconPath.isEmpty())
00702                     icon = KIcon("edit-find");
00703                 else
00704                     icon = KIcon(iconPath);
00705                 name = service->name();
00706 
00707                 KAction *action = new KAction(name, this);
00708                 d->m_actionCollection->addAction(QString("searchProvider" + searchProviderPrefix).toLatin1().constData(), action);
00709                 action->setIcon(icon);
00710                 connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
00711 
00712                 providerList->addAction(action);
00713             }
00714         }
00715     }
00716 }
00717 
00718 QString KHTMLPopupGUIClient::selectedTextAsOneLine() const
00719 {
00720     QString text = d->m_khtml->simplifiedSelectedText();
00721     // in addition to what simplifiedSelectedText does,
00722     // remove linefeeds and any whitespace surrounding it (#113177),
00723     // to get it all in a single line.
00724     text.remove(QRegExp("[\\s]*\\n+[\\s]*"));
00725     return text;
00726 }
00727 
00728 void KHTMLPopupGUIClient::openSelection()
00729 {
00730     KParts::BrowserArguments browserArgs;
00731     browserArgs.frameName = "_blank";
00732 
00733     emit d->m_khtml->browserExtension()->openUrlRequest(selectedTextAsOneLine(), KParts::OpenUrlArguments(), browserArgs);
00734 }
00735 
00736 KParts::BrowserExtension::ActionGroupMap KHTMLPopupGUIClient::actionGroups() const
00737 {
00738     return d->actionGroups;
00739 }
00740 
00741 void KHTMLPopupGUIClient::slotSaveLinkAs()
00742 {
00743   KIO::MetaData metaData;
00744   metaData["referrer"] = d->m_khtml->referrer();
00745   saveURL( d->m_khtml->widget(), i18n( "Save Link As" ), d->m_url, metaData );
00746 }
00747 
00748 void KHTMLPopupGUIClient::slotSendImage()
00749 {
00750     QStringList urls;
00751     urls.append( d->m_imageURL.url());
00752     QString subject = d->m_imageURL.url();
00753     KToolInvocation::invokeMailer(QString(), QString(), QString(), subject,
00754                        QString(), //body
00755                        QString(),
00756                        urls); // attachments
00757 
00758 
00759 }
00760 
00761 void KHTMLPopupGUIClient::slotSaveImageAs()
00762 {
00763   KIO::MetaData metaData;
00764   metaData["referrer"] = d->m_khtml->referrer();
00765   saveURL( d->m_khtml->widget(), i18n( "Save Image As" ), d->m_imageURL, metaData, QString(), 0, d->m_suggestedFilename );
00766 }
00767 
00768 void KHTMLPopupGUIClient::slotBlockHost()
00769 {
00770     QString name=d->m_imageURL.protocol()+"://"+d->m_imageURL.host()+"/*";
00771     KHTMLGlobal::defaultHTMLSettings()->addAdFilter( name );
00772     d->m_khtml->reparseConfiguration();
00773 }
00774 
00775 void KHTMLPopupGUIClient::slotBlockImage()
00776 {
00777     bool ok = false;
00778 
00779     QString url = KInputDialog::getText( i18n("Add URL to Filter"),
00780                                          i18n("Enter the URL:"),
00781                                          d->m_imageURL.url(),
00782                                          &ok);
00783     if ( ok ) {
00784         KHTMLGlobal::defaultHTMLSettings()->addAdFilter( url );
00785         d->m_khtml->reparseConfiguration();
00786     }
00787 }
00788 
00789 void KHTMLPopupGUIClient::slotBlockIFrame()
00790 {
00791     bool ok = false;
00792     QString url = KInputDialog::getText( i18n( "Add URL to Filter"),
00793                                                i18n("Enter the URL:"),
00794                                                d->m_khtml->url().url(),
00795                                                &ok );
00796     if ( ok ) {
00797         KHTMLGlobal::defaultHTMLSettings()->addAdFilter( url );
00798         d->m_khtml->reparseConfiguration();
00799     }
00800 }
00801 
00802 void KHTMLPopupGUIClient::slotCopyLinkLocation()
00803 {
00804   KUrl safeURL(d->m_url);
00805   safeURL.setPass(QString());
00806 #ifndef QT_NO_MIMECLIPBOARD
00807   // Set it in both the mouse selection and in the clipboard
00808   QMimeData* mimeData = new QMimeData;
00809   safeURL.populateMimeData( mimeData );
00810   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
00811 
00812   mimeData = new QMimeData;
00813   safeURL.populateMimeData( mimeData );
00814   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
00815 
00816 #else
00817   QApplication::clipboard()->setText( safeURL.url() ); //FIXME(E): Handle multiple entries
00818 #endif
00819 }
00820 
00821 void KHTMLPopupGUIClient::slotStopAnimations()
00822 {
00823   d->m_khtml->stopAnimations();
00824 }
00825 
00826 void KHTMLPopupGUIClient::slotCopyImage()
00827 {
00828 #ifndef QT_NO_MIMECLIPBOARD
00829   KUrl safeURL(d->m_imageURL);
00830   safeURL.setPass(QString());
00831 
00832   // Set it in both the mouse selection and in the clipboard
00833   QMimeData* mimeData = new QMimeData;
00834   mimeData->setImageData( d->m_pixmap );
00835   safeURL.populateMimeData( mimeData );
00836   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
00837 
00838   mimeData = new QMimeData;
00839   mimeData->setImageData( d->m_pixmap );
00840   safeURL.populateMimeData( mimeData );
00841   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
00842 #else
00843   kDebug() << "slotCopyImage called when the clipboard does not support this.  This should not be possible.";
00844 #endif
00845 }
00846 
00847 void KHTMLPopupGUIClient::slotCopyImageLocation()
00848 {
00849   KUrl safeURL(d->m_imageURL);
00850   safeURL.setPass(QString());
00851 #ifndef QT_NO_MIMECLIPBOARD
00852   // Set it in both the mouse selection and in the clipboard
00853   QMimeData* mimeData = new QMimeData;
00854   safeURL.populateMimeData( mimeData );
00855   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
00856   mimeData = new QMimeData;
00857   safeURL.populateMimeData( mimeData );
00858   QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
00859 #else
00860   QApplication::clipboard()->setText( safeURL.url() ); //FIXME(E): Handle multiple entries
00861 #endif
00862 }
00863 
00864 void KHTMLPopupGUIClient::slotViewImage()
00865 {
00866   d->m_khtml->browserExtension()->createNewWindow(d->m_imageURL);
00867 }
00868 
00869 void KHTMLPopupGUIClient::slotReloadFrame()
00870 {
00871   KParts::OpenUrlArguments args = d->m_khtml->arguments();
00872   args.setReload( true );
00873   args.metaData()["referrer"] = d->m_khtml->pageReferrer();
00874   // reload document
00875   d->m_khtml->closeUrl();
00876   d->m_khtml->setArguments( args );
00877   d->m_khtml->openUrl( d->m_khtml->url() );
00878 }
00879 
00880 void KHTMLPopupGUIClient::slotFrameInWindow()
00881 {
00882   KParts::OpenUrlArguments args = d->m_khtml->arguments();
00883   args.metaData()["referrer"] = d->m_khtml->pageReferrer();
00884   args.metaData()["forcenewwindow"] = "true";
00885   emit d->m_khtml->browserExtension()->createNewWindow( d->m_khtml->url(), args );
00886 }
00887 
00888 void KHTMLPopupGUIClient::slotFrameInTop()
00889 {
00890   KParts::OpenUrlArguments args = d->m_khtml->arguments();
00891   args.metaData()["referrer"] = d->m_khtml->pageReferrer();
00892   KParts::BrowserArguments browserArgs( d->m_khtml->browserExtension()->browserArguments() );
00893   browserArgs.frameName = "_top";
00894   emit d->m_khtml->browserExtension()->openUrlRequest( d->m_khtml->url(), args, browserArgs );
00895 }
00896 
00897 void KHTMLPopupGUIClient::slotFrameInTab()
00898 {
00899   KParts::OpenUrlArguments args = d->m_khtml->arguments();
00900   args.metaData()["referrer"] = d->m_khtml->pageReferrer();
00901   KParts::BrowserArguments browserArgs( d->m_khtml->browserExtension()->browserArguments() );
00902   browserArgs.setNewTab(true);
00903   emit d->m_khtml->browserExtension()->createNewWindow( d->m_khtml->url(), args, browserArgs );
00904 }
00905 
00906 void KHTMLPopupGUIClient::saveURL( QWidget *parent, const QString &caption,
00907                                    const KUrl &url,
00908                                    const QMap<QString, QString> &metadata,
00909                                    const QString &filter, long cacheId,
00910                                    const QString & suggestedFilename )
00911 {
00912   QString name = QLatin1String( "index.html" );
00913   if ( !suggestedFilename.isEmpty() )
00914     name = suggestedFilename;
00915   else if ( !url.fileName().isEmpty() )
00916     name = url.fileName();
00917 
00918   KUrl destURL;
00919   int query;
00920   do {
00921     query = KMessageBox::Yes;
00922     destURL = KFileDialog::getSaveUrl( name, filter, parent, caption );
00923       if( destURL.isLocalFile() )
00924       {
00925         QFileInfo info( destURL.path() );
00926         if( info.exists() ) {
00927           // TODO: use KIO::RenameDlg (shows more information)
00928           query = KMessageBox::warningContinueCancel( parent, i18n( "A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" ,  info.fileName() ), i18n( "Overwrite File?" ), KGuiItem(i18n( "Overwrite" )) );
00929         }
00930        }
00931    } while ( query == KMessageBox::Cancel );
00932 
00933   if ( destURL.isValid() )
00934     saveURL(parent, url, destURL, metadata, cacheId);
00935 }
00936 
00937 void KHTMLPopupGUIClient::saveURL( QWidget* parent, const KUrl &url, const KUrl &destURL,
00938                                    const QMap<QString, QString> &metadata,
00939                                    long cacheId )
00940 {
00941     if ( destURL.isValid() )
00942     {
00943         bool saved = false;
00944         if (KHTMLPageCache::self()->isComplete(cacheId))
00945         {
00946             if (destURL.isLocalFile())
00947             {
00948                 KSaveFile destFile(destURL.path());
00949                 if (destFile.open())
00950                 {
00951                     QDataStream stream ( &destFile );
00952                     KHTMLPageCache::self()->saveData(cacheId, &stream);
00953                     saved = true;
00954                 }
00955             }
00956             else
00957             {
00958                 // save to temp file, then move to final destination.
00959                 KTemporaryFile destFile;
00960                 if (destFile.open())
00961                 {
00962                     QDataStream stream ( &destFile );
00963                     KHTMLPageCache::self()->saveData(cacheId, &stream);
00964                     KUrl url2 = KUrl();
00965                     url2.setPath(destFile.fileName());
00966                     KIO::file_move(url2, destURL, -1, KIO::Overwrite);
00967                     saved = true;
00968                 }
00969             }
00970         }
00971         if(!saved)
00972         {
00973           // DownloadManager <-> konqueror integration
00974           // find if the integration is enabled
00975           // the empty key  means no integration
00976           // only use download manager for non-local urls!
00977           bool downloadViaKIO = true;
00978           if ( !url.isLocalFile() )
00979           {
00980             KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings");
00981             QString downloadManger = cfg.readPathEntry("DownloadManager", QString());
00982             if (!downloadManger.isEmpty())
00983             {
00984                 // then find the download manager location
00985                 kDebug(1000) << "Using: "<<downloadManger <<" as Download Manager";
00986                 QString cmd = KStandardDirs::findExe(downloadManger);
00987                 if (cmd.isEmpty())
00988                 {
00989                     QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManger);
00990                     QString errMsgEx= i18n("Try to reinstall it  \n\nThe integration with Konqueror will be disabled.");
00991                     KMessageBox::detailedSorry(0,errMsg,errMsgEx);
00992                     cfg.writePathEntry("DownloadManager",QString());
00993                     cfg.sync ();
00994                 }
00995                 else
00996                 {
00997                     downloadViaKIO = false;
00998                     KUrl cleanDest = destURL;
00999                     cleanDest.setPass( QString() ); // don't put password into commandline
01000                     cmd += ' ' + KShell::quoteArg(url.url()) + ' ' +
01001                            KShell::quoteArg(cleanDest.url());
01002                     kDebug(1000) << "Calling command  "<<cmd;
01003                     KRun::runCommand(cmd, parent->topLevelWidget());
01004                 }
01005             }
01006           }
01007 
01008           if ( downloadViaKIO )
01009           {
01010               KIO::Job *job = KIO::file_copy( url, destURL, -1, KIO::Overwrite );
01011               job->setMetaData(metadata);
01012               job->addMetaData("MaxCacheSize", "0"); // Don't store in http cache.
01013               job->addMetaData("cache", "cache"); // Use entry from cache if available.
01014               job->uiDelegate()->setAutoErrorHandlingEnabled( true );
01015           }
01016         } //end if(!saved)
01017     }
01018 }
01019 
01020 KHTMLPartBrowserHostExtension::KHTMLPartBrowserHostExtension( KHTMLPart *part )
01021 : KParts::BrowserHostExtension( part )
01022 {
01023   m_part = part;
01024 }
01025 
01026 KHTMLPartBrowserHostExtension::~KHTMLPartBrowserHostExtension()
01027 {
01028 }
01029 
01030 QStringList KHTMLPartBrowserHostExtension::frameNames() const
01031 {
01032   return m_part->frameNames();
01033 }
01034 
01035 const QList<KParts::ReadOnlyPart*> KHTMLPartBrowserHostExtension::frames() const
01036 {
01037   return m_part->frames();
01038 }
01039 
01040 bool KHTMLPartBrowserHostExtension::openUrlInFrame(const KUrl &url, const KParts::OpenUrlArguments& arguments, const KParts::BrowserArguments &browserArguments)
01041 {
01042   return m_part->openUrlInFrame( url, arguments, browserArguments );
01043 }
01044 
01045 KParts::BrowserHostExtension* KHTMLPartBrowserHostExtension::findFrameParent( KParts::ReadOnlyPart
01046       *callingPart, const QString &frame )
01047 {
01048     KHTMLPart *parentPart = m_part->findFrameParent(callingPart, frame);
01049     if (parentPart)
01050        return parentPart->browserHostExtension();
01051     return 0;
01052 }
01053 
01054 
01055 // defined in khtml_part.cpp
01056 extern const int KDE_NO_EXPORT fastZoomSizes[];
01057 extern const int KDE_NO_EXPORT fastZoomSizeCount;
01058 
01059 KHTMLZoomFactorAction::KHTMLZoomFactorAction( KHTMLPart *part, bool direction, const QString &icon, const QString &text, QObject *parent )
01060     : KSelectAction( text, parent )
01061 {
01062     setIcon( KIcon( icon ) );
01063 
01064     setToolBarMode(MenuMode);
01065     setToolButtonPopupMode(QToolButton::DelayedPopup);
01066 
01067     init(part, direction);
01068 }
01069 
01070 void KHTMLZoomFactorAction::init(KHTMLPart *part, bool direction)
01071 {
01072     m_direction = direction;
01073     m_part = part;
01074 
01075     // xgettext: no-c-format
01076     addAction( i18n( "Default Font Size (100%)" ) );
01077 
01078     int m = m_direction ? 1 : -1;
01079     int ofs = fastZoomSizeCount / 2;       // take index of 100%
01080 
01081     // this only works if there is an odd number of elements in fastZoomSizes[]
01082     for ( int i = m; i != m*(ofs+1); i += m )
01083     {
01084         int num = i * m;
01085         QString numStr = QString::number( num );
01086         if ( num > 0 ) numStr.prepend( QLatin1Char('+') );
01087 
01088         // xgettext: no-c-format
01089         addAction( i18n( "%1%" ,  fastZoomSizes[ofs + i] ) );
01090     }
01091 
01092     connect( selectableActionGroup(), SIGNAL( triggered(QAction*) ), this, SLOT( slotTriggered(QAction*) ) );
01093 }
01094 
01095 KHTMLZoomFactorAction::~KHTMLZoomFactorAction()
01096 {
01097 }
01098 
01099 void KHTMLZoomFactorAction::slotTriggered(QAction* action)
01100 {
01101     int idx = selectableActionGroup()->actions().indexOf(action);
01102 
01103     if (idx == 0)
01104         m_part->setFontScaleFactor(100);
01105     else
01106         m_part->setFontScaleFactor(fastZoomSizes[fastZoomSizeCount/2 + (m_direction ? 1 : -1)*idx]);
01107     setCurrentAction( 0L );
01108 }
01109 
01110 #include "khtml_ext.moc"
01111 

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal