1
2#include "view.h"
3
4#include "formatter.h"
5#include "history.h"
6
7#include <dom/html_document.h>
8#include <dom/html_head.h>
9#include <dom/html_misc.h>
10
11#include <KAction>
12#include <KActionCollection>
13#include <KApplication>
14#include <KDebug>
15#include <KHTMLSettings>
16#include <KHTMLView>
17#include <KLocale>
18#include <KMenu>
19#include <KStandardDirs>
20#include <KToolBarPopupAction>
21#include <KGlobal>
22
23#include <QFileInfo>
24#include <QClipboard>
25#include <QTextStream>
26#include <QKeyEvent>
27#include <QEvent>
28#include <QScrollBar>
29
30using namespace KHC;
31
32View::View( QWidget *parentWidget, QObject *parent, KHTMLPart::GUIProfile prof, KActionCollection *col )
33 : KHTMLPart( parentWidget, parent, prof ), mState( Docu ), mActionCollection(col)
34{
35 setJScriptEnabled(false);
36 setJavaEnabled(false);
37 setPluginsEnabled(false);
38
39 mFormatter = new Formatter;
40 if ( !mFormatter->readTemplates() ) {
41 kDebug() << "Unable to read Formatter templates.";
42 }
43
44 m_fontScaleStepping = 10;
45
46 connect( this, SIGNAL( setWindowCaption( const QString & ) ),
47 this, SLOT( setTitle( const QString & ) ) );
48 connect( this, SIGNAL( popupMenu( const QString &, const QPoint& ) ),
49 this, SLOT( showMenu( const QString &, const QPoint& ) ) );
50
51 QString css = langLookup("common/kde-default.css");
52 if (!css.isEmpty())
53 {
54 QFile css_file(css);
55 if (css_file.open(QIODevice::ReadOnly))
56 {
57 QTextStream s(&css_file);
58 QString stylesheet = s.readAll();
59 preloadStyleSheet("help:/common/kde-default.css", stylesheet);
60 }
61 }
62
63 view()->installEventFilter( this );
64}
65
66View::~View()
67{
68 delete mFormatter;
69}
70
71void View::copySelectedText()
72{
73 kapp->clipboard()->setText( selectedText() );
74}
75
76bool View::openUrl( const KUrl &url )
77{
78 mState = Docu;
79 return KHTMLPart::openUrl( url );
80}
81
82void View::saveState( QDataStream &stream )
83{
84 stream << mState;
85 if ( mState == Docu )
86 KHTMLPart::saveState( stream );
87}
88
89void View::restoreState( QDataStream &stream )
90{
91 stream >> mState;
92 if ( mState == Docu )
93 KHTMLPart::restoreState( stream );
94}
95
96QString View::langLookup( const QString &fname )
97{
98 QStringList search;
99
100 // assemble the local search paths
101 const QStringList localDoc = KGlobal::dirs()->resourceDirs("html");
102
103 // look up the different languages
104 for (int id=localDoc.count()-1; id >= 0; --id)
105 {
106 QStringList langs = KGlobal::locale()->languageList();
107 langs.replaceInStrings("en_US", "en");
108 langs.append("en");
109 QStringList::ConstIterator lang;
110 for (lang = langs.constBegin(); lang != langs.constEnd(); ++lang)
111 search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
112 }
113
114 // try to locate the file
115 QStringList::Iterator it;
116 for (it = search.begin(); it != search.end(); ++it)
117 {
118 QFileInfo info(*it);
119 if (info.exists() && info.isFile() && info.isReadable())
120 return *it;
121
122 QString file = (*it).left((*it).lastIndexOf('/')) + "/index.docbook";
123 info.setFile(file);
124 if (info.exists() && info.isFile() && info.isReadable())
125 return *it;
126 }
127
128 return QString();
129}
130
131void View::setTitle( const QString &title )
132{
133 mTitle = title;
134}
135
136void View::beginSearchResult()
137{
138 mState = Search;
139
140 begin();
141 mSearchResult = "";
142}
143
144void View::writeSearchResult( const QString &str )
145{
146 write( str );
147 mSearchResult += str;
148}
149
150void View::endSearchResult()
151{
152 end();
153 if ( !mSearchResult.isEmpty() ) emit searchResultCacheAvailable();
154}
155
156void View::beginInternal( const KUrl &url )
157{
158 mInternalUrl = url;
159 begin();
160}
161
162KUrl View::internalUrl() const
163{
164 return mInternalUrl;
165}
166
167void View::lastSearch()
168{
169 if ( mSearchResult.isEmpty() ) return;
170
171 mState = Search;
172
173 begin();
174 write( mSearchResult );
175 end();
176}
177
178void View::slotIncFontSizes()
179{
180 setFontScaleFactor( fontScaleFactor() + m_fontScaleStepping );
181}
182
183void View::slotDecFontSizes()
184{
185 setFontScaleFactor( fontScaleFactor() - m_fontScaleStepping );
186}
187
188void View::showMenu( const QString& url, const QPoint& pos)
189{
190 KMenu pop(view());
191
192 if (url.isEmpty())
193 {
194 QAction *action;
195 action = mActionCollection->action("go_home");
196 if (action) pop.addAction( action );
197
198 pop.addSeparator();
199
200 action = mActionCollection->action("prevPage");
201 if (action) pop.addAction( action );
202 action = mActionCollection->action("nextPage");
203 if (action) pop.addAction( action);
204
205 pop.addSeparator();
206
207 pop.addAction( History::self().m_backAction );
208 pop.addAction( History::self().m_forwardAction );
209 }
210 else
211 {
212 QAction *action = pop.addAction(i18n("Copy Link Address"));
213 connect( action, SIGNAL( triggered() ), this, SLOT( slotCopyLink() ) );
214
215 mCopyURL = completeURL(url).url();
216 }
217
218 pop.exec(pos);
219}
220
221void View::slotCopyLink()
222{
223 QApplication::clipboard()->setText(mCopyURL);
224}
225
226static DOM::HTMLLinkElement findLink(const DOM::NodeList& links, const char *rel)
227{
228 for (unsigned i = 0; i <= links.length(); i++) {
229 DOM::HTMLLinkElement link(links.item(i));
230 if (link.isNull())
231 continue;
232
233 if (link.rel() == rel)
234 return link;
235 }
236 return DOM::HTMLLinkElement();
237}
238
239bool View::prevPage(bool checkOnly)
240{
241 const DOM::NodeList links = document().getElementsByTagName("link");
242
243 KUrl prevURL = urlFromLinkNode( findLink(links, "prev") );
244
245 if (!prevURL.isValid())
246 return false;
247
248 if (!checkOnly)
249 emit browserExtension()->openUrlRequest(prevURL);
250 return true;
251}
252
253bool View::nextPage(bool checkOnly)
254{
255 const DOM::NodeList links = document().getElementsByTagName("link");
256
257 KUrl nextURL = urlFromLinkNode( findLink(links, "next") );
258
259 if (!nextURL.isValid())
260 return false;
261
262 if (!checkOnly)
263 emit browserExtension()->openUrlRequest(nextURL);
264 return true;
265}
266
267bool View::eventFilter( QObject *o, QEvent *e )
268{
269 if ( e->type() != QEvent::KeyPress ||
270 htmlDocument().links().length() == 0 )
271 return KHTMLPart::eventFilter( o, e );
272
273 QKeyEvent *ke = static_cast<QKeyEvent *>( e );
274 if ( ke->modifiers() & Qt::ShiftModifier && ke->key() == Qt::Key_Space ) {
275 // If we're on the first page, it does not make sense to go back.
276 if ( baseURL().path().endsWith( QLatin1String("/index.html") ) )
277 return KHTMLPart::eventFilter( o, e );
278
279 const QScrollBar * const scrollBar = view()->verticalScrollBar();
280 if ( scrollBar->value() == scrollBar->minimum() ) {
281 if (prevPage())
282 return true;
283 }
284 } else if ( ke->key() == Qt::Key_Space ) {
285 const QScrollBar * const scrollBar = view()->verticalScrollBar();
286 if ( scrollBar->value() == scrollBar->maximum() ) {
287 if (nextPage())
288 return true;
289 }
290 }
291 return KHTMLPart::eventFilter( o, e );
292}
293
294KUrl View::urlFromLinkNode( const DOM::HTMLLinkElement &link ) const
295{
296 if ( link.isNull() )
297 return KUrl();
298
299 DOM::DOMString domHref = link.href();
300 if (domHref.isNull())
301 return KUrl();
302
303 return KUrl(baseURL(), domHref.string());
304}
305
306void View::slotReload( const KUrl &url )
307{
308 const_cast<KHTMLSettings *>( settings() )->init( KGlobal::config().data() );
309 KParts::OpenUrlArguments args = arguments();
310 args.setReload( true );
311 setArguments( args );
312 if ( url.isEmpty() )
313 openUrl( baseURL() );
314 else
315 openUrl( url );
316}
317
318#include "view.moc"
319// vim:ts=2:sw=2:et
320