1 | /* |
2 | * This file is part of the KDE Help Center |
3 | * |
4 | * Copyright (C) 1999 Matthias Elter (me@kde.org) |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "navigator.h" |
22 | |
23 | #include <QDir> |
24 | #include <QFile> |
25 | #include <QPixmap> |
26 | |
27 | #include <QLabel> |
28 | #include <QtXml/QtXml> |
29 | #include <QTextStream> |
30 | #include <QRegExp> |
31 | #include <QLayout> |
32 | #include <QPushButton> |
33 | #include <QFrame> |
34 | #include <QHBoxLayout> |
35 | #include <QBoxLayout> |
36 | #include <QVBoxLayout> |
37 | #include <QTreeWidgetItemIterator> |
38 | |
39 | #include <KAction> |
40 | #include <KApplication> |
41 | #include <KConfig> |
42 | #include <KStandardDirs> |
43 | #include <KGlobal> |
44 | #include <KLocale> |
45 | #include <KDebug> |
46 | |
47 | #include <KLineEdit> |
48 | #include <KMessageBox> |
49 | #include <KIconLoader> |
50 | #include <KCharsets> |
51 | #include <KDialog> |
52 | #include <KDesktopFile> |
53 | #include <KProtocolInfo> |
54 | #include <KServiceGroup> |
55 | #include <KServiceTypeTrader> |
56 | #include <KCModuleInfo> |
57 | #include <KCModule> |
58 | |
59 | #include <sys/types.h> |
60 | #include <sys/stat.h> |
61 | #include <unistd.h> |
62 | |
63 | #include "navigatoritem.h" |
64 | #include "navigatorappitem.h" |
65 | #include "searchwidget.h" |
66 | #include "searchengine.h" |
67 | #include "docmetainfo.h" |
68 | #include "docentrytraverser.h" |
69 | #include "glossary.h" |
70 | #include "toc.h" |
71 | #include "view.h" |
72 | #include "infotree.h" |
73 | #include "mainwindow.h" |
74 | #include "plugintraverser.h" |
75 | #include "scrollkeepertreebuilder.h" |
76 | #include "kcmhelpcenter.h" |
77 | #include "formatter.h" |
78 | #include "history.h" |
79 | #include "prefs.h" |
80 | |
81 | using namespace KHC; |
82 | |
83 | Navigator::Navigator( View *view, QWidget *parent, const char *name ) |
84 | : QWidget( parent ), mIndexDialog( 0 ), |
85 | mView( view ), mSelected( false ) |
86 | { |
87 | setObjectName( name ); |
88 | |
89 | KConfigGroup config(KGlobal::config(), "General" ); |
90 | mShowMissingDocs = config.readEntry("ShowMissingDocs" , false); |
91 | |
92 | mSearchEngine = new SearchEngine( view ); |
93 | connect( mSearchEngine, SIGNAL( searchFinished() ), |
94 | SLOT( slotSearchFinished() ) ); |
95 | |
96 | DocMetaInfo::self()->scanMetaInfo(); |
97 | |
98 | QBoxLayout *topLayout = new QVBoxLayout( this ); |
99 | |
100 | mSearchFrame = new QFrame( this ); |
101 | topLayout->addWidget( mSearchFrame ); |
102 | |
103 | QBoxLayout *searchLayout = new QHBoxLayout( mSearchFrame ); |
104 | searchLayout->setSpacing( KDialog::spacingHint() ); |
105 | searchLayout->setMargin( 6 ); |
106 | |
107 | mSearchEdit = new KLineEdit( mSearchFrame ); |
108 | mSearchEdit->setClearButtonShown(true); |
109 | searchLayout->addWidget( mSearchEdit ); |
110 | connect( mSearchEdit, SIGNAL( returnPressed() ), SLOT( slotSearch() ) ); |
111 | connect( mSearchEdit, SIGNAL( textChanged( const QString & ) ), |
112 | SLOT( checkSearchButton() ) ); |
113 | |
114 | mSearchButton = new QPushButton( i18n("&Search" ), mSearchFrame ); |
115 | searchLayout->addWidget( mSearchButton ); |
116 | connect( mSearchButton, SIGNAL( clicked() ), SLOT( slotSearch() ) ); |
117 | |
118 | mTabWidget = new QTabWidget( this ); |
119 | topLayout->addWidget( mTabWidget ); |
120 | |
121 | setupContentsTab(); |
122 | setupGlossaryTab(); |
123 | setupSearchTab(); |
124 | |
125 | insertPlugins(); |
126 | hideSearch(); |
127 | /* |
128 | if ( !mSearchEngine->initSearchHandlers() ) { |
129 | hideSearch(); |
130 | } else { |
131 | mSearchWidget->updateScopeList(); |
132 | mSearchWidget->readConfig( KGlobal::config().data() ); |
133 | } |
134 | */ |
135 | connect( mTabWidget, SIGNAL( currentChanged( QWidget * ) ), |
136 | SLOT( slotTabChanged( QWidget * ) ) ); |
137 | } |
138 | |
139 | Navigator::~Navigator() |
140 | { |
141 | delete mSearchEngine; |
142 | } |
143 | |
144 | SearchEngine *Navigator::searchEngine() const |
145 | { |
146 | return mSearchEngine; |
147 | } |
148 | |
149 | Formatter *Navigator::formatter() const |
150 | { |
151 | return mView->formatter(); |
152 | } |
153 | |
154 | bool Navigator::showMissingDocs() const |
155 | { |
156 | return mShowMissingDocs; |
157 | } |
158 | |
159 | void Navigator::setupContentsTab() |
160 | { |
161 | mContentsTree = new QTreeWidget( mTabWidget ); |
162 | mContentsTree->setFrameStyle( QFrame::NoFrame ); |
163 | mContentsTree->setAllColumnsShowFocus(true); |
164 | mContentsTree->setRootIsDecorated(false); |
165 | mContentsTree->headerItem()->setHidden(true); |
166 | |
167 | connect(mContentsTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), |
168 | SLOT(slotItemSelected(QTreeWidgetItem*))); |
169 | |
170 | mTabWidget->addTab(mContentsTree, i18n("&Contents" )); |
171 | } |
172 | |
173 | void Navigator::setupSearchTab() |
174 | { |
175 | |
176 | mSearchWidget = new SearchWidget( mSearchEngine, mTabWidget ); |
177 | connect( mSearchWidget, SIGNAL( searchResult( const QString & ) ), |
178 | SLOT( slotShowSearchResult( const QString & ) ) ); |
179 | connect( mSearchWidget, SIGNAL( scopeCountChanged( int ) ), |
180 | SLOT( checkSearchButton() ) ); |
181 | connect( mSearchWidget, SIGNAL( showIndexDialog() ), |
182 | SLOT( showIndexDialog() ) ); |
183 | |
184 | mTabWidget->addTab( mSearchWidget, i18n("Search Options" )); |
185 | |
186 | } |
187 | |
188 | void Navigator::setupGlossaryTab() |
189 | { |
190 | mGlossaryTree = new Glossary( mTabWidget ); |
191 | connect( mGlossaryTree, SIGNAL( entrySelected( const GlossaryEntry & ) ), |
192 | this, SIGNAL( glossSelected( const GlossaryEntry & ) ) ); |
193 | mTabWidget->addTab( mGlossaryTree, i18n( "G&lossary" ) ); |
194 | } |
195 | |
196 | void Navigator::insertPlugins() |
197 | { |
198 | PluginTraverser t( this, mContentsTree ); |
199 | DocMetaInfo::self()->traverseEntries( &t ); |
200 | } |
201 | |
202 | void Navigator::insertParentAppDocs( const QString &name, NavigatorItem *topItem ) |
203 | { |
204 | kDebug(1400) << "Requested plugin documents for ID " << name; |
205 | |
206 | KServiceGroup::Ptr grp = KServiceGroup::childGroup( name ); |
207 | if ( !grp ) |
208 | return; |
209 | |
210 | KServiceGroup::List entries = grp->entries(); |
211 | KServiceGroup::List::ConstIterator it = entries.constBegin(); |
212 | KServiceGroup::List::ConstIterator end = entries.constEnd(); |
213 | for ( ; it != end; ++it ) { |
214 | QString desktopFile = ( *it )->entryPath(); |
215 | if ( QDir::isRelativePath( desktopFile ) ) |
216 | desktopFile = KStandardDirs::locate( "apps" , desktopFile ); |
217 | createItemFromDesktopFile( topItem, desktopFile ); |
218 | } |
219 | } |
220 | |
221 | void Navigator::insertKCMDocs( const QString &name, NavigatorItem *topItem, const QString &type ) |
222 | { |
223 | kDebug(1400) << "Requested KCM documents for ID" << name; |
224 | QString systemsettingskontrolconstraint = "[X-KDE-System-Settings-Parent-Category] != ''" ; |
225 | QString konquerorcontrolconstraint = "[X-KDE-PluginKeyword] == 'khtml_general'\ |
226 | or [X-KDE-PluginKeyword] == 'performance'\ |
227 | or [X-KDE-PluginKeyword] == 'bookmarks'" ; |
228 | QString filemanagercontrolconstraint = "[X-KDE-PluginKeyword] == 'behavior'\ |
229 | or [X-KDE-PluginKeyword] == 'dolphinviewmodes'\ |
230 | or [X-KDE-PluginKeyword] == 'dolphinnavigation'\ |
231 | or [X-KDE-PluginKeyword] == 'dolphinservices'\ |
232 | or [X-KDE-PluginKeyword] == 'dolphingeneral'\ |
233 | or [X-KDE-PluginKeyword] == 'trash'" ; |
234 | QString browsercontrolconstraint = "[X-KDE-PluginKeyword] == 'khtml_behavior'\ |
235 | or [X-KDE-PluginKeyword] == 'proxy'\ |
236 | or [X-KDE-PluginKeyword] == 'khtml_appearance'\ |
237 | or [X-KDE-PluginKeyword] == 'khtml_filter'\ |
238 | or [X-KDE-PluginKeyword] == 'cache'\ |
239 | or [X-KDE-PluginKeyword] == 'cookie'\ |
240 | or [X-KDE-PluginKeyword] == 'useragent'\ |
241 | or [X-KDE-PluginKeyword] == 'khtml_java_js'\ |
242 | or [X-KDE-PluginKeyword] == 'khtml_plugins'" ; |
243 | /* missing in browsercontrolconstraint |
244 | History no X-KDE-PluginKeyword in kcmhistory.desktop |
245 | */ |
246 | QString othercontrolconstraint = "[X-KDE-PluginKeyword] == 'cgi'" ; |
247 | |
248 | KService::List list; |
249 | |
250 | if ( type == QString("kcontrol" ) ) { |
251 | list = KServiceTypeTrader::self()->query( "KCModule" , systemsettingskontrolconstraint ); |
252 | } else if ( type == QString("konquerorcontrol" ) ) { |
253 | list = KServiceTypeTrader::self()->query( "KCModule" , konquerorcontrolconstraint ); |
254 | } else if ( type == QString("browsercontrol" ) ) { |
255 | list = KServiceTypeTrader::self()->query( "KCModule" , browsercontrolconstraint ); |
256 | } else if ( type == QString("filemanagercontrol" ) ) { |
257 | list = KServiceTypeTrader::self()->query( "KCModule" , filemanagercontrolconstraint ); |
258 | } else if ( type == QString("othercontrol" ) ) { |
259 | list = KServiceTypeTrader::self()->query( "KCModule" , othercontrolconstraint ); |
260 | } else if ( type == QString("kinfocenter" ) ) { |
261 | list = KServiceTypeTrader::self()->query( "KCModule" , "[X-KDE-ParentApp] == 'kinfocenter'" ); |
262 | } |
263 | |
264 | for ( KService::List::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) |
265 | { |
266 | KService::Ptr s = (*it); |
267 | KCModuleInfo m = KCModuleInfo(s); |
268 | QString desktopFile = KStandardDirs::locate( "services" , m.fileName() ); |
269 | createItemFromDesktopFile( topItem, desktopFile ); |
270 | } |
271 | topItem->sortChildren( 0, Qt::AscendingOrder /* ascending */ ); |
272 | } |
273 | |
274 | void Navigator::insertIOSlaveDocs( const QString &name, NavigatorItem *topItem ) |
275 | { |
276 | kDebug(1400) << "Requested IOSlave documents for ID" << name; |
277 | |
278 | QStringList list = KProtocolInfo::protocols(); |
279 | list.sort(); |
280 | |
281 | NavigatorItem *prevItem = 0; |
282 | for ( QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) |
283 | { |
284 | QString docPath = KProtocolInfo::docPath(*it); |
285 | if ( !docPath.isNull() ) |
286 | { |
287 | // First parameter is ignored if second is an absolute path |
288 | KUrl url(KUrl("help:/" ), docPath); |
289 | QString icon = KProtocolInfo::icon(*it); |
290 | if ( icon.isEmpty() ) icon = "text-plain" ; |
291 | DocEntry *entry = new DocEntry( *it, url.url(), icon ); |
292 | NavigatorItem *item = new NavigatorItem( entry, topItem, prevItem ); |
293 | prevItem = item; |
294 | item->setAutoDeleteDocEntry( true ); |
295 | } |
296 | } |
297 | } |
298 | |
299 | void Navigator::createItemFromDesktopFile( NavigatorItem *topItem, |
300 | const QString &file ) |
301 | { |
302 | KDesktopFile desktopFile( file ); |
303 | QString docPath = desktopFile.readDocPath(); |
304 | if ( !docPath.isNull() ) { |
305 | // First parameter is ignored if second is an absolute path |
306 | KUrl url(KUrl("help:/" ), docPath); |
307 | QString icon = desktopFile.readIcon(); |
308 | if ( icon.isEmpty() ) icon = "text-plain" ; |
309 | DocEntry *entry = new DocEntry( desktopFile.readName(), url.url(), icon ); |
310 | NavigatorItem *item = new NavigatorItem( entry, topItem ); |
311 | item->setAutoDeleteDocEntry( true ); |
312 | } |
313 | } |
314 | |
315 | void Navigator::insertInfoDocs( NavigatorItem *topItem ) |
316 | { |
317 | InfoTree *infoTree = new InfoTree( this ); |
318 | infoTree->build( topItem ); |
319 | } |
320 | |
321 | NavigatorItem *Navigator::insertScrollKeeperDocs( NavigatorItem *topItem, |
322 | NavigatorItem *after ) |
323 | { |
324 | ScrollKeeperTreeBuilder *builder = new ScrollKeeperTreeBuilder( this ); |
325 | return builder->build( topItem, after ); |
326 | } |
327 | |
328 | void Navigator::selectItem( const KUrl &url ) |
329 | { |
330 | kDebug() << "Navigator::selectItem(): " << url.url(); |
331 | |
332 | if ( url.url() == "khelpcenter:home" ) { |
333 | clearSelection(); |
334 | return; |
335 | } |
336 | |
337 | // help:/foo&anchor=bar gets redirected to help:/foo#bar |
338 | // Make sure that we match both the original URL as well as |
339 | // its counterpart. |
340 | KUrl alternativeURL = url; |
341 | if (url.hasRef()) |
342 | { |
343 | alternativeURL.setQuery("anchor=" +url.ref()); |
344 | alternativeURL.setRef(QString()); |
345 | } |
346 | |
347 | // If the navigator already has the given URL selected, do nothing. |
348 | NavigatorItem *item; |
349 | item = static_cast<NavigatorItem *>( mContentsTree->currentItem() ); |
350 | if ( item && mSelected ) { |
351 | KUrl currentURL ( item->entry()->url() ); |
352 | if ( (currentURL == url) || (currentURL == alternativeURL) ) { |
353 | kDebug() << "URL already shown." ; |
354 | return; |
355 | } |
356 | } |
357 | |
358 | // First, populate the NavigatorAppItems if we don't want the home page |
359 | if ( url != homeURL() ) { |
360 | QTreeWidgetItemIterator it1( mContentsTree ); |
361 | while( (*it1) ) |
362 | { |
363 | NavigatorAppItem *appItem = dynamic_cast<NavigatorAppItem *>( (*it1) ); |
364 | if ( appItem ) appItem->populate( true ); |
365 | ++it1; |
366 | } |
367 | } |
368 | |
369 | QTreeWidgetItemIterator it( mContentsTree ); |
370 | while ( (*it) ) { |
371 | NavigatorItem *item = static_cast<NavigatorItem *>( (*it) ); |
372 | KUrl itemUrl( item->entry()->url() ); |
373 | if ( (itemUrl == url) || (itemUrl == alternativeURL) ) { |
374 | mContentsTree->setCurrentItem( item ); |
375 | // If the current item was not selected and remained unchanged it |
376 | // needs to be explicitly selected |
377 | mContentsTree->setCurrentItem(item); |
378 | item->setExpanded( true ); |
379 | break; |
380 | } |
381 | ++it; |
382 | } |
383 | if ( !(*it) ) { |
384 | clearSelection(); |
385 | } else { |
386 | mSelected = true; |
387 | } |
388 | } |
389 | |
390 | void Navigator::clearSelection() |
391 | { |
392 | mContentsTree->clearSelection(); |
393 | mSelected = false; |
394 | } |
395 | |
396 | void Navigator::slotItemSelected( QTreeWidgetItem *currentItem ) |
397 | { |
398 | if ( !currentItem ) return; |
399 | |
400 | mSelected = true; |
401 | |
402 | NavigatorItem *item = static_cast<NavigatorItem *>( currentItem ); |
403 | |
404 | kDebug(1400) << item->entry()->name() << endl; |
405 | |
406 | item->setExpanded( !item->isExpanded() ); |
407 | |
408 | KUrl url ( item->entry()->url() ); |
409 | |
410 | |
411 | |
412 | if ( url.protocol() == "khelpcenter" ) { |
413 | mView->closeUrl(); |
414 | History::self().updateCurrentEntry( mView ); |
415 | History::self().createEntry(); |
416 | showOverview( item, url ); |
417 | } else { |
418 | |
419 | emit itemSelected( url.url() ); |
420 | } |
421 | |
422 | mLastUrl = url; |
423 | } |
424 | |
425 | void Navigator::openInternalUrl( const KUrl &url ) |
426 | { |
427 | if ( url.url() == "khelpcenter:home" ) { |
428 | clearSelection(); |
429 | showOverview( 0, url ); |
430 | return; |
431 | } |
432 | |
433 | selectItem( url ); |
434 | if ( !mSelected ) return; |
435 | |
436 | NavigatorItem *item = |
437 | static_cast<NavigatorItem *>( mContentsTree->currentItem() ); |
438 | |
439 | if ( item ) showOverview( item, url ); |
440 | } |
441 | |
442 | void Navigator::showOverview( NavigatorItem *item, const KUrl &url ) |
443 | { |
444 | mView->beginInternal( url ); |
445 | |
446 | QString fileName = KStandardDirs::locate( "data" , "khelpcenter/index.html.in" ); |
447 | if ( fileName.isEmpty() ) |
448 | return; |
449 | |
450 | QFile file( fileName ); |
451 | |
452 | if ( !file.open( QIODevice::ReadOnly ) ) |
453 | return; |
454 | |
455 | QTextStream stream( &file ); |
456 | QString res = stream.readAll(); |
457 | |
458 | QString title,name,content; |
459 | uint childCount; |
460 | |
461 | if ( item ) { |
462 | title = item->entry()->name(); |
463 | name = item->entry()->name(); |
464 | |
465 | QString info = item->entry()->info(); |
466 | if ( !info.isEmpty() ) content = QLatin1String("<p>" ) + info + QLatin1String("</p>\n" ); |
467 | |
468 | childCount = item->childCount(); |
469 | } else { |
470 | title = i18n("Start Page" ); |
471 | name = i18n("KDE Help Center" ); |
472 | |
473 | childCount = mContentsTree->topLevelItemCount(); |
474 | } |
475 | |
476 | if ( childCount > 0 ) { |
477 | QTreeWidgetItem *child; |
478 | if ( item ) child = item; |
479 | else child = mContentsTree->invisibleRootItem(); |
480 | |
481 | mDirLevel = 0; |
482 | |
483 | content += createChildrenList( child ); |
484 | } |
485 | else |
486 | content += QLatin1String("<p></p>" ); |
487 | |
488 | res = res.arg(title).arg(name).arg(content); |
489 | |
490 | mView->write( res ); |
491 | |
492 | mView->end(); |
493 | } |
494 | |
495 | QString Navigator::createChildrenList( QTreeWidgetItem *child ) |
496 | { |
497 | ++mDirLevel; |
498 | |
499 | QString t; |
500 | |
501 | t += QLatin1String("<ul>\n" ); |
502 | |
503 | int cc = child->childCount(); |
504 | for (int i=0;i<cc;i++) |
505 | { |
506 | NavigatorItem *childItem = static_cast<NavigatorItem *>( child->child(i) ); |
507 | |
508 | DocEntry *e = childItem->entry(); |
509 | |
510 | t += QLatin1String("<li><a href=\"" ) + e->url() + QLatin1String("\">" ); |
511 | if ( e->isDirectory() ) t += QLatin1String("<b>" ); |
512 | t += e->name(); |
513 | if ( e->isDirectory() ) t += QLatin1String("</b>" ); |
514 | t += QLatin1String("</a>" ); |
515 | |
516 | if ( !e->info().isEmpty() ) { |
517 | t += QLatin1String("<br>" ) + e->info(); |
518 | } |
519 | |
520 | t += QLatin1String("</li>\n" ); |
521 | |
522 | if ( childItem->childCount() > 0 && mDirLevel < 2 ) { |
523 | t += createChildrenList( childItem ); |
524 | } |
525 | |
526 | } |
527 | |
528 | t += QLatin1String("</ul>\n" ); |
529 | |
530 | --mDirLevel; |
531 | |
532 | return t; |
533 | } |
534 | |
535 | void Navigator::slotSearch() |
536 | { |
537 | |
538 | kDebug(1400) << "Navigator::slotSearch()" ; |
539 | |
540 | if ( !checkSearchIndex() ) return; |
541 | |
542 | if ( mSearchEngine->isRunning() ) return; |
543 | |
544 | QString words = mSearchEdit->text(); |
545 | QString method = mSearchWidget->method(); |
546 | int pages = mSearchWidget->pages(); |
547 | QString scope = mSearchWidget->scope(); |
548 | |
549 | kDebug(1400) << "Navigator::slotSearch() words: " << words; |
550 | kDebug(1400) << "Navigator::slotSearch() scope: " << scope; |
551 | |
552 | if ( words.isEmpty() || scope.isEmpty() ) return; |
553 | |
554 | // disable search Button during searches |
555 | mSearchButton->setEnabled(false); |
556 | QApplication::setOverrideCursor(Qt::WaitCursor); |
557 | |
558 | if ( !mSearchEngine->search( words, method, pages, scope ) ) { |
559 | slotSearchFinished(); |
560 | KMessageBox::sorry( this, i18n("Unable to run search program." ) ); |
561 | } |
562 | |
563 | } |
564 | |
565 | void Navigator::slotShowSearchResult( const QString &url ) |
566 | { |
567 | QString u = url; |
568 | u.replace( "%k" , mSearchEdit->text() ); |
569 | |
570 | emit itemSelected( u ); |
571 | } |
572 | |
573 | void Navigator::slotSearchFinished() |
574 | { |
575 | mSearchButton->setEnabled(true); |
576 | QApplication::restoreOverrideCursor(); |
577 | |
578 | kDebug( 1400 ) << "Search finished." ; |
579 | } |
580 | |
581 | void Navigator::checkSearchButton() |
582 | { |
583 | mSearchButton->setEnabled( !mSearchEdit->text().isEmpty() && |
584 | mSearchWidget->scopeCount() > 0 ); |
585 | mTabWidget->setCurrentIndex( mTabWidget->indexOf( mSearchWidget ) ); |
586 | } |
587 | |
588 | |
589 | void Navigator::hideSearch() |
590 | { |
591 | mSearchFrame->hide(); |
592 | mTabWidget->removeTab( mTabWidget->indexOf( mSearchWidget ) ); |
593 | } |
594 | |
595 | bool Navigator::checkSearchIndex() |
596 | { |
597 | KConfigGroup cfg(KGlobal::config(), "Search" ); |
598 | if ( cfg.readEntry( "IndexExists" , false) ) return true; |
599 | |
600 | if ( mIndexDialog && !mIndexDialog->isHidden() ) return true; |
601 | |
602 | QString text = i18n( "A search index does not yet exist. Do you want " |
603 | "to create the index now?" ); |
604 | |
605 | int result = KMessageBox::questionYesNo( this, text, QString(), |
606 | KGuiItem(i18n("Create" )), |
607 | KGuiItem(i18n("Do Not Create" )), |
608 | QLatin1String("indexcreation" ) ); |
609 | if ( result == KMessageBox::Yes ) { |
610 | showIndexDialog(); |
611 | return false; |
612 | } |
613 | |
614 | return true; |
615 | } |
616 | |
617 | void Navigator::slotTabChanged( QWidget *wid ) |
618 | { |
619 | if ( wid == mSearchWidget ) checkSearchIndex(); |
620 | } |
621 | |
622 | void Navigator::slotSelectGlossEntry( const QString &id ) |
623 | { |
624 | mGlossaryTree->slotSelectGlossEntry( id ); |
625 | } |
626 | |
627 | KUrl Navigator::homeURL() |
628 | { |
629 | if ( !mHomeUrl.isEmpty() ) return mHomeUrl; |
630 | |
631 | KSharedConfig::Ptr cfg = KGlobal::config(); |
632 | // We have to reparse the configuration here in order to get a |
633 | // language-specific StartUrl, e.g. "StartUrl[de]". |
634 | cfg->reparseConfiguration(); |
635 | mHomeUrl = cfg->group("General" ).readPathEntry( "StartUrl" , QLatin1String("khelpcenter:home" ) ); |
636 | return mHomeUrl; |
637 | } |
638 | |
639 | void Navigator::showIndexDialog() |
640 | { |
641 | if ( !mIndexDialog ) { |
642 | mIndexDialog = new KCMHelpCenter( mSearchEngine, this ); |
643 | connect( mIndexDialog, SIGNAL( searchIndexUpdated() ), mSearchWidget, |
644 | SLOT( updateScopeList() ) ); |
645 | } |
646 | mIndexDialog->show(); |
647 | mIndexDialog->raise(); |
648 | } |
649 | |
650 | void Navigator::readConfig() |
651 | { |
652 | if ( Prefs::currentTab() == Prefs::Search ) { |
653 | mTabWidget->setCurrentIndex( mTabWidget->indexOf( mSearchWidget ) ); |
654 | } else if ( Prefs::currentTab() == Prefs::Glossary ) { |
655 | mTabWidget->setCurrentIndex( mTabWidget->indexOf( mGlossaryTree ) ); |
656 | } else { |
657 | mTabWidget->setCurrentIndex( mTabWidget->indexOf( mContentsTree ) ); |
658 | } |
659 | } |
660 | |
661 | void Navigator::writeConfig() |
662 | { |
663 | if ( mTabWidget->currentWidget() == mSearchWidget ) { |
664 | Prefs::setCurrentTab( Prefs::Search ); |
665 | } else if ( mTabWidget->currentWidget() == mGlossaryTree ) { |
666 | Prefs::setCurrentTab( Prefs::Glossary ); |
667 | } else { |
668 | Prefs::setCurrentTab( Prefs::Content ); |
669 | } |
670 | } |
671 | |
672 | void Navigator::clearSearch() |
673 | { |
674 | mSearchEdit->setText( QString() ); |
675 | } |
676 | |
677 | #include "navigator.moc" |
678 | |
679 | // vim:ts=2:sw=2:et |
680 | |