akregator/src

pageviewer.cpp
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>
5  2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, permission is given to link this program
22  with any edition of TQt, and distribute the resulting executable,
23  without including the source code for TQt in the source distribution.
24 */
25 
26 #include "akregatorconfig.h"
27 #include "akregator_run.h"
28 #include "feediconmanager.h"
29 #include "pageviewer.h"
30 #include "viewer.h"
31 
32 #include <tdeaction.h>
33 #include <tdeapplication.h>
34 #include <kbookmark.h>
35 #include <kbookmarkmanager.h>
36 #include <tdeconfig.h>
37 #include <tdeglobalsettings.h>
38 #include <tdehtml_settings.h>
39 #include <tdehtmlview.h>
40 #include <kiconloader.h>
41 #include <tdelocale.h>
42 #include <tdepopupmenu.h>
43 #include <kstandarddirs.h>
44 #include <tdestdaccel.h>
45 #include <tdeparts/browserinterface.h>
46 
47 #include <tqclipboard.h>
48 #include <tqcstring.h>
49 #include <tqdatastream.h>
50 #include <tqdatetime.h>
51 #include <tqfile.h>
52 #include <tqmetaobject.h>
53 #include <tqscrollview.h>
54 #include <tqstring.h>
55 #include <tqvaluelist.h>
56 #include <private/tqucomextra_p.h>
57 
58 #include <cstdlib>
59 using std::abs;
60 
61 namespace Akregator {
62 
63 
64 // taken from KDevelop
65 class PageViewer::HistoryEntry
66 {
67  public:
68 
69  KURL url;
70  TQString title;
71  TQByteArray state;
72  int id;
73 
74  HistoryEntry() {}
75  HistoryEntry(const KURL& u, const TQString& t=TQString()): url(u), title(t)
76  {
77  id = abs( TQTime::currentTime().msecsTo( TQTime() ) ); // nasty, but should provide a reasonably unique number
78  }
79 
80 };
81 
82 class PageViewer::PageViewerPrivate
83 {
84  public:
85 
86  TQValueList<HistoryEntry> history;
87  TQValueList<HistoryEntry>::Iterator current;
88 
89  TDEToolBarPopupAction* backAction;
90  TDEToolBarPopupAction* forwardAction;
91  TDEAction* reloadAction;
92  TDEAction* stopAction;
93 
94  TQString caption;
95 };
96 
97 
98 PageViewer::PageViewer(TQWidget *parent, const char *name)
99  : Viewer(parent, name), d(new PageViewerPrivate)
100 {
101  // this hack is necessary since the part looks for []HTML Settings] in
102  // TDEGlobal::config() by default, which is wrong when running in Kontact
103  TDEHTMLSettings* s = const_cast<TDEHTMLSettings*> (settings());
104  s->init(Settings::self()->config());
105 
106  setXMLFile(locate("data", "akregator/pageviewer.rc"), true);
107 
108  TQPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward();
109 
110  d->backAction = new TDEToolBarPopupAction(backForward.first,
111  TDEStdAccel::shortcut(TDEStdAccel::Back), this,
112  TQ_SLOT(slotBack()), actionCollection(),
113  "pageviewer_back");
114 
115  connect(d->backAction->popupMenu(), TQ_SIGNAL(aboutToShow()),
116  this, TQ_SLOT(slotBackAboutToShow()));
117  connect(d->backAction->popupMenu(), TQ_SIGNAL(activated(int)),
118  this, TQ_SLOT(slotPopupActivated(int)));
119 
120 
121  d->forwardAction = new TDEToolBarPopupAction(backForward.second,
122  TDEStdAccel::shortcut(TDEStdAccel::Forward),this,
123  TQ_SLOT(slotForward()), actionCollection(),
124  "pageviewer_forward");
125 
126  connect(d->forwardAction->popupMenu(), TQ_SIGNAL(aboutToShow()),
127  this, TQ_SLOT(slotForwardAboutToShow()));
128  connect(d->forwardAction->popupMenu(), TQ_SIGNAL(activated(int)),
129  this, TQ_SLOT(slotPopupActivated(int)));
130 
131  d->reloadAction = new TDEAction(i18n("Reload"), "reload", 0,
132  this, TQ_SLOT(slotReload()),
133  actionCollection(), "pageviewer_reload");
134  d->stopAction = new TDEAction(KStdGuiItem::guiItem(KStdGuiItem::Stop), 0,
135  this, TQ_SLOT(slotStop()),
136  actionCollection(), "pageviewer_stop");
137 
138  //connect( this, TQ_SIGNAL(popupMenu(const TQString &, const TQPoint &)), this, TQ_SLOT(slotPopupMenu(const TQString &, const TQPoint &)));
139 
140  d->backAction->setEnabled(false);
141  d->forwardAction->setEnabled(false);
142  d->stopAction->setEnabled(false);
143 
144  connect( this, TQ_SIGNAL(setWindowCaption (const TQString &)),
145  this, TQ_SLOT(slotSetCaption (const TQString &)) );
146 
147  connect(this, TQ_SIGNAL(started(TDEIO::Job *)), this, TQ_SLOT(slotStarted(TDEIO::Job* )));
148  connect(this, TQ_SIGNAL(completed()), this, TQ_SLOT(slotCompleted()));
149  connect(this, TQ_SIGNAL(canceled(const TQString &)), this, TQ_SLOT(slotCancelled(const TQString &)));
150 
151  d->current = d->history.end();
152 
153  // uncomment this to load konq plugins (doesn't work properly and clutters the GUI)
154  //loadPlugins( partObject(), this, instance() );
155 
156 }
157 
158 PageViewer::~PageViewer()
159 {
160  delete d;
161  d = 0;
162 }
163 
164 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
165 void PageViewer::slotBack()
166 {
167  if ( d->current != d->history.begin() )
168  {
169  TQValueList<HistoryEntry>::Iterator tmp = d->current;
170  --tmp;
171  restoreHistoryEntry(tmp);
172  }
173 }
174 
175 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
176 void PageViewer::slotForward()
177 {
178  if ( d->current != d->history.fromLast() && d->current != d->history.end() )
179  {
180  TQValueList<HistoryEntry>::Iterator tmp = d->current;
181  ++tmp;
182  restoreHistoryEntry(tmp);
183  }
184 }
185 
186 void PageViewer::slotBackAboutToShow()
187 {
188  TDEPopupMenu *popup = d->backAction->popupMenu();
189  popup->clear();
190 
191  if ( d->current == d->history.begin() )
192  return;
193 
194  TQValueList<HistoryEntry>::Iterator it = d->current;
195  --it;
196 
197  int i = 0;
198  while( i < 10 )
199  {
200  if ( it == d->history.begin() )
201  {
202  popup->insertItem( (*it).title, (*it).id );
203  return;
204  }
205 
206  popup->insertItem( (*it).title, (*it).id );
207  ++i;
208  --it;
209  }
210 }
211 
212 void PageViewer::slotForwardAboutToShow()
213 {
214  TDEPopupMenu *popup = d->forwardAction->popupMenu();
215  popup->clear();
216 
217  if ( d->current == d->history.fromLast() )
218  return;
219 
220  TQValueList<HistoryEntry>::Iterator it = d->current;
221  ++it;
222 
223  int i = 0;
224  while( i < 10 )
225  {
226  if ( it == d->history.fromLast() )
227  {
228  popup->insertItem( (*it).title, (*it).id );
229  return;
230  }
231 
232  popup->insertItem( (*it).title, (*it).id );
233  ++i;
234  ++it;
235  }
236 }
237 
238 
239 void PageViewer::slotReload()
240 {
241  openURL( url() );
242 }
243 
244 void PageViewer::slotStop()
245 {
246  closeURL();
247 }
248 
249 bool PageViewer::openURL(const KURL& url)
250 {
251  updateHistoryEntry(); // update old history entry before switching to the new one
252  emit started(0);
253 
254  bool val = TDEHTMLPart::openURL(url);
255 
256  addHistoryEntry(url); // add new URL to history
257 
258  d->backAction->setEnabled( d->current != d->history.begin() );
259  d->forwardAction->setEnabled( d->current != d->history.fromLast() );
260 
261  TQString favicon = FeedIconManager::self()->iconLocation(url);
262  if (!favicon.isEmpty())
263  emit setTabIcon(TQPixmap(TDEGlobal::dirs()->findResource("cache", favicon+".png")));
264  else
265  emit setTabIcon(SmallIcon("text-html"));
266 
267  return val;
268 }
269 
270 
271 void PageViewer::slotOpenURLRequest(const KURL& url, const KParts::URLArgs& args)
272 {
273  updateHistoryEntry();
274  if (args.doPost())
275  {
276  browserExtension()->setURLArgs(args);
277  openURL(url);
278  }
279 
280 }
281 
282 void PageViewer::slotPopupActivated( int id )
283 {
284  TQValueList<HistoryEntry>::Iterator it = d->history.begin();
285  while( it != d->history.end() )
286  {
287  if ( (*it).id == id )
288  {
289  restoreHistoryEntry(it);
290  return;
291  }
292  ++it;
293  }
294 }
295 
296 void PageViewer::updateHistoryEntry()
297 {
298  (*d->current).title = d->caption;
299  (*d->current).state = TQByteArray(); // Start with empty buffer.
300  TQDataStream stream( (*d->current).state, IO_WriteOnly);
301  browserExtension()->saveState(stream);
302 }
303 
304 void PageViewer::restoreHistoryEntry(const TQValueList<HistoryEntry>::Iterator& entry)
305 {
306  updateHistoryEntry();
307 
308  TQDataStream stream( (*entry).state, IO_ReadOnly );
309  browserExtension()->restoreState( stream );
310  d->current = entry;
311  d->backAction->setEnabled( d->current != d->history.begin() );
312  d->forwardAction->setEnabled( d->current != d->history.fromLast() );
313  //openURL( entry.url ); // TODO read state
314 
315 
316 }
317 
318 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
319 void PageViewer::addHistoryEntry(const KURL& url)
320 {
321  TQValueList<HistoryEntry>::Iterator it = d->current;
322 
323  // if We're not already the last entry, we truncate the list here before adding an entry
324  if ( it != d->history.end() && it != d->history.fromLast() )
325  {
326  d->history.erase( ++it, d->history.end() );
327  }
328  HistoryEntry newEntry( url, url.url() );
329 
330  // Only save the new entry if it is different from the last
331  if ( newEntry.url != (*d->current).url )
332  {
333  d->history.append( newEntry );
334  d->current = d->history.fromLast();
335  }
336  updateHistoryEntry();
337 }
338 
339 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
340 void PageViewer::slotStarted( TDEIO::Job * )
341 {
342  d->stopAction->setEnabled(true);
343 }
344 
345 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
346 void PageViewer::slotCompleted( )
347 {
348  d->stopAction->setEnabled(false);
349 }
350 
351 // Taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
352 void PageViewer::slotCancelled( const TQString & /*errMsg*/ )
353 {
354  d->stopAction->setEnabled(false);
355 }
356 
357 void PageViewer::urlSelected(const TQString &url, int button, int state, const TQString &_target, KParts::URLArgs args)
358 {
359  if (url.startsWith(TQString::fromLatin1( "javascript:" ), /*case-sensitive=*/false) )
360  {
361  TDEHTMLPart::urlSelected(url,button,state,_target,args);
362  }
363  else
364  {
365  if (button == TQt::LeftButton)
366  {
367  m_url = completeURL(url);
368  browserExtension()->setURLArgs(args);
369  slotOpenLinkInThisTab();
370  }
371  else
372  {
373  Viewer::urlSelected(url,button,state,_target,args);
374  }
375  }
376 }
377 
378 void PageViewer::slotSetCaption(const TQString& cap)
379 {
380  d->caption = cap;
381  (*d->current).title = cap;
382 }
383 
384 void PageViewer::slotPaletteOrFontChanged()
385 {
386  kdDebug() << "PageViewer::slotPaletteOrFontChanged()" << endl;
387  // taken from KonqView (tdebase/konqueror/konq_view.cpp)
388 
389  TQObject *obj = KParts::BrowserExtension::childObject(this);
390  if ( !obj ) // not all views have a browser extension !
391  return;
392 
393  int id = obj->metaObject()->findSlot("reparseConfiguration()");
394  if (id == -1)
395  return;
396  TQUObject o[1];
397 
398  obj->tqt_invoke(id, o);
399 
400  // this hack is necessary since the part looks for []HTML Settings] in
401  // TDEGlobal::config() by default, which is wrong when running in Kontact
402  // NOTE: when running in Kontact, immediate updating doesn't work
403  TDEHTMLSettings* s = const_cast<TDEHTMLSettings*> (settings());
404  s->init(Settings::self()->config());
405 }
406 
407 void PageViewer::slotGlobalBookmarkArticle()
408 {
409  KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager();
410  KBookmarkGroup grp = mgr->root();
411  grp.addBookmark(mgr, d->caption, toplevelURL());
412  mgr->emitChanged(grp);
413  mgr->save();
414 }
415 
416 
417 void PageViewer::slotPopupMenu(KXMLGUIClient*, const TQPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags kpf, mode_t)
418 {
419  m_url = kurl;
420  TQString url = kurl.url(); // maximal url confusion
421 
422  const bool showReload = (kpf & KParts::BrowserExtension::ShowReload) != 0;
423  const bool showNavigationItems = (kpf & KParts::BrowserExtension::ShowNavigationItems) != 0;
424  const bool isLink = (kpf & (KParts::BrowserExtension::ShowNavigationItems | KParts::BrowserExtension::ShowTextSelectionItems)) == 0;
425  const bool isSelection = (kpf & KParts::BrowserExtension::ShowTextSelectionItems) != 0;
426 
427  TDEPopupMenu popup(this->widget());
428 
429  int idNewWindow = -2;
430  if (isLink)
431  {
432  idNewWindow = popup.insertItem(SmallIcon("tab_new"),i18n("Open Link in New &Tab"), this, TQ_SLOT(slotOpenLinkInForegroundTab()));
433  popup.setWhatsThis(idNewWindow, i18n("<b>Open Link in New Tab</b><p>Opens current link in a new tab."));
434  popup.insertItem(SmallIcon("window-new"), i18n("Open Link in External &Browser"), this, TQ_SLOT(slotOpenLinkInBrowser()));
435 
436  popup.insertSeparator();
437  action("savelinkas")->plug(&popup);
438  TDEAction* copylinkaddress = action("copylinkaddress");
439  if (copylinkaddress)
440  {
441  copylinkaddress->plug( &popup);
442  //popup.insertSeparator();
443  }
444  }
445  else // we are not on a link
446  {
447  if (showNavigationItems)
448  {
449  d->backAction->plug( &popup );
450  d->forwardAction->plug( &popup );
451  }
452 
453  if (showReload)
454  d->reloadAction->plug(&popup);
455 
456  d->stopAction->plug(&popup);
457 
458  popup.insertSeparator();
459 
460  if (isSelection)
461  {
462  action("viewer_copy")->plug(&popup);
463  popup.insertSeparator();
464  }
465 
466  TDEAction* incFontAction = this->action("incFontSizes");
467  TDEAction* decFontAction = this->action("decFontSizes");
468  if ( incFontAction && decFontAction )
469  {
470  incFontAction->plug( &popup );
471  decFontAction->plug( &popup );
472  popup.insertSeparator();
473  }
474 
475  popup.insertItem(SmallIcon("window-new"), i18n("Open Page in External Browser"), this, TQ_SLOT(slotOpenLinkInBrowser()));
476 
477  action("viewer_print")->plug(&popup);
478  popup.insertSeparator();
479 
480  TDEAction *ac = action("setEncoding");
481  if (ac)
482  ac->plug(&popup);
483  popup.insertItem(SmallIcon("bookmark_add"),i18n("Add to Konqueror Bookmarks"), this, TQ_SLOT(slotGlobalBookmarkArticle()));
484  }
485 
486  int r = popup.exec(p);
487 
488  if (r == idNewWindow)
489  {
490  KURL kurl;
491  if (!KURL(url).path().startsWith("/"))
492  {
493  kdDebug() << "processing relative url: " << url << endl;
494  if (url.startsWith("#"))
495  {
496  kurl = KURL(PageViewer::url());
497  kurl.setRef(url.mid(1));
498  }
499  else
500  kurl = KURL(PageViewer::url().upURL().url(true)+url);
501  }
502  else
503  kurl = KURL(url);
504 // kurl.addPath(url);
505  if (kurl.isValid()) {
506  //slotOpenInNewWindow(kurl);
507  }
508 // ( kurl );
509  }
510 }
511 
512 } // namespace Akregator
513 
514 #include "pageviewer.moc"