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 TQt, and distribute the resulting executable, 00023 without including the source code for TQt 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 <tqclipboard.h> 00048 #include <tqcstring.h> 00049 #include <tqdatastream.h> 00050 #include <tqdatetime.h> 00051 #include <tqfile.h> 00052 #include <tqmetaobject.h> 00053 #include <tqscrollview.h> 00054 #include <tqstring.h> 00055 #include <tqvaluelist.h> 00056 #include <tqucomextra_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 TQString title; 00071 TQByteArray state; 00072 int id; 00073 00074 HistoryEntry() {} 00075 HistoryEntry(const KURL& u, const TQString& t=TQString()): url(u), title(t) 00076 { 00077 id = abs( TQTime::currentTime().msecsTo( TQTime() ) ); // nasty, but should provide a reasonably unique number 00078 } 00079 00080 }; 00081 00082 class PageViewer::PageViewerPrivate 00083 { 00084 public: 00085 00086 TQValueList<HistoryEntry> history; 00087 TQValueList<HistoryEntry>::Iterator current; 00088 00089 KToolBarPopupAction* backAction; 00090 KToolBarPopupAction* forwardAction; 00091 KAction* reloadAction; 00092 KAction* stopAction; 00093 00094 TQString caption; 00095 }; 00096 00097 00098 PageViewer::PageViewer(TQWidget *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 TQPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward(); 00109 00110 d->backAction = new KToolBarPopupAction(backForward.first, 00111 KStdAccel::shortcut(KStdAccel::Back), this, 00112 TQT_SLOT(slotBack()), actionCollection(), 00113 "pageviewer_back"); 00114 00115 connect(d->backAction->popupMenu(), TQT_SIGNAL(aboutToShow()), 00116 this, TQT_SLOT(slotBackAboutToShow())); 00117 connect(d->backAction->popupMenu(), TQT_SIGNAL(activated(int)), 00118 this, TQT_SLOT(slotPopupActivated(int))); 00119 00120 00121 d->forwardAction = new KToolBarPopupAction(backForward.second, 00122 KStdAccel::shortcut(KStdAccel::Forward),this, 00123 TQT_SLOT(slotForward()), actionCollection(), 00124 "pageviewer_forward"); 00125 00126 connect(d->forwardAction->popupMenu(), TQT_SIGNAL(aboutToShow()), 00127 this, TQT_SLOT(slotForwardAboutToShow())); 00128 connect(d->forwardAction->popupMenu(), TQT_SIGNAL(activated(int)), 00129 this, TQT_SLOT(slotPopupActivated(int))); 00130 00131 d->reloadAction = new KAction(i18n("Reload"), "reload", 0, 00132 this, TQT_SLOT(slotReload()), 00133 actionCollection(), "pageviewer_reload"); 00134 d->stopAction = new KAction(KStdGuiItem::guiItem(KStdGuiItem::Stop), 0, 00135 this, TQT_SLOT(slotStop()), 00136 actionCollection(), "pageviewer_stop"); 00137 00138 //connect( this, TQT_SIGNAL(popupMenu(const TQString &, const TQPoint &)), this, TQT_SLOT(slotPopupMenu(const TQString &, const TQPoint &))); 00139 00140 d->backAction->setEnabled(false); 00141 d->forwardAction->setEnabled(false); 00142 d->stopAction->setEnabled(false); 00143 00144 connect( this, TQT_SIGNAL(setWindowCaption (const TQString &)), 00145 this, TQT_SLOT(slotSetCaption (const TQString &)) ); 00146 00147 connect(this, TQT_SIGNAL(started(KIO::Job *)), this, TQT_SLOT(slotStarted(KIO::Job* ))); 00148 connect(this, TQT_SIGNAL(completed()), this, TQT_SLOT(slotCompleted())); 00149 connect(this, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(slotCancelled(const TQString &))); 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 TQValueList<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 TQValueList<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 TQValueList<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 TQValueList<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 TQString favicon = FeedIconManager::self()->iconLocation(url); 00262 if (!favicon.isEmpty()) 00263 emit setTabIcon(TQPixmap(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 TQValueList<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 = TQByteArray(); // Start with empty buffer. 00300 TQDataStream stream( (*d->current).state, IO_WriteOnly); 00301 browserExtension()->saveState(stream); 00302 } 00303 00304 void PageViewer::restoreHistoryEntry(const TQValueList<HistoryEntry>::Iterator& entry) 00305 { 00306 updateHistoryEntry(); 00307 00308 TQDataStream 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 TQValueList<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 TQString & /*errMsg*/ ) 00353 { 00354 d->stopAction->setEnabled(false); 00355 } 00356 00357 void PageViewer::urlSelected(const TQString &url, int button, int state, const TQString &_target, KParts::URLArgs args) 00358 { 00359 if (url.startsWith(TQString::fromLatin1( "javascript:" ), /*case-sensitive=*/false) ) 00360 { 00361 KHTMLPart::urlSelected(url,button,state,_target,args); 00362 } 00363 else 00364 { 00365 if (button == Qt::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 TQString& 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 TQObject *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 TQUObject 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 TQPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags kpf, mode_t) 00418 { 00419 m_url = kurl; 00420 TQString 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, TQT_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, TQT_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, TQT_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, TQT_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"