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
64using namespace KHC;
65
66class 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
105MainWindow::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
185MainWindow::~MainWindow()
186{
187 writeConfig();
188}
189
190void MainWindow::enableCopyTextAction()
191{
192 mCopyText->setEnabled( mDoc->hasSelection() );
193}
194
195void MainWindow::saveProperties( KConfigGroup &config )
196{
197 kDebug();
198 config.writePathEntry( "URL" , mDoc->baseURL().url() );
199}
200
201void MainWindow::readProperties( const KConfigGroup &config )
202{
203 kDebug();
204 mDoc->slotReload( KUrl( config.readPathEntry( "URL", QString() ) ) );
205}
206
207void 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
218void 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
228void 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
287void MainWindow::slotCopySelectedText()
288{
289 mDoc->copySelectedText();
290}
291
292void MainWindow::print()
293{
294 mDoc->view()->print();
295}
296
297void 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
306void MainWindow::goInternalUrl( const KUrl &url )
307{
308 mDoc->closeUrl();
309 slotOpenURLRequest( url );
310}
311
312void 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
322void MainWindow::viewUrl( const QString &url )
323{
324 viewUrl( KUrl( url ) );
325}
326
327void 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
374void MainWindow::documentCompleted()
375{
376 kDebug();
377
378 History::self().updateCurrentEntry( mDoc );
379 History::self().updateActions();
380}
381
382void MainWindow::slotInfoMessage(KJob *, const QString &m)
383{
384 statusBarMessage(m);
385}
386
387void MainWindow::statusBarMessage(const QString &m)
388{
389 statusBar()->changeItem(m, 0);
390}
391
392void MainWindow::openUrl( const QString &url )
393{
394 openUrl( KUrl( url ) );
395}
396
397void MainWindow::openUrl( const QString &url, const QByteArray& startup_id )
398{
399 KStartupInfo::setNewStartupId( this, startup_id );
400 openUrl( KUrl( url ) );
401}
402
403void MainWindow::openUrl( const KUrl &url )
404{
405 if ( url.isEmpty() ) slotShowHome();
406 else {
407 mNavigator->selectItem( url );
408 viewUrl( url );
409 }
410}
411
412void 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
423void MainWindow::stop()
424{
425 kDebug();
426
427 mDoc->closeUrl();
428 History::self().updateCurrentEntry( mDoc );
429}
430
431void MainWindow::showHome()
432{
433 slotShowHome();
434}
435
436void MainWindow::slotShowHome()
437{
438 viewUrl( mNavigator->homeURL() );
439 mNavigator->clearSelection();
440}
441
442void MainWindow::lastSearch()
443{
444 slotLastSearch();
445}
446
447void MainWindow::slotLastSearch()
448{
449 mDoc->lastSearch();
450}
451
452void MainWindow::enableLastSearchAction()
453{
454 mLastSearchAction->setEnabled( true );
455}
456
457void 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
470void MainWindow::slotIncFontSizes()
471{
472 mDoc->slotIncFontSizes();
473 updateFontScaleActions();
474}
475
476void MainWindow::slotDecFontSizes()
477{
478 mDoc->slotDecFontSizes();
479 updateFontScaleActions();
480}
481
482void 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
492void 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