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 | |
30 | using namespace KHC; |
31 | |
32 | View::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 | |
66 | View::~View() |
67 | { |
68 | delete mFormatter; |
69 | } |
70 | |
71 | void View::copySelectedText() |
72 | { |
73 | kapp->clipboard()->setText( selectedText() ); |
74 | } |
75 | |
76 | bool View::openUrl( const KUrl &url ) |
77 | { |
78 | mState = Docu; |
79 | return KHTMLPart::openUrl( url ); |
80 | } |
81 | |
82 | void View::saveState( QDataStream &stream ) |
83 | { |
84 | stream << mState; |
85 | if ( mState == Docu ) |
86 | KHTMLPart::saveState( stream ); |
87 | } |
88 | |
89 | void View::restoreState( QDataStream &stream ) |
90 | { |
91 | stream >> mState; |
92 | if ( mState == Docu ) |
93 | KHTMLPart::restoreState( stream ); |
94 | } |
95 | |
96 | QString 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 | |
131 | void View::setTitle( const QString &title ) |
132 | { |
133 | mTitle = title; |
134 | } |
135 | |
136 | void View::beginSearchResult() |
137 | { |
138 | mState = Search; |
139 | |
140 | begin(); |
141 | mSearchResult = "" ; |
142 | } |
143 | |
144 | void View::writeSearchResult( const QString &str ) |
145 | { |
146 | write( str ); |
147 | mSearchResult += str; |
148 | } |
149 | |
150 | void View::endSearchResult() |
151 | { |
152 | end(); |
153 | if ( !mSearchResult.isEmpty() ) emit searchResultCacheAvailable(); |
154 | } |
155 | |
156 | void View::beginInternal( const KUrl &url ) |
157 | { |
158 | mInternalUrl = url; |
159 | begin(); |
160 | } |
161 | |
162 | KUrl View::internalUrl() const |
163 | { |
164 | return mInternalUrl; |
165 | } |
166 | |
167 | void View::lastSearch() |
168 | { |
169 | if ( mSearchResult.isEmpty() ) return; |
170 | |
171 | mState = Search; |
172 | |
173 | begin(); |
174 | write( mSearchResult ); |
175 | end(); |
176 | } |
177 | |
178 | void View::slotIncFontSizes() |
179 | { |
180 | setFontScaleFactor( fontScaleFactor() + m_fontScaleStepping ); |
181 | } |
182 | |
183 | void View::slotDecFontSizes() |
184 | { |
185 | setFontScaleFactor( fontScaleFactor() - m_fontScaleStepping ); |
186 | } |
187 | |
188 | void View::( 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 | |
221 | void View::slotCopyLink() |
222 | { |
223 | QApplication::clipboard()->setText(mCopyURL); |
224 | } |
225 | |
226 | static 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 | |
239 | bool 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 | |
253 | bool 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 | |
267 | bool 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 | |
294 | KUrl 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 | |
306 | void 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 | |