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

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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