1
2/* This file is part of the KDE project
3 * Copyright 2002 Cornelius Schumacher <schumacher@kde.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public
7 * License version 2 or at your option version 3 as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "docmetainfo.h"
22
23#include <QRegExp>
24
25#include <KDebug>
26#include <KStandardDirs>
27#include <KLocale>
28#include <KConfig>
29#include <KConfigGroup>
30
31#include "htmlsearch.h"
32#include "docentrytraverser.h"
33
34using namespace KHC;
35
36bool DocMetaInfo::mLoaded = false;
37
38DocMetaInfo *DocMetaInfo::mSelf = 0;
39
40DocMetaInfo *DocMetaInfo::self()
41{
42 if ( !mSelf ) mSelf = new DocMetaInfo;
43 return mSelf;
44}
45
46DocMetaInfo::DocMetaInfo()
47{
48 kDebug() << "DocMetaInfo()";
49
50 mHtmlSearch = new HTMLSearch;
51
52 mRootEntry.setName( i18n("Top-Level Documentation") );
53}
54
55DocMetaInfo::~DocMetaInfo()
56{
57 kDebug() << "~DocMetaInfo()";
58
59 DocEntry::List::ConstIterator it;
60 for( it = mDocEntries.constBegin(); it != mDocEntries.constEnd(); ++it )
61 {
62 delete *it;
63 }
64
65 delete mHtmlSearch;
66
67 mLoaded = false;
68
69 mSelf = 0;
70}
71
72DocEntry *DocMetaInfo::addDocEntry( const QString &fileName )
73{
74 QFileInfo fi( fileName );
75 if ( !fi.exists() ) return 0;
76
77 QString extension = fi.completeSuffix();
78 QStringList extensions = extension.split( '.');
79 QString lang;
80 if ( extensions.count() >= 2 )
81 {
82 lang = extensions[ extensions.count() - 2 ];
83 }
84
85 if ( !lang.isEmpty() && !mLanguages.contains( lang ) )
86 {
87 return 0;
88 }
89
90 DocEntry *entry = new DocEntry();
91
92 if ( entry->readFromFile( fileName ) )
93 {
94 if ( !lang.isEmpty() && lang != mLanguages.first() )
95 {
96 entry->setLang( lang );
97 entry->setName( i18nc("doctitle (language)","%1 (%2)",
98 entry->name() ,
99 mLanguageNames[ lang ] ) );
100 }
101 if ( entry->searchMethod().toLower() == "htdig" )
102 {
103 mHtmlSearch->setupDocEntry( entry );
104 }
105 QString indexer = entry->indexer();
106 indexer.replace( "%f", fileName );
107 entry->setIndexer( indexer );
108 addDocEntry( entry );
109 return entry;
110 }
111 else
112 {
113 delete entry;
114 return 0;
115 }
116}
117
118void DocMetaInfo::addDocEntry( DocEntry *entry )
119{
120 mDocEntries.append( entry );
121 if ( !entry->search().isEmpty() ) mSearchEntries.append( entry );
122}
123
124DocEntry::List DocMetaInfo::docEntries()
125{
126 return mDocEntries;
127}
128
129DocEntry::List DocMetaInfo::searchEntries()
130{
131 return mSearchEntries;
132}
133
134QString DocMetaInfo::languageName( const QString &langcode )
135{
136 if ( langcode == "en" ) return i18nc("Describes documentation entries that are in English","English");
137
138 QString cfgfile = KStandardDirs::locate( "locale",
139 QString::fromLatin1( "%1/entry.desktop" ).arg( langcode ) );
140
141 kDebug() << "-- langcode: " << langcode << " cfgfile: " << cfgfile;
142
143 KConfig _cfg( cfgfile, KConfig::SimpleConfig );
144 KConfigGroup cfg(&_cfg, "KCM Locale" );
145 QString name = cfg.readEntry( "Name", langcode );
146
147 return name;
148}
149
150void DocMetaInfo::scanMetaInfo( bool force )
151{
152 if ( mLoaded && !force ) return;
153
154 mLanguages = KGlobal::locale()->languageList();
155
156 kDebug( 1400 ) << "LANGS: " << mLanguages.join( QLatin1String(" ") );
157
158 QStringList::ConstIterator it;
159 for( it = mLanguages.constBegin(); it != mLanguages.constEnd(); ++it )
160 {
161 mLanguageNames.insert( *it, languageName( *it ) );
162 }
163
164 KConfig config( QLatin1String("khelpcenterrc") );
165 KConfigGroup cg(&config, "General");
166 QStringList metaInfos = cg.readEntry( "MetaInfoDirs" , QStringList() );
167
168 if ( metaInfos.isEmpty() )
169 {
170 KStandardDirs* kstd = KGlobal::dirs();
171 metaInfos = kstd->findDirs( "appdata", "plugins" );
172 }
173 for( it = metaInfos.constBegin(); it != metaInfos.constEnd(); ++it)
174 {
175 kDebug() << "DocMetaInfo::scanMetaInfo(): scanning " << *it;
176 scanMetaInfoDir( *it, &mRootEntry );
177 }
178
179 mLoaded = true;
180}
181
182DocEntry *DocMetaInfo::scanMetaInfoDir( const QString &dirName,
183 DocEntry *parent )
184{
185 QDir dir( dirName );
186 if ( !dir.exists() ) return 0;
187
188 foreach( const QFileInfo &fi, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot) )
189 {
190 DocEntry *entry = 0;
191 if ( fi.isDir() )
192 {
193 DocEntry *dirEntry = addDirEntry( QDir( fi.absoluteFilePath() ), parent );
194 entry = scanMetaInfoDir( fi.absoluteFilePath(), dirEntry );
195 }
196 else if ( fi.suffix() == QLatin1String("desktop") )
197 {
198 entry = addDocEntry( fi.absoluteFilePath() );
199 if ( parent && entry ) parent->addChild( entry );
200 }
201 }
202
203 return 0;
204}
205
206DocEntry *DocMetaInfo::addDirEntry( const QDir &dir, DocEntry *parent )
207{
208 DocEntry *dirEntry = addDocEntry( dir.absolutePath() + QLatin1String("/.directory") );
209
210 if ( !dirEntry )
211 {
212 dirEntry = new DocEntry;
213 dirEntry->setName( dir.dirName() );
214 addDocEntry( dirEntry );
215 }
216
217 dirEntry->setDirectory( true );
218 if ( parent ) parent->addChild( dirEntry );
219
220 return dirEntry;
221}
222
223
224void DocMetaInfo::traverseEntries( DocEntryTraverser *traverser )
225{
226 traverseEntry( &mRootEntry, traverser );
227}
228
229void DocMetaInfo::traverseEntry( DocEntry *entry, DocEntryTraverser *traverser )
230{
231 DocEntry::List children = entry->children();
232 DocEntry::List::ConstIterator it;
233 for( it = children.constBegin(); it != children.constEnd(); ++it )
234 {
235 if ( (*it)->isDirectory() && !(*it)->hasChildren() &&
236 (*it)->khelpcenterSpecial().isEmpty() ) continue;
237 traverser->process( *it );
238 if ( (*it)->hasChildren() )
239 {
240 DocEntryTraverser *t = traverser->childTraverser( *it );
241 if (t)
242 {
243 traverseEntry( *it, t );
244 t->deleteTraverser();
245 }
246 }
247 }
248}
249
250void DocMetaInfo::startTraverseEntries( DocEntryTraverser *traverser )
251{
252 kDebug() << "DocMetaInfo::startTraverseEntries()";
253 traverser->setNotifyee( this );
254 startTraverseEntry( &mRootEntry, traverser );
255}
256
257void DocMetaInfo::startTraverseEntry( DocEntry *entry,
258 DocEntryTraverser *traverser )
259{
260 if ( !traverser )
261 {
262 kDebug() << "DocMetaInfo::startTraverseEntry(): ERROR. No Traverser."
263 << endl;
264 return;
265 }
266
267 if ( !entry )
268 {
269 kDebug() << "DocMetaInfo::startTraverseEntry(): no entry.";
270 endTraverseEntries( traverser );
271 return;
272 }
273
274 traverser->startProcess( entry );
275}
276
277void DocMetaInfo::endProcess( DocEntry *entry, DocEntryTraverser *traverser )
278{
279 if ( !entry )
280 {
281 endTraverseEntries( traverser );
282 return;
283 }
284
285 if ( entry->hasChildren() )
286 {
287 startTraverseEntry( entry->firstChild(), traverser->childTraverser( entry ) );
288 } else if ( entry->nextSibling() )
289 {
290 startTraverseEntry( entry->nextSibling(), traverser );
291 } else
292 {
293 DocEntry *parent = entry->parent();
294 DocEntryTraverser *parentTraverser = 0;
295 while ( parent ) {
296 parentTraverser = traverser->parentTraverser();
297 traverser->deleteTraverser();
298 if ( parent->nextSibling() ) {
299 startTraverseEntry( parent->nextSibling(), parentTraverser );
300 break;
301 }
302 else
303 {
304 parent = parent->parent();
305 traverser = parentTraverser;
306 }
307 }
308 if ( !parent )
309 {
310 endTraverseEntries( traverser );
311 }
312 }
313}
314
315void DocMetaInfo::endTraverseEntries( DocEntryTraverser *traverser )
316{
317 kDebug() << "DocMetaInfo::endTraverseEntries()";
318
319 if ( !traverser )
320 {
321 kDebug() << " no more traversers.";
322 return;
323 }
324
325 traverser->finishTraversal();
326}
327// vim:ts=2:sw=2:et
328