1 | /* |
2 | * This file is part of the KDE Help Center |
3 | * |
4 | * Copyright (C) 1999 Matthias Elter (me@kde.org) |
5 | * 2001 Stephan Kulow (coolo@kde.org) |
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 | |
22 | #include "mainwindow.h" |
23 | |
24 | #include "history.h" |
25 | #include "view.h" |
26 | #include "searchengine.h" |
27 | #include "fontdialog.h" |
28 | #include "prefs.h" |
29 | |
30 | #include <KAction> |
31 | #include <KActionCollection> |
32 | #include <KApplication> |
33 | #include <KConfig> |
34 | #include <KIcon> |
35 | #include <KIconLoader> |
36 | #include <KMimeType> |
37 | #include <KRun> |
38 | #include <KAboutData> |
39 | #include <KDebug> |
40 | #include <KHTMLView> |
41 | #include <KHTMLSettings> |
42 | #include <KStatusBar> |
43 | #include <KStandardShortcut> |
44 | #include <KDialog> |
45 | #include <KLocale> |
46 | #include <KStandardAction> |
47 | #include <KXmlGuiWindow> |
48 | #include <KStartupInfo> |
49 | #include <KConfigGroup> |
50 | |
51 | #include <QtDBus/QDBusConnection> |
52 | #include <QSplitter> |
53 | #include <QTextEdit> |
54 | #include <QLayout> |
55 | #include <QVBoxLayout> |
56 | #include <QFrame> |
57 | #include <QList> |
58 | #include <QBoxLayout> |
59 | |
60 | #include <stdlib.h> |
61 | #include <assert.h> |
62 | #include <kglobal.h> |
63 | |
64 | using namespace KHC; |
65 | |
66 | class LogDialog : public KDialog |
67 | { |
68 | public: |
69 | LogDialog( QWidget *parent = 0 ) |
70 | : KDialog( parent ) |
71 | { |
72 | setCaption( i18n("Search Error Log" ) ); |
73 | setButtons( Ok ); |
74 | |
75 | QFrame *topFrame = new QFrame( this ); |
76 | setMainWidget( topFrame ); |
77 | |
78 | QBoxLayout *topLayout = new QVBoxLayout( topFrame ); |
79 | |
80 | mTextView = new QTextEdit( topFrame ); |
81 | mTextView->setReadOnly ( true ); |
82 | mTextView->setWordWrapMode( QTextOption::NoWrap ); |
83 | topLayout->addWidget( mTextView ); |
84 | |
85 | KConfigGroup cg = KGlobal::config()->group( "logdialog" ); |
86 | restoreDialogSize( cg ); |
87 | } |
88 | |
89 | ~LogDialog() |
90 | { |
91 | KConfigGroup cg = KGlobal::config()->group( "logdialog" ); |
92 | KDialog::saveDialogSize( cg ); |
93 | } |
94 | |
95 | void setLog( const QString &log ) |
96 | { |
97 | mTextView->setText( log ); |
98 | } |
99 | |
100 | private: |
101 | QTextEdit *mTextView; |
102 | }; |
103 | |
104 | |
105 | MainWindow::MainWindow() |
106 | : KXmlGuiWindow(0), |
107 | mLogDialog( 0 ) |
108 | { |
109 | setObjectName( QLatin1String( "MainWindow" ) ); |
110 | |
111 | QDBusConnection::sessionBus().registerObject("/KHelpCenter" , this, QDBusConnection::ExportScriptableSlots); |
112 | mSplitter = new QSplitter( this ); |
113 | |
114 | mDoc = new View( mSplitter, this, KHTMLPart::DefaultGUI, actionCollection() ); |
115 | connect( mDoc, SIGNAL( setWindowCaption( const QString & ) ), |
116 | SLOT( setCaption( const QString & ) ) ); |
117 | connect( mDoc, SIGNAL( setStatusBarText( const QString & ) ), |
118 | SLOT( statusBarMessage( const QString & ) ) ); |
119 | connect( mDoc, SIGNAL( onURL( const QString & ) ), |
120 | SLOT( statusBarMessage( const QString & ) ) ); |
121 | connect( mDoc, SIGNAL( started( KIO::Job * ) ), |
122 | SLOT( slotStarted( KIO::Job * ) ) ); |
123 | connect( mDoc, SIGNAL( completed() ), |
124 | SLOT( documentCompleted() ) ); |
125 | connect( mDoc, SIGNAL( searchResultCacheAvailable() ), |
126 | SLOT( enableLastSearchAction() ) ); |
127 | |
128 | connect( mDoc, SIGNAL( selectionChanged() ), |
129 | SLOT( enableCopyTextAction() ) ); |
130 | |
131 | statusBar()->insertItem(i18n("Preparing Index" ), 0, 1); |
132 | statusBar()->setItemAlignment(0, Qt::AlignLeft | Qt::AlignVCenter); |
133 | |
134 | connect( mDoc->browserExtension(), |
135 | SIGNAL( openUrlRequest( const KUrl &, |
136 | const KParts::OpenUrlArguments &, const KParts::BrowserArguments & ) ), |
137 | SLOT( slotOpenURLRequest( const KUrl &, |
138 | const KParts::OpenUrlArguments &, const KParts::BrowserArguments & ) ) ); |
139 | |
140 | mNavigator = new Navigator( mDoc, mSplitter, "nav" ); |
141 | connect( mNavigator, SIGNAL( itemSelected( const QString & ) ), |
142 | SLOT( viewUrl( const QString & ) ) ); |
143 | connect( mNavigator, SIGNAL( glossSelected( const GlossaryEntry & ) ), |
144 | SLOT( slotGlossSelected( const GlossaryEntry & ) ) ); |
145 | |
146 | mSplitter->insertWidget(0, mNavigator); |
147 | mSplitter->setStretchFactor(mSplitter->indexOf(mNavigator), 0); |
148 | setCentralWidget( mSplitter ); |
149 | QList<int> sizes; |
150 | sizes << 220 << 580; |
151 | mSplitter->setSizes(sizes); |
152 | |
153 | KSharedConfig::Ptr cfg = KGlobal::config(); |
154 | { |
155 | KConfigGroup configGroup( cfg, "General" ); |
156 | if ( configGroup.readEntry( "UseKonqSettings" , true) ) { |
157 | KConfig konqCfg( "konquerorrc" ); |
158 | const_cast<KHTMLSettings *>( mDoc->settings() )->init( &konqCfg ); |
159 | } |
160 | const int fontScaleFactor = configGroup.readEntry( "Font zoom factor" , 100 ); |
161 | mDoc->setFontScaleFactor( fontScaleFactor ); |
162 | } |
163 | |
164 | setupActions(); |
165 | |
166 | foreach (QAction *act, mDoc->actionCollection()->actions()) |
167 | actionCollection()->addAction(act->objectName(), act); |
168 | |
169 | setupGUI(QSize(800, 600), ToolBar | Keys | StatusBar | Create); |
170 | setAutoSaveSettings(); |
171 | |
172 | History::self().installMenuBarHook( this ); |
173 | |
174 | connect( &History::self(), SIGNAL( goInternalUrl( const KUrl & ) ), |
175 | mNavigator, SLOT( openInternalUrl( const KUrl & ) ) ); |
176 | connect( &History::self(), SIGNAL( goUrl( const KUrl & ) ), |
177 | mNavigator, SLOT( selectItem( const KUrl & ) ) ); |
178 | |
179 | statusBarMessage(i18n("Ready" )); |
180 | enableCopyTextAction(); |
181 | |
182 | readConfig(); |
183 | } |
184 | |
185 | MainWindow::~MainWindow() |
186 | { |
187 | writeConfig(); |
188 | } |
189 | |
190 | void MainWindow::enableCopyTextAction() |
191 | { |
192 | mCopyText->setEnabled( mDoc->hasSelection() ); |
193 | } |
194 | |
195 | void MainWindow::saveProperties( KConfigGroup &config ) |
196 | { |
197 | kDebug(); |
198 | config.writePathEntry( "URL" , mDoc->baseURL().url() ); |
199 | } |
200 | |
201 | void MainWindow::readProperties( const KConfigGroup &config ) |
202 | { |
203 | kDebug(); |
204 | mDoc->slotReload( KUrl( config.readPathEntry( "URL" , QString() ) ) ); |
205 | } |
206 | |
207 | void MainWindow::readConfig() |
208 | { |
209 | KConfigGroup config(KGlobal::config(), "MainWindowState" ); |
210 | QList<int> sizes = config.readEntry( "Splitter" , QList<int>() ); |
211 | if ( sizes.count() == 2 ) { |
212 | mSplitter->setSizes( sizes ); |
213 | } |
214 | |
215 | mNavigator->readConfig(); |
216 | } |
217 | |
218 | void MainWindow::writeConfig() |
219 | { |
220 | KConfigGroup config(KGlobal::config(), "MainWindowState" ); |
221 | config.writeEntry( "Splitter" , mSplitter->sizes() ); |
222 | |
223 | mNavigator->writeConfig(); |
224 | |
225 | Prefs::self()->writeConfig(); |
226 | } |
227 | |
228 | void MainWindow::setupActions() |
229 | { |
230 | actionCollection()->addAction( KStandardAction::Quit, this, SLOT( close() ) ); |
231 | actionCollection()->addAction( KStandardAction::Print, this, SLOT( print() ) ); |
232 | |
233 | KAction *prevPage = actionCollection()->addAction( "prevPage" ); |
234 | prevPage->setText( i18n( "Previous Page" ) ); |
235 | prevPage->setShortcut( Qt::CTRL+Qt::Key_PageUp ); |
236 | prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); |
237 | connect( prevPage, SIGNAL( triggered() ), mDoc, SLOT( prevPage() ) ); |
238 | |
239 | KAction *nextPage = actionCollection()->addAction( "nextPage" ); |
240 | nextPage->setText( i18n( "Next Page" ) ); |
241 | nextPage->setShortcut( Qt::CTRL + Qt::Key_PageDown ); |
242 | nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); |
243 | connect( nextPage, SIGNAL( triggered() ), mDoc, SLOT( nextPage() ) ); |
244 | |
245 | QAction *home = KStandardAction::home( this, SLOT( slotShowHome() ), this ); |
246 | actionCollection()->addAction( home->objectName(), home ); |
247 | home->setText(i18n("Table of &Contents" )); |
248 | home->setToolTip(i18n("Table of contents" )); |
249 | home->setWhatsThis(i18n("Go back to the table of contents" )); |
250 | |
251 | mCopyText = KStandardAction::copy( this, SLOT(slotCopySelectedText()), this ); |
252 | actionCollection()->addAction( "copy_text" , mCopyText ); |
253 | |
254 | mLastSearchAction = actionCollection()->addAction( QLatin1String("lastsearch" ) ); |
255 | mLastSearchAction->setText( i18n("&Last Search Result" ) ); |
256 | mLastSearchAction->setEnabled( false ); |
257 | connect( mLastSearchAction, SIGNAL( triggered() ), this, SLOT( slotLastSearch() ) ); |
258 | /* |
259 | QAction *action = actionCollection()->addAction( QLatin1String("build_index") ); |
260 | action->setText( i18n("Build Search Index...") ); |
261 | connect( action, SIGNAL( triggered() ), mNavigator, SLOT( showIndexDialog() ) ); |
262 | |
263 | KConfigGroup debugGroup( KGlobal::config(), "Debug" ); |
264 | if ( debugGroup.readEntry( "SearchErrorLog", false) ) { |
265 | action = actionCollection()->addAction(QLatin1String("show_search_stderr")); |
266 | action->setText( i18n("Show Search Error Log") ); |
267 | connect( action, SIGNAL( triggered() ), this, SLOT( showSearchStderr() ) ); |
268 | } |
269 | */ |
270 | History::self().setupActions( actionCollection() ); |
271 | |
272 | QAction *action = actionCollection()->addAction(QLatin1String("configure_fonts" )); |
273 | action->setText( i18n( "Configure Fonts..." ) ); |
274 | connect( action, SIGNAL( triggered() ), this, SLOT( slotConfigureFonts() ) ); |
275 | |
276 | action = actionCollection()->addAction(QLatin1String("incFontSizes" )); |
277 | action->setText( i18n( "Increase Font Sizes" ) ); |
278 | action->setIcon( KIcon( QLatin1String("zoom-in" ) ) ); |
279 | connect( action, SIGNAL( triggered() ), this, SLOT( slotIncFontSizes() ) ); |
280 | |
281 | action = actionCollection()->addAction(QLatin1String("decFontSizes" )); |
282 | action->setText( i18n( "Decrease Font Sizes" ) ); |
283 | action->setIcon( KIcon( QLatin1String("zoom-out" ) ) ); |
284 | connect( action, SIGNAL( triggered() ), this, SLOT( slotDecFontSizes() ) ); |
285 | } |
286 | |
287 | void MainWindow::slotCopySelectedText() |
288 | { |
289 | mDoc->copySelectedText(); |
290 | } |
291 | |
292 | void MainWindow::print() |
293 | { |
294 | mDoc->view()->print(); |
295 | } |
296 | |
297 | void MainWindow::slotStarted(KIO::Job *job) |
298 | { |
299 | if (job) |
300 | connect(job, SIGNAL(infoMessage( KJob *, const QString &, const QString &)), |
301 | SLOT(slotInfoMessage(KJob *, const QString &))); |
302 | |
303 | History::self().updateActions(); |
304 | } |
305 | |
306 | void MainWindow::goInternalUrl( const KUrl &url ) |
307 | { |
308 | mDoc->closeUrl(); |
309 | slotOpenURLRequest( url ); |
310 | } |
311 | |
312 | void MainWindow::slotOpenURLRequest( const KUrl &url, |
313 | const KParts::OpenUrlArguments &args, |
314 | const KParts::BrowserArguments &browserArgs ) |
315 | { |
316 | kDebug( 1400 ) << url.url(); |
317 | |
318 | mNavigator->selectItem( url ); |
319 | viewUrl( url, args, browserArgs ); |
320 | } |
321 | |
322 | void MainWindow::viewUrl( const QString &url ) |
323 | { |
324 | viewUrl( KUrl( url ) ); |
325 | } |
326 | |
327 | void MainWindow::viewUrl( const KUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs ) |
328 | { |
329 | stop(); |
330 | |
331 | QString proto = url.protocol().toLower(); |
332 | |
333 | if ( proto == "khelpcenter" ) { |
334 | History::self().createEntry(); |
335 | mNavigator->openInternalUrl( url ); |
336 | return; |
337 | } |
338 | |
339 | bool own = false; |
340 | |
341 | if ( proto == QLatin1String("help" ) |
342 | || proto == QLatin1String("glossentry" ) |
343 | || proto == QLatin1String("about" ) |
344 | || proto == QLatin1String("man" ) |
345 | || proto == QLatin1String("info" ) |
346 | || proto == QLatin1String("cgi" ) |
347 | || proto == QLatin1String("ghelp" )) |
348 | own = true; |
349 | else if ( url.isLocalFile() ) { |
350 | KMimeType::Ptr mime = KMimeType::findByPath( url.toLocalFile() ); |
351 | if ( mime->is("text/html" ) ) |
352 | own = true; |
353 | } |
354 | |
355 | if ( !own ) { |
356 | new KRun( url,this ); |
357 | return; |
358 | } |
359 | |
360 | History::self().createEntry(); |
361 | |
362 | mDoc->setArguments( args ); |
363 | mDoc->browserExtension()->setBrowserArguments( browserArgs ); |
364 | |
365 | if ( proto == QLatin1String("glossentry" ) ) { |
366 | QString decodedEntryId = QUrl::fromPercentEncoding( url.encodedPathAndQuery().toAscii() ); |
367 | slotGlossSelected( mNavigator->glossEntry( decodedEntryId ) ); |
368 | mNavigator->slotSelectGlossEntry( decodedEntryId ); |
369 | } else { |
370 | mDoc->openUrl( url ); |
371 | } |
372 | } |
373 | |
374 | void MainWindow::documentCompleted() |
375 | { |
376 | kDebug(); |
377 | |
378 | History::self().updateCurrentEntry( mDoc ); |
379 | History::self().updateActions(); |
380 | } |
381 | |
382 | void MainWindow::slotInfoMessage(KJob *, const QString &m) |
383 | { |
384 | statusBarMessage(m); |
385 | } |
386 | |
387 | void MainWindow::statusBarMessage(const QString &m) |
388 | { |
389 | statusBar()->changeItem(m, 0); |
390 | } |
391 | |
392 | void MainWindow::openUrl( const QString &url ) |
393 | { |
394 | openUrl( KUrl( url ) ); |
395 | } |
396 | |
397 | void MainWindow::openUrl( const QString &url, const QByteArray& startup_id ) |
398 | { |
399 | KStartupInfo::setNewStartupId( this, startup_id ); |
400 | openUrl( KUrl( url ) ); |
401 | } |
402 | |
403 | void MainWindow::openUrl( const KUrl &url ) |
404 | { |
405 | if ( url.isEmpty() ) slotShowHome(); |
406 | else { |
407 | mNavigator->selectItem( url ); |
408 | viewUrl( url ); |
409 | } |
410 | } |
411 | |
412 | void MainWindow::slotGlossSelected(const GlossaryEntry &entry) |
413 | { |
414 | kDebug(); |
415 | |
416 | stop(); |
417 | History::self().createEntry(); |
418 | mDoc->begin( KUrl( "help:/khelpcenter/glossary" ) ); |
419 | mDoc->write( Glossary::entryToHtml( entry ) ); |
420 | mDoc->end(); |
421 | } |
422 | |
423 | void MainWindow::stop() |
424 | { |
425 | kDebug(); |
426 | |
427 | mDoc->closeUrl(); |
428 | History::self().updateCurrentEntry( mDoc ); |
429 | } |
430 | |
431 | void MainWindow::showHome() |
432 | { |
433 | slotShowHome(); |
434 | } |
435 | |
436 | void MainWindow::slotShowHome() |
437 | { |
438 | viewUrl( mNavigator->homeURL() ); |
439 | mNavigator->clearSelection(); |
440 | } |
441 | |
442 | void MainWindow::lastSearch() |
443 | { |
444 | slotLastSearch(); |
445 | } |
446 | |
447 | void MainWindow::slotLastSearch() |
448 | { |
449 | mDoc->lastSearch(); |
450 | } |
451 | |
452 | void MainWindow::enableLastSearchAction() |
453 | { |
454 | mLastSearchAction->setEnabled( true ); |
455 | } |
456 | |
457 | void MainWindow::showSearchStderr() |
458 | { |
459 | QString log = mNavigator->searchEngine()->errorLog(); |
460 | |
461 | if ( !mLogDialog ) { |
462 | mLogDialog = new LogDialog( this ); |
463 | } |
464 | |
465 | mLogDialog->setLog( log ); |
466 | mLogDialog->show(); |
467 | mLogDialog->raise(); |
468 | } |
469 | |
470 | void MainWindow::slotIncFontSizes() |
471 | { |
472 | mDoc->slotIncFontSizes(); |
473 | updateFontScaleActions(); |
474 | } |
475 | |
476 | void MainWindow::slotDecFontSizes() |
477 | { |
478 | mDoc->slotDecFontSizes(); |
479 | updateFontScaleActions(); |
480 | } |
481 | |
482 | void MainWindow::updateFontScaleActions() |
483 | { |
484 | actionCollection()->action( QLatin1String("incFontSizes" ) )->setEnabled( mDoc->fontScaleFactor() + mDoc->fontScaleStepping() <= 300 ); |
485 | actionCollection()->action( QLatin1String("decFontSizes" ) )->setEnabled( mDoc->fontScaleFactor() - mDoc->fontScaleStepping() >= 20 ); |
486 | |
487 | KConfigGroup configGroup( KGlobal::config(), QLatin1String("General" ) ); |
488 | configGroup.writeEntry( QLatin1String("Font zoom factor" ), mDoc->fontScaleFactor() ); |
489 | configGroup.sync(); |
490 | } |
491 | |
492 | void MainWindow::slotConfigureFonts() |
493 | { |
494 | FontDialog dlg( this ); |
495 | if ( dlg.exec() == QDialog::Accepted ) |
496 | { |
497 | if (mDoc->baseURL().isEmpty()) |
498 | { |
499 | const_cast<KHTMLSettings *>( mDoc->settings() )->init( KGlobal::config().data() ); |
500 | slotShowHome(); |
501 | } |
502 | else mDoc->slotReload(); |
503 | } |
504 | } |
505 | |
506 | #include "mainwindow.moc" |
507 | |
508 | // vim:ts=2:sw=2:et |
509 | |