akregator/src

pageviewer.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>
00005                   2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include "akregatorconfig.h"
00027 #include "akregator_run.h" 
00028 #include "feediconmanager.h"
00029 #include "pageviewer.h"
00030 #include "viewer.h"
00031 
00032 #include <kaction.h>
00033 #include <kapplication.h>
00034 #include <kbookmark.h>
00035 #include <kbookmarkmanager.h>
00036 #include <kconfig.h>
00037 #include <kglobalsettings.h>
00038 #include <khtml_settings.h>
00039 #include <khtmlview.h>
00040 #include <kiconloader.h>
00041 #include <klocale.h>
00042 #include <kpopupmenu.h>
00043 #include <kstandarddirs.h>
00044 #include <kstdaccel.h>
00045 #include <kparts/browserinterface.h>
00046 
00047 #include <qclipboard.h>
00048 #include <qcstring.h>
00049 #include <qdatastream.h>
00050 #include <qdatetime.h>
00051 #include <qfile.h>
00052 #include <qmetaobject.h>
00053 #include <qscrollview.h>
00054 #include <qstring.h>
00055 #include <qvaluelist.h>
00056 #include <private/qucomextra_p.h>
00057 
00058 #include <cstdlib>
00059 using std::abs;
00060 
00061 namespace Akregator {
00062 
00063 
00064 // taken from KDevelop
00065 class PageViewer::HistoryEntry
00066 {
00067     public:
00068 
00069     KURL url;
00070     QString title;
00071     QByteArray state;
00072     int id;
00073 
00074     HistoryEntry() {}
00075     HistoryEntry(const KURL& u, const QString& t=QString::null): url(u), title(t)   
00076     {
00077         id = abs( QTime::currentTime().msecsTo( QTime() ) );    // nasty, but should provide a reasonably unique number
00078     }
00079     
00080 };
00081 
00082 class PageViewer::PageViewerPrivate
00083 {
00084     public:
00085 
00086     QValueList<HistoryEntry> history;
00087     QValueList<HistoryEntry>::Iterator current;
00088     
00089     KToolBarPopupAction* backAction;
00090     KToolBarPopupAction* forwardAction;
00091     KAction* reloadAction;
00092     KAction* stopAction;
00093     
00094     QString caption;
00095 };           
00096 
00097  
00098 PageViewer::PageViewer(QWidget *parent, const char *name)
00099     : Viewer(parent, name), d(new PageViewerPrivate)
00100 {
00101     // this hack is necessary since the part looks for []HTML Settings] in
00102     // KGlobal::config() by default, which is wrong when running in Kontact
00103     KHTMLSettings* s = const_cast<KHTMLSettings*> (settings());
00104     s->init(Settings::self()->config());
00105     
00106     setXMLFile(locate("data", "akregator/pageviewer.rc"), true);
00107 
00108     QPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward();
00109 
00110     d->backAction = new KToolBarPopupAction(backForward.first, 
00111                                 KStdAccel::shortcut(KStdAccel::Back), this, 
00112                                 SLOT(slotBack()), actionCollection(), 
00113                                 "pageviewer_back");
00114 
00115     connect(d->backAction->popupMenu(), SIGNAL(aboutToShow()),
00116             this, SLOT(slotBackAboutToShow()));
00117     connect(d->backAction->popupMenu(), SIGNAL(activated(int)),
00118             this, SLOT(slotPopupActivated(int)));
00119 
00120     
00121     d->forwardAction = new KToolBarPopupAction(backForward.second, 
00122                                 KStdAccel::shortcut(KStdAccel::Forward),this, 
00123                                 SLOT(slotForward()), actionCollection(), 
00124                                 "pageviewer_forward");
00125 
00126     connect(d->forwardAction->popupMenu(), SIGNAL(aboutToShow()),
00127             this, SLOT(slotForwardAboutToShow()));
00128     connect(d->forwardAction->popupMenu(), SIGNAL(activated(int)),
00129             this, SLOT(slotPopupActivated(int)));
00130 
00131     d->reloadAction = new KAction(i18n("Reload"), "reload", 0,
00132                             this, SLOT(slotReload()),
00133                             actionCollection(), "pageviewer_reload");
00134     d->stopAction = new KAction(KStdGuiItem::guiItem(KStdGuiItem::Stop), 0,
00135                                  this, SLOT(slotStop()),
00136                                  actionCollection(), "pageviewer_stop");
00137  
00138     //connect( this, SIGNAL(popupMenu(const QString &, const QPoint &)), this, SLOT(slotPopupMenu(const QString &, const QPoint &)));
00139 
00140     d->backAction->setEnabled(false);
00141     d->forwardAction->setEnabled(false);
00142     d->stopAction->setEnabled(false);
00143     
00144     connect( this, SIGNAL(setWindowCaption (const QString &)),
00145             this, SLOT(slotSetCaption (const QString &)) );
00146 
00147     connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(slotStarted(KIO::Job* )));
00148     connect(this, SIGNAL(completed()), this, SLOT(slotCompleted()));
00149     connect(this, SIGNAL(canceled(const QString &)), this, SLOT(slotCancelled(const QString &)));
00150 
00151     d->current = d->history.end();
00152 
00153     // uncomment this to load konq plugins (doesn't work properly and clutters the GUI)
00154     //loadPlugins( partObject(), this, instance() );
00155     
00156 }
00157 
00158 PageViewer::~PageViewer()
00159 {
00160     delete d;
00161     d = 0;
00162 }
00163 
00164 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00165 void PageViewer::slotBack()
00166 {
00167     if ( d->current != d->history.begin() )
00168     {
00169         QValueList<HistoryEntry>::Iterator tmp = d->current;
00170         --tmp;
00171         restoreHistoryEntry(tmp);
00172     }
00173 }
00174 
00175 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00176 void PageViewer::slotForward()
00177 {
00178     if ( d->current != d->history.fromLast() && d->current != d->history.end() )
00179     {
00180         QValueList<HistoryEntry>::Iterator tmp = d->current;
00181         ++tmp;
00182         restoreHistoryEntry(tmp);
00183     }
00184 }
00185 
00186 void PageViewer::slotBackAboutToShow()
00187 {
00188     KPopupMenu *popup = d->backAction->popupMenu();
00189     popup->clear();
00190 
00191     if ( d->current == d->history.begin() )
00192         return;
00193 
00194     QValueList<HistoryEntry>::Iterator it = d->current;
00195     --it;
00196     
00197     int i = 0;
00198     while( i < 10 )
00199     {
00200         if ( it == d->history.begin() )
00201         {
00202             popup->insertItem( (*it).title, (*it).id );
00203             return;
00204         }
00205         
00206         popup->insertItem( (*it).title, (*it).id );
00207         ++i;
00208         --it;
00209     }
00210 }
00211 
00212 void PageViewer::slotForwardAboutToShow()
00213 {
00214     KPopupMenu *popup = d->forwardAction->popupMenu();
00215     popup->clear();
00216 
00217     if ( d->current == d->history.fromLast() )
00218         return;
00219 
00220     QValueList<HistoryEntry>::Iterator it = d->current;
00221     ++it;
00222     
00223     int i = 0;
00224     while( i < 10 )
00225     {
00226         if ( it == d->history.fromLast() )
00227         {
00228             popup->insertItem( (*it).title, (*it).id );
00229             return;
00230         }
00231         
00232         popup->insertItem( (*it).title, (*it).id );
00233         ++i;
00234         ++it;
00235     }
00236 }
00237 
00238 
00239 void PageViewer::slotReload()
00240 {
00241     openURL( url() );
00242 }
00243 
00244 void PageViewer::slotStop()
00245 {
00246     closeURL();
00247 }
00248 
00249 bool PageViewer::openURL(const KURL& url)
00250 {
00251     updateHistoryEntry(); // update old history entry before switching to the new one
00252     emit started(0);
00253 
00254     bool val = KHTMLPart::openURL(url);
00255     
00256     addHistoryEntry(url); // add new URL to history
00257     
00258     d->backAction->setEnabled( d->current != d->history.begin() );
00259     d->forwardAction->setEnabled( d->current != d->history.fromLast() );
00260   
00261     QString favicon = FeedIconManager::self()->iconLocation(url);
00262     if (!favicon.isEmpty()) 
00263         emit setTabIcon(QPixmap(KGlobal::dirs()->findResource("cache", favicon+".png")));
00264     else
00265         emit setTabIcon(SmallIcon("html"));
00266 
00267     return val;
00268 }
00269 
00270 
00271 void PageViewer::slotOpenURLRequest(const KURL& url, const KParts::URLArgs& args)
00272 {
00273     updateHistoryEntry();
00274     if (args.doPost())
00275     {
00276         browserExtension()->setURLArgs(args);
00277         openURL(url);
00278     }
00279 
00280 }
00281 
00282 void PageViewer::slotPopupActivated( int id )
00283 {
00284     QValueList<HistoryEntry>::Iterator it = d->history.begin();
00285     while( it != d->history.end() )
00286     {
00287         if ( (*it).id == id )
00288         {
00289             restoreHistoryEntry(it);
00290             return;
00291         }
00292         ++it;
00293     }
00294 }
00295 
00296 void PageViewer::updateHistoryEntry()
00297 {
00298     (*d->current).title = d->caption;
00299     (*d->current).state = QByteArray(); // Start with empty buffer.
00300     QDataStream stream( (*d->current).state, IO_WriteOnly);
00301     browserExtension()->saveState(stream);
00302 }
00303 
00304 void PageViewer::restoreHistoryEntry(const QValueList<HistoryEntry>::Iterator& entry)
00305 {
00306     updateHistoryEntry();
00307     
00308     QDataStream stream( (*entry).state, IO_ReadOnly );
00309     browserExtension()->restoreState( stream );
00310     d->current = entry;
00311     d->backAction->setEnabled( d->current != d->history.begin() );
00312     d->forwardAction->setEnabled( d->current != d->history.fromLast() );
00313     //openURL( entry.url ); // TODO read state
00314     
00315 
00316 }
00317 
00318 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00319 void PageViewer::addHistoryEntry(const KURL& url)
00320 {
00321     QValueList<HistoryEntry>::Iterator it = d->current;
00322     
00323     // if We're not already the last entry, we truncate the list here before adding an entry
00324     if ( it != d->history.end() && it != d->history.fromLast() )
00325     {
00326         d->history.erase( ++it, d->history.end() );
00327     }
00328     HistoryEntry newEntry( url, url.url() );
00329 
00330     // Only save the new entry if it is different from the last
00331     if ( newEntry.url != (*d->current).url )
00332     {
00333         d->history.append( newEntry );
00334         d->current = d->history.fromLast();
00335     }
00336     updateHistoryEntry();
00337 }
00338 
00339 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00340 void PageViewer::slotStarted( KIO::Job * )
00341 {
00342     d->stopAction->setEnabled(true);
00343 }
00344 
00345 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00346 void PageViewer::slotCompleted( )
00347 {
00348     d->stopAction->setEnabled(false);
00349 }
00350 
00351 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
00352 void PageViewer::slotCancelled( const QString & /*errMsg*/ )
00353 {
00354     d->stopAction->setEnabled(false);
00355 }
00356 
00357 void PageViewer::urlSelected(const QString &url, int button, int state, const QString &_target, KParts::URLArgs args)
00358 {
00359     if (url.startsWith(QString::fromLatin1( "javascript:" ), /*case-sensitive=*/false) )
00360     {
00361         KHTMLPart::urlSelected(url,button,state,_target,args);
00362     }
00363     else
00364     {
00365         if (button == LeftButton)
00366         {
00367             m_url = completeURL(url);
00368             browserExtension()->setURLArgs(args); 
00369             slotOpenLinkInThisTab();
00370         }
00371         else
00372         {
00373             Viewer::urlSelected(url,button,state,_target,args);
00374         }
00375     }
00376 }
00377 
00378 void PageViewer::slotSetCaption(const QString& cap) 
00379 {
00380     d->caption = cap;
00381     (*d->current).title = cap;
00382 }
00383 
00384 void PageViewer::slotPaletteOrFontChanged()
00385 {
00386     kdDebug() << "PageViewer::slotPaletteOrFontChanged()" << endl;
00387     // taken from KonqView (kdebase/konqueror/konq_view.cc)
00388     
00389     QObject *obj = KParts::BrowserExtension::childObject(this);
00390     if ( !obj ) // not all views have a browser extension !
00391         return;
00392     
00393     int id = obj->metaObject()->findSlot("reparseConfiguration()");
00394     if (id == -1)
00395         return;
00396     QUObject o[1];
00397 
00398     obj->qt_invoke(id, o);
00399     
00400     // this hack is necessary since the part looks for []HTML Settings] in
00401     // KGlobal::config() by default, which is wrong when running in Kontact
00402     // NOTE: when running in Kontact, immediate updating doesn't work
00403     KHTMLSettings* s = const_cast<KHTMLSettings*> (settings());
00404     s->init(Settings::self()->config());
00405 }
00406 
00407 void PageViewer::slotGlobalBookmarkArticle()
00408 {
00409     KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager();
00410     KBookmarkGroup grp = mgr->root();
00411     grp.addBookmark(mgr, d->caption, toplevelURL());
00412     mgr->emitChanged(grp);
00413     mgr->save();
00414 }
00415 
00416 
00417 void PageViewer::slotPopupMenu(KXMLGUIClient*, const QPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags kpf, mode_t)
00418 {
00419     m_url = kurl;
00420     QString url = kurl.url(); // maximal url confusion
00421     
00422     const bool showReload = (kpf & KParts::BrowserExtension::ShowReload) != 0;
00423     const bool showNavigationItems = (kpf & KParts::BrowserExtension::ShowNavigationItems) != 0;
00424     const bool isLink = (kpf & (KParts::BrowserExtension::ShowNavigationItems | KParts::BrowserExtension::ShowTextSelectionItems)) == 0;
00425     const bool isSelection = (kpf & KParts::BrowserExtension::ShowTextSelectionItems) != 0;
00426         
00427     KPopupMenu popup(this->widget());
00428 
00429     int idNewWindow = -2;
00430     if (isLink)
00431     {
00432         idNewWindow = popup.insertItem(SmallIcon("tab_new"),i18n("Open Link in New &Tab"), this, SLOT(slotOpenLinkInForegroundTab()));
00433         popup.setWhatsThis(idNewWindow, i18n("<b>Open Link in New Tab</b><p>Opens current link in a new tab."));
00434         popup.insertItem(SmallIcon("window_new"), i18n("Open Link in External &Browser"), this, SLOT(slotOpenLinkInBrowser()));
00435                 
00436         popup.insertSeparator();
00437         action("savelinkas")->plug(&popup);    
00438         KAction* copylinkaddress = action("copylinkaddress");
00439         if (copylinkaddress)
00440         {
00441             copylinkaddress->plug( &popup);
00442             //popup.insertSeparator();
00443         }
00444     }
00445     else // we are not on a link
00446     {
00447         if (showNavigationItems)
00448         {
00449             d->backAction->plug( &popup );
00450             d->forwardAction->plug( &popup );
00451         }
00452 
00453         if (showReload)
00454             d->reloadAction->plug(&popup);
00455         
00456         d->stopAction->plug(&popup);
00457         
00458         popup.insertSeparator();
00459         
00460         if (isSelection)
00461         {
00462             action("viewer_copy")->plug(&popup);
00463             popup.insertSeparator();
00464         }
00465 
00466         KAction* incFontAction = this->action("incFontSizes");
00467         KAction* decFontAction = this->action("decFontSizes");
00468         if ( incFontAction && decFontAction )
00469         {
00470             incFontAction->plug( &popup );
00471             decFontAction->plug( &popup );
00472             popup.insertSeparator();
00473         }
00474     
00475         popup.insertItem(SmallIcon("window_new"), i18n("Open Page in External Browser"), this, SLOT(slotOpenLinkInBrowser()));
00476     
00477         action("viewer_print")->plug(&popup);
00478         popup.insertSeparator();
00479         
00480         KAction *ac = action("setEncoding");
00481         if (ac)
00482             ac->plug(&popup);
00483         popup.insertItem(SmallIcon("bookmark_add"),i18n("Add to Konqueror Bookmarks"), this, SLOT(slotGlobalBookmarkArticle()));
00484     }
00485     
00486     int r = popup.exec(p);
00487     
00488     if (r == idNewWindow)
00489     {
00490         KURL kurl;
00491         if (!KURL(url).path().startsWith("/"))
00492         {
00493             kdDebug() << "processing relative url: " << url << endl;
00494             if (url.startsWith("#"))
00495             {
00496                 kurl = KURL(PageViewer::url());
00497                 kurl.setRef(url.mid(1));
00498             }
00499             else
00500                 kurl = KURL(PageViewer::url().upURL().url(true)+url);
00501         }
00502         else
00503             kurl = KURL(url);
00504 //    kurl.addPath(url);
00505         if (kurl.isValid()) {
00506             //slotOpenInNewWindow(kurl);
00507         }
00508 //      ( kurl );
00509     }
00510 }
00511 
00512 } // namespace Akregator 
00513 
00514 #include "pageviewer.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys