KHTML
khtml_settings.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 1999 David Faure <faure@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "khtml_settings.h" 00021 #include "khtmldefaults.h" 00022 00023 #include <kconfig.h> 00024 #include <kconfiggroup.h> 00025 #include <kdebug.h> 00026 #include <kglobal.h> 00027 #include <kglobalsettings.h> 00028 #include <klocale.h> 00029 #include <kmessagebox.h> 00030 #include <khtml_filter_p.h> 00031 #include <kstandarddirs.h> 00032 #include <kjob.h> 00033 #include <kio/job.h> 00034 00035 #include <QFile> 00036 #include <QFileInfo> 00037 #include <QtGui/QFontDatabase> 00038 #include <QByteArray> 00039 00044 struct KPerDomainSettings { 00045 bool m_bEnableJava : 1; 00046 bool m_bEnableJavaScript : 1; 00047 bool m_bEnablePlugins : 1; 00048 // don't forget to maintain the bitfields as the enums grow 00049 KHTMLSettings::KJSWindowOpenPolicy m_windowOpenPolicy : 2; 00050 KHTMLSettings::KJSWindowStatusPolicy m_windowStatusPolicy : 1; 00051 KHTMLSettings::KJSWindowFocusPolicy m_windowFocusPolicy : 1; 00052 KHTMLSettings::KJSWindowMovePolicy m_windowMovePolicy : 1; 00053 KHTMLSettings::KJSWindowResizePolicy m_windowResizePolicy : 1; 00054 00055 #ifdef DEBUG_SETTINGS 00056 void dump(const QString &infix = QString()) const { 00057 kDebug() << "KPerDomainSettings " << infix << " @" << this << ":"; 00058 kDebug() << " m_bEnableJava: " << m_bEnableJava; 00059 kDebug() << " m_bEnableJavaScript: " << m_bEnableJavaScript; 00060 kDebug() << " m_bEnablePlugins: " << m_bEnablePlugins; 00061 kDebug() << " m_windowOpenPolicy: " << m_windowOpenPolicy; 00062 kDebug() << " m_windowStatusPolicy: " << m_windowStatusPolicy; 00063 kDebug() << " m_windowFocusPolicy: " << m_windowFocusPolicy; 00064 kDebug() << " m_windowMovePolicy: " << m_windowMovePolicy; 00065 kDebug() << " m_windowResizePolicy: " << m_windowResizePolicy; 00066 } 00067 #endif 00068 }; 00069 00070 QString *KHTMLSettings::avFamilies = 0; 00071 typedef QMap<QString,KPerDomainSettings> PolicyMap; 00072 00073 // The "struct" that contains all the data. Must be copiable (no pointers). 00074 class KHTMLSettingsData 00075 { 00076 public: 00077 bool m_bChangeCursor : 1; 00078 bool m_bOpenMiddleClick : 1; 00079 bool m_underlineLink : 1; 00080 bool m_hoverLink : 1; 00081 bool m_bEnableJavaScriptDebug : 1; 00082 bool m_bEnableJavaScriptErrorReporting : 1; 00083 bool enforceCharset : 1; 00084 bool m_bAutoLoadImages : 1; 00085 bool m_bUnfinishedImageFrame : 1; 00086 bool m_formCompletionEnabled : 1; 00087 bool m_autoDelayedActionsEnabled : 1; 00088 bool m_jsErrorsEnabled : 1; 00089 bool m_follow_system_colors : 1; 00090 bool m_allowTabulation : 1; 00091 bool m_autoSpellCheck : 1; 00092 bool m_adFilterEnabled : 1; 00093 bool m_hideAdsEnabled : 1; 00094 bool m_jsPopupBlockerPassivePopup : 1; 00095 bool m_accessKeysEnabled : 1; 00096 00097 // the virtual global "domain" 00098 KPerDomainSettings global; 00099 00100 int m_fontSize; 00101 int m_minFontSize; 00102 int m_maxFormCompletionItems; 00103 KHTMLSettings::KAnimationAdvice m_showAnimations; 00104 KHTMLSettings::KSmoothScrollingMode m_smoothScrolling; 00105 KHTMLSettings::KDNSPrefetch m_dnsPrefetch; 00106 00107 QString m_encoding; 00108 QString m_userSheet; 00109 00110 QColor m_textColor; 00111 QColor m_baseColor; 00112 QColor m_linkColor; 00113 QColor m_vLinkColor; 00114 00115 PolicyMap domainPolicy; 00116 QStringList fonts; 00117 QStringList defaultFonts; 00118 00119 khtml::FilterSet adBlackList; 00120 khtml::FilterSet adWhiteList; 00121 QList< QPair< QString, QChar > > m_fallbackAccessKeysAssignments; 00122 }; 00123 00124 class KHTMLSettingsPrivate : public QObject, public KHTMLSettingsData 00125 { 00126 Q_OBJECT 00127 public: 00128 00129 void adblockFilterLoadList(const QString& filename) 00130 { 00131 kDebug(6000) << "Loading filter list from" << filename; 00133 QFile file(filename); 00134 if (file.open(QIODevice::ReadOnly)) { 00135 QTextStream ts(&file); 00136 QString line = ts.readLine(); 00137 #ifndef NDEBUG /// only count when compiled for debugging 00138 int whiteCounter = 0, blackCounter = 0; 00139 #endif // NDEBUG 00140 while (!line.isEmpty()) { 00142 if (line.startsWith(QLatin1String("@@"))) 00143 { 00144 #ifndef NDEBUG 00145 ++whiteCounter; 00146 #endif // NDEBUG 00147 adWhiteList.addFilter(line); 00148 } 00149 else 00150 { 00151 #ifndef NDEBUG 00152 ++blackCounter; 00153 #endif // NDEBUG 00154 adBlackList.addFilter(line); 00155 } 00156 00157 line = ts.readLine(); 00158 } 00159 file.close(); 00160 00161 #ifndef NDEBUG 00162 kDebug(6000) << "Filter list loaded" << whiteCounter << "white list entries and" << blackCounter << "black list entries"; 00163 #endif // NDEBUG 00164 } 00165 } 00166 00167 public slots: 00168 void adblockFilterResult(KJob *job) 00169 { 00170 KIO::StoredTransferJob *tJob = qobject_cast<KIO::StoredTransferJob*>(job); 00171 Q_ASSERT(tJob); 00172 00173 if ( tJob->error() ) { 00174 kDebug(6000) << "Failed to download" << tJob->url() << "with message:" << tJob->errorText(); 00175 } 00176 else if ( tJob->isErrorPage() ) { // 4XX error code 00177 kDebug(6000) << "Failed to fetch filter list" << tJob->url(); 00178 } 00179 else { 00180 const QByteArray byteArray = tJob->data(); 00181 const QString localFileName = tJob->property( "khtmlsettings_adBlock_filename" ).toString(); 00182 00183 QFile file(localFileName); 00184 if ( file.open(QFile::WriteOnly) ) { 00185 bool success = file.write(byteArray) == byteArray.size(); 00186 file.close(); 00187 if ( success ) 00188 adblockFilterLoadList(localFileName); 00189 else 00190 kDebug(6000) << "Could not write" << byteArray.size() << "to file" << localFileName; 00191 } 00192 else 00193 kDebug(6000) << "Cannot open file" << localFileName << "for filter list"; 00194 } 00195 00196 } 00197 }; 00198 00199 00203 static KPerDomainSettings &setup_per_domain_policy( 00204 KHTMLSettingsPrivate* const d, 00205 const QString &domain) { 00206 if (domain.isEmpty()) { 00207 kWarning(6000) << "setup_per_domain_policy: domain is empty"; 00208 } 00209 const QString ldomain = domain.toLower(); 00210 PolicyMap::iterator it = d->domainPolicy.find(ldomain); 00211 if (it == d->domainPolicy.end()) { 00212 // simply copy global domain settings (they should have been initialized 00213 // by this time) 00214 it = d->domainPolicy.insert(ldomain,d->global); 00215 } 00216 return *it; 00217 } 00218 00219 00220 KHTMLSettings::KJavaScriptAdvice KHTMLSettings::strToAdvice(const QString& _str) 00221 { 00222 KJavaScriptAdvice ret = KJavaScriptDunno; 00223 00224 if (_str.isNull()) 00225 ret = KJavaScriptDunno; 00226 00227 if (_str.toLower() == QLatin1String("accept")) 00228 ret = KJavaScriptAccept; 00229 else if (_str.toLower() == QLatin1String("reject")) 00230 ret = KJavaScriptReject; 00231 00232 return ret; 00233 } 00234 00235 const char* KHTMLSettings::adviceToStr(KJavaScriptAdvice _advice) 00236 { 00237 switch( _advice ) { 00238 case KJavaScriptAccept: return I18N_NOOP("Accept"); 00239 case KJavaScriptReject: return I18N_NOOP("Reject"); 00240 default: return 0; 00241 } 00242 return 0; 00243 } 00244 00245 00246 void KHTMLSettings::splitDomainAdvice(const QString& configStr, QString &domain, 00247 KJavaScriptAdvice &javaAdvice, KJavaScriptAdvice& javaScriptAdvice) 00248 { 00249 QString tmp(configStr); 00250 int splitIndex = tmp.indexOf(':'); 00251 if ( splitIndex == -1) 00252 { 00253 domain = configStr.toLower(); 00254 javaAdvice = KJavaScriptDunno; 00255 javaScriptAdvice = KJavaScriptDunno; 00256 } 00257 else 00258 { 00259 domain = tmp.left(splitIndex).toLower(); 00260 QString adviceString = tmp.mid( splitIndex+1, tmp.length() ); 00261 int splitIndex2 = adviceString.indexOf( ':' ); 00262 if( splitIndex2 == -1 ) { 00263 // Java advice only 00264 javaAdvice = strToAdvice( adviceString ); 00265 javaScriptAdvice = KJavaScriptDunno; 00266 } else { 00267 // Java and JavaScript advice 00268 javaAdvice = strToAdvice( adviceString.left( splitIndex2 ) ); 00269 javaScriptAdvice = strToAdvice( adviceString.mid( splitIndex2+1, 00270 adviceString.length() ) ); 00271 } 00272 } 00273 } 00274 00275 void KHTMLSettings::readDomainSettings(const KConfigGroup &config, bool reset, 00276 bool global, KPerDomainSettings &pd_settings) { 00277 QString jsPrefix = global ? QString() 00278 : QString::fromLatin1("javascript."); 00279 QString javaPrefix = global ? QString() 00280 : QString::fromLatin1("java."); 00281 QString pluginsPrefix = global ? QString() 00282 : QString::fromLatin1("plugins."); 00283 00284 // The setting for Java 00285 QString key = javaPrefix + QLatin1String("EnableJava"); 00286 if ( (global && reset) || config.hasKey( key ) ) 00287 pd_settings.m_bEnableJava = config.readEntry( key, false ); 00288 else if ( !global ) 00289 pd_settings.m_bEnableJava = d->global.m_bEnableJava; 00290 00291 // The setting for Plugins 00292 key = pluginsPrefix + QLatin1String("EnablePlugins"); 00293 if ( (global && reset) || config.hasKey( key ) ) 00294 pd_settings.m_bEnablePlugins = config.readEntry( key, true ); 00295 else if ( !global ) 00296 pd_settings.m_bEnablePlugins = d->global.m_bEnablePlugins; 00297 00298 // The setting for JavaScript 00299 key = jsPrefix + QLatin1String("EnableJavaScript"); 00300 if ( (global && reset) || config.hasKey( key ) ) 00301 pd_settings.m_bEnableJavaScript = config.readEntry( key, true ); 00302 else if ( !global ) 00303 pd_settings.m_bEnableJavaScript = d->global.m_bEnableJavaScript; 00304 00305 // window property policies 00306 key = jsPrefix + QLatin1String("WindowOpenPolicy"); 00307 if ( (global && reset) || config.hasKey( key ) ) 00308 pd_settings.m_windowOpenPolicy = (KJSWindowOpenPolicy) 00309 config.readEntry( key, uint(KJSWindowOpenSmart) ); 00310 else if ( !global ) 00311 pd_settings.m_windowOpenPolicy = d->global.m_windowOpenPolicy; 00312 00313 key = jsPrefix + QLatin1String("WindowMovePolicy"); 00314 if ( (global && reset) || config.hasKey( key ) ) 00315 pd_settings.m_windowMovePolicy = (KJSWindowMovePolicy) 00316 config.readEntry( key, uint(KJSWindowMoveAllow) ); 00317 else if ( !global ) 00318 pd_settings.m_windowMovePolicy = d->global.m_windowMovePolicy; 00319 00320 key = jsPrefix + QLatin1String("WindowResizePolicy"); 00321 if ( (global && reset) || config.hasKey( key ) ) 00322 pd_settings.m_windowResizePolicy = (KJSWindowResizePolicy) 00323 config.readEntry( key, uint(KJSWindowResizeAllow) ); 00324 else if ( !global ) 00325 pd_settings.m_windowResizePolicy = d->global.m_windowResizePolicy; 00326 00327 key = jsPrefix + QLatin1String("WindowStatusPolicy"); 00328 if ( (global && reset) || config.hasKey( key ) ) 00329 pd_settings.m_windowStatusPolicy = (KJSWindowStatusPolicy) 00330 config.readEntry( key, uint(KJSWindowStatusAllow) ); 00331 else if ( !global ) 00332 pd_settings.m_windowStatusPolicy = d->global.m_windowStatusPolicy; 00333 00334 key = jsPrefix + QLatin1String("WindowFocusPolicy"); 00335 if ( (global && reset) || config.hasKey( key ) ) 00336 pd_settings.m_windowFocusPolicy = (KJSWindowFocusPolicy) 00337 config.readEntry( key, uint(KJSWindowFocusAllow) ); 00338 else if ( !global ) 00339 pd_settings.m_windowFocusPolicy = d->global.m_windowFocusPolicy; 00340 00341 } 00342 00343 00344 KHTMLSettings::KHTMLSettings() 00345 :d (new KHTMLSettingsPrivate()) 00346 { 00347 init(); 00348 } 00349 00350 KHTMLSettings::KHTMLSettings(const KHTMLSettings &other) 00351 :d(new KHTMLSettingsPrivate()) 00352 { 00353 KHTMLSettingsData* data = d; 00354 *data = *other.d; 00355 } 00356 00357 KHTMLSettings::~KHTMLSettings() 00358 { 00359 delete d; 00360 } 00361 00362 bool KHTMLSettings::changeCursor() const 00363 { 00364 return d->m_bChangeCursor; 00365 } 00366 00367 bool KHTMLSettings::underlineLink() const 00368 { 00369 return d->m_underlineLink; 00370 } 00371 00372 bool KHTMLSettings::hoverLink() const 00373 { 00374 return d->m_hoverLink; 00375 } 00376 00377 void KHTMLSettings::init() 00378 { 00379 KConfig global( "khtmlrc", KConfig::NoGlobals ); 00380 init( &global, true ); 00381 00382 KSharedConfig::Ptr local = KGlobal::config(); 00383 if ( !local ) 00384 return; 00385 00386 init( local.data(), false ); 00387 } 00388 00389 void KHTMLSettings::init( KConfig * config, bool reset ) 00390 { 00391 KConfigGroup cg( config, "MainView Settings" ); 00392 if (reset || cg.exists() ) 00393 { 00394 if ( reset || cg.hasKey( "OpenMiddleClick" ) ) 00395 d->m_bOpenMiddleClick = cg.readEntry( "OpenMiddleClick", true ); 00396 } 00397 00398 KConfigGroup cgAccess(config,"Access Keys" ); 00399 if (reset || cgAccess.exists() ) { 00400 d->m_accessKeysEnabled = cgAccess.readEntry( "Enabled", true ); 00401 } 00402 00403 KConfigGroup cgFilter( config, "Filter Settings" ); 00404 00405 if (reset || cgFilter.exists() ) 00406 { 00407 d->m_adFilterEnabled = cgFilter.readEntry("Enabled", false); 00408 d->m_hideAdsEnabled = cgFilter.readEntry("Shrink", false); 00409 00410 d->adBlackList.clear(); 00411 d->adWhiteList.clear(); 00412 00413 if (d->m_adFilterEnabled) { 00414 00416 int htmlFilterListMaxAgeDays = cgFilter.readEntry(QString("HTMLFilterListMaxAgeDays")).toInt(); 00417 if (htmlFilterListMaxAgeDays < 1) 00418 htmlFilterListMaxAgeDays = 1; 00419 00420 QMap<QString,QString> entryMap = cgFilter.entryMap(); 00421 QMap<QString,QString>::ConstIterator it; 00422 for( it = entryMap.constBegin(); it != entryMap.constEnd(); ++it ) 00423 { 00424 int id = -1; 00425 QString name = it.key(); 00426 QString url = it.value(); 00427 00428 if (name.startsWith("Filter")) 00429 { 00430 if (url.startsWith(QLatin1String("@@"))) 00431 d->adWhiteList.addFilter(url); 00432 else 00433 d->adBlackList.addFilter(url); 00434 } else if (name.startsWith("HTMLFilterListName-") && (id = name.mid(19).toInt()) > 0) 00435 { 00437 bool filterEnabled = cgFilter.readEntry(QString("HTMLFilterListEnabled-").append(QString::number(id))) != QLatin1String("false"); 00438 00440 KUrl url(cgFilter.readEntry(QString("HTMLFilterListURL-").append(QString::number(id)))); 00441 00442 if (filterEnabled && url.isValid()) { 00444 QString localFile = cgFilter.readEntry(QString("HTMLFilterListLocalFilename-").append(QString::number(id))); 00445 localFile = KStandardDirs::locateLocal("data", "khtml/" + localFile); 00446 00448 QFileInfo fileInfo(localFile); 00449 00451 if (fileInfo.exists()) 00452 d->adblockFilterLoadList( localFile ); 00453 00455 if (!fileInfo.exists() || fileInfo.lastModified().daysTo(QDateTime::currentDateTime()) > htmlFilterListMaxAgeDays) 00456 { 00458 kDebug(6000) << "Asynchronously fetching filter list from" << url << "to" << localFile; 00459 00460 KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo ); 00461 QObject::connect( job, SIGNAL(result(KJob*)), d, SLOT(adblockFilterResult(KJob*)) ); 00463 job->setProperty("khtmlsettings_adBlock_filename", localFile); 00464 } 00465 } 00466 } 00467 } 00468 } 00469 00470 } 00471 00472 KConfigGroup cgHtml( config, "HTML Settings" ); 00473 if (reset || cgHtml.exists() ) 00474 { 00475 // Fonts and colors 00476 if( reset ) { 00477 d->defaultFonts = QStringList(); 00478 d->defaultFonts.append( cgHtml.readEntry( "StandardFont", KGlobalSettings::generalFont().family() ) ); 00479 d->defaultFonts.append( cgHtml.readEntry( "FixedFont", KGlobalSettings::fixedFont().family() ) ); 00480 d->defaultFonts.append( cgHtml.readEntry( "SerifFont", HTML_DEFAULT_VIEW_SERIF_FONT ) ); 00481 d->defaultFonts.append( cgHtml.readEntry( "SansSerifFont", HTML_DEFAULT_VIEW_SANSSERIF_FONT ) ); 00482 d->defaultFonts.append( cgHtml.readEntry( "CursiveFont", HTML_DEFAULT_VIEW_CURSIVE_FONT ) ); 00483 d->defaultFonts.append( cgHtml.readEntry( "FantasyFont", HTML_DEFAULT_VIEW_FANTASY_FONT ) ); 00484 d->defaultFonts.append( QString( "0" ) ); // font size adjustment 00485 } 00486 00487 if ( reset || cgHtml.hasKey( "MinimumFontSize" ) ) 00488 d->m_minFontSize = cgHtml.readEntry( "MinimumFontSize", HTML_DEFAULT_MIN_FONT_SIZE ); 00489 00490 if ( reset || cgHtml.hasKey( "MediumFontSize" ) ) 00491 d->m_fontSize = cgHtml.readEntry( "MediumFontSize", 12 ); 00492 00493 d->fonts = cgHtml.readEntry( "Fonts", QStringList() ); 00494 00495 if ( reset || cgHtml.hasKey( "DefaultEncoding" ) ) 00496 d->m_encoding = cgHtml.readEntry( "DefaultEncoding", "" ); 00497 00498 if ( reset || cgHtml.hasKey( "EnforceDefaultCharset" ) ) 00499 d->enforceCharset = cgHtml.readEntry( "EnforceDefaultCharset", false ); 00500 00501 // Behavior 00502 if ( reset || cgHtml.hasKey( "ChangeCursor" ) ) 00503 d->m_bChangeCursor = cgHtml.readEntry( "ChangeCursor", KDE_DEFAULT_CHANGECURSOR ); 00504 00505 if ( reset || cgHtml.hasKey("UnderlineLinks") ) 00506 d->m_underlineLink = cgHtml.readEntry( "UnderlineLinks", true ); 00507 00508 if ( reset || cgHtml.hasKey( "HoverLinks" ) ) 00509 { 00510 if ( (d->m_hoverLink = cgHtml.readEntry( "HoverLinks", false ))) 00511 d->m_underlineLink = false; 00512 } 00513 00514 if ( reset || cgHtml.hasKey( "AllowTabulation" ) ) 00515 d->m_allowTabulation = cgHtml.readEntry( "AllowTabulation", false ); 00516 00517 if ( reset || cgHtml.hasKey( "AutoSpellCheck" ) ) 00518 d->m_autoSpellCheck = cgHtml.readEntry( "AutoSpellCheck", true ); 00519 00520 // Other 00521 if ( reset || cgHtml.hasKey( "AutoLoadImages" ) ) 00522 d->m_bAutoLoadImages = cgHtml.readEntry( "AutoLoadImages", true ); 00523 00524 if ( reset || cgHtml.hasKey( "UnfinishedImageFrame" ) ) 00525 d->m_bUnfinishedImageFrame = cgHtml.readEntry( "UnfinishedImageFrame", true ); 00526 00527 if ( reset || cgHtml.hasKey( "ShowAnimations" ) ) 00528 { 00529 QString value = cgHtml.readEntry( "ShowAnimations").toLower(); 00530 if (value == "disabled") 00531 d->m_showAnimations = KAnimationDisabled; 00532 else if (value == "looponce") 00533 d->m_showAnimations = KAnimationLoopOnce; 00534 else 00535 d->m_showAnimations = KAnimationEnabled; 00536 } 00537 00538 if ( reset || cgHtml.hasKey( "SmoothScrolling" ) ) 00539 { 00540 QString value = cgHtml.readEntry( "SmoothScrolling", "whenefficient" ).toLower(); 00541 if (value == "disabled") 00542 d->m_smoothScrolling = KSmoothScrollingDisabled; 00543 else if (value == "whenefficient") 00544 d->m_smoothScrolling = KSmoothScrollingWhenEfficient; 00545 else 00546 d->m_smoothScrolling = KSmoothScrollingEnabled; 00547 } 00548 00549 if ( reset || cgHtml.hasKey( "DNSPrefetch" ) ) 00550 { 00551 // Enabled, Disabled, OnlyWWWAndSLD 00552 QString value = cgHtml.readEntry( "DNSPrefetch", "Enabled" ).toLower(); 00553 if (value == "enabled") 00554 d->m_dnsPrefetch = KDNSPrefetchEnabled; 00555 else if (value == "onlywwwandsld") 00556 d->m_dnsPrefetch = KDNSPrefetchOnlyWWWAndSLD; 00557 else 00558 d->m_dnsPrefetch = KDNSPrefetchDisabled; 00559 } 00560 00561 if ( cgHtml.readEntry( "UserStyleSheetEnabled", false ) == true ) { 00562 if ( reset || cgHtml.hasKey( "UserStyleSheet" ) ) 00563 d->m_userSheet = cgHtml.readEntry( "UserStyleSheet", "" ); 00564 } 00565 00566 d->m_formCompletionEnabled = cgHtml.readEntry("FormCompletion", true); 00567 d->m_maxFormCompletionItems = cgHtml.readEntry("MaxFormCompletionItems", 10); 00568 d->m_autoDelayedActionsEnabled = cgHtml.readEntry ("AutoDelayedActions", true); 00569 d->m_jsErrorsEnabled = cgHtml.readEntry("ReportJSErrors", true); 00570 const QStringList accesskeys = cgHtml.readEntry("FallbackAccessKeysAssignments", QStringList()); 00571 d->m_fallbackAccessKeysAssignments.clear(); 00572 for( QStringList::ConstIterator it = accesskeys.begin(); it != accesskeys.end(); ++it ) 00573 if( (*it).length() > 2 && (*it)[ 1 ] == ':' ) 00574 d->m_fallbackAccessKeysAssignments.append( qMakePair( (*it).mid( 2 ), (*it)[ 0 ] )); 00575 } 00576 00577 // Colors 00578 //In which group ????? 00579 if ( reset || cg.hasKey( "FollowSystemColors" ) ) 00580 d->m_follow_system_colors = cg.readEntry( "FollowSystemColors", false ); 00581 00582 KConfigGroup cgGeneral( config, "General" ); 00583 if ( reset || cgGeneral.exists( ) ) 00584 { 00585 if ( reset || cgGeneral.hasKey( "foreground" ) ) { 00586 QColor def(HTML_DEFAULT_TXT_COLOR); 00587 d->m_textColor = cgGeneral.readEntry( "foreground", def ); 00588 } 00589 00590 if ( reset || cgGeneral.hasKey( "linkColor" ) ) { 00591 QColor def(HTML_DEFAULT_LNK_COLOR); 00592 d->m_linkColor = cgGeneral.readEntry( "linkColor", def ); 00593 } 00594 00595 if ( reset || cgGeneral.hasKey( "visitedLinkColor" ) ) { 00596 QColor def(HTML_DEFAULT_VLNK_COLOR); 00597 d->m_vLinkColor = cgGeneral.readEntry( "visitedLinkColor", def); 00598 } 00599 00600 if ( reset || cgGeneral.hasKey( "background" ) ) { 00601 QColor def(HTML_DEFAULT_BASE_COLOR); 00602 d->m_baseColor = cgGeneral.readEntry( "background", def); 00603 } 00604 } 00605 00606 KConfigGroup cgJava( config, "Java/JavaScript Settings" ); 00607 if( reset || cgJava.exists() ) 00608 { 00609 // The global setting for JavaScript debugging 00610 // This is currently always enabled by default 00611 if ( reset || cgJava.hasKey( "EnableJavaScriptDebug" ) ) 00612 d->m_bEnableJavaScriptDebug = cgJava.readEntry( "EnableJavaScriptDebug", false ); 00613 00614 // The global setting for JavaScript error reporting 00615 if ( reset || cgJava.hasKey( "ReportJavaScriptErrors" ) ) 00616 d->m_bEnableJavaScriptErrorReporting = cgJava.readEntry( "ReportJavaScriptErrors", false ); 00617 00618 // The global setting for popup block passive popup 00619 if ( reset || cgJava.hasKey( "PopupBlockerPassivePopup" ) ) 00620 d->m_jsPopupBlockerPassivePopup = cgJava.readEntry("PopupBlockerPassivePopup", true ); 00621 00622 // Read options from the global "domain" 00623 readDomainSettings(cgJava,reset,true,d->global); 00624 #ifdef DEBUG_SETTINGS 00625 d->global.dump("init global"); 00626 #endif 00627 00628 // The domain-specific settings. 00629 00630 static const char *const domain_keys[] = { // always keep order of keys 00631 "ECMADomains", "JavaDomains", "PluginDomains" 00632 }; 00633 bool check_old_ecma_settings = true; 00634 bool check_old_java_settings = true; 00635 // merge all domains into one list 00636 QMap<QString,int> domainList; // why can't Qt have a QSet? 00637 for (unsigned i = 0; i < sizeof domain_keys/sizeof domain_keys[0]; ++i) { 00638 if ( reset || cgJava.hasKey(domain_keys[i]) ) { 00639 if (i == 0) check_old_ecma_settings = false; 00640 else if (i == 1) check_old_java_settings = false; 00641 const QStringList dl = cgJava.readEntry( domain_keys[i], QStringList() ); 00642 const QMap<QString,int>::Iterator notfound = domainList.end(); 00643 QStringList::ConstIterator it = dl.begin(); 00644 const QStringList::ConstIterator itEnd = dl.end(); 00645 for (; it != itEnd; ++it) { 00646 const QString domain = (*it).toLower(); 00647 QMap<QString,int>::Iterator pos = domainList.find(domain); 00648 if (pos == notfound) domainList.insert(domain,0); 00649 }/*next it*/ 00650 } 00651 }/*next i*/ 00652 00653 if (reset) 00654 d->domainPolicy.clear(); 00655 00656 { 00657 QMap<QString,int>::ConstIterator it = domainList.constBegin(); 00658 const QMap<QString,int>::ConstIterator itEnd = domainList.constEnd(); 00659 for ( ; it != itEnd; ++it) 00660 { 00661 const QString domain = it.key(); 00662 KConfigGroup cg( config, domain ); 00663 readDomainSettings(cg,reset,false,d->domainPolicy[domain]); 00664 #ifdef DEBUG_SETTINGS 00665 d->domainPolicy[domain].dump("init "+domain); 00666 #endif 00667 } 00668 } 00669 00670 bool check_old_java = true; 00671 if( ( reset || cgJava.hasKey( "JavaDomainSettings" ) ) 00672 && check_old_java_settings ) 00673 { 00674 check_old_java = false; 00675 const QStringList domainList = cgJava.readEntry( "JavaDomainSettings", QStringList() ); 00676 QStringList::ConstIterator it = domainList.constBegin(); 00677 const QStringList::ConstIterator itEnd = domainList.constEnd(); 00678 for ( ; it != itEnd; ++it) 00679 { 00680 QString domain; 00681 KJavaScriptAdvice javaAdvice; 00682 KJavaScriptAdvice javaScriptAdvice; 00683 splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); 00684 setup_per_domain_policy(d,domain).m_bEnableJava = 00685 javaAdvice == KJavaScriptAccept; 00686 #ifdef DEBUG_SETTINGS 00687 setup_per_domain_policy(d,domain).dump("JavaDomainSettings 4 "+domain); 00688 #endif 00689 } 00690 } 00691 00692 bool check_old_ecma = true; 00693 if( ( reset || cgJava.hasKey( "ECMADomainSettings" ) ) 00694 && check_old_ecma_settings ) 00695 { 00696 check_old_ecma = false; 00697 const QStringList domainList = cgJava.readEntry( "ECMADomainSettings", QStringList() ); 00698 QStringList::ConstIterator it = domainList.constBegin(); 00699 const QStringList::ConstIterator itEnd = domainList.constEnd(); 00700 for ( ; it != itEnd; ++it) 00701 { 00702 QString domain; 00703 KJavaScriptAdvice javaAdvice; 00704 KJavaScriptAdvice javaScriptAdvice; 00705 splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); 00706 setup_per_domain_policy(d,domain).m_bEnableJavaScript = 00707 javaScriptAdvice == KJavaScriptAccept; 00708 #ifdef DEBUG_SETTINGS 00709 setup_per_domain_policy(d,domain).dump("ECMADomainSettings 4 "+domain); 00710 #endif 00711 } 00712 } 00713 00714 if( ( reset || cgJava.hasKey( "JavaScriptDomainAdvice" ) ) 00715 && ( check_old_java || check_old_ecma ) 00716 && ( check_old_ecma_settings || check_old_java_settings ) ) 00717 { 00718 const QStringList domainList = cgJava.readEntry( "JavaScriptDomainAdvice", QStringList() ); 00719 QStringList::ConstIterator it = domainList.constBegin(); 00720 const QStringList::ConstIterator itEnd = domainList.constEnd(); 00721 for ( ; it != itEnd; ++it) 00722 { 00723 QString domain; 00724 KJavaScriptAdvice javaAdvice; 00725 KJavaScriptAdvice javaScriptAdvice; 00726 splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); 00727 if( check_old_java ) 00728 setup_per_domain_policy(d,domain).m_bEnableJava = 00729 javaAdvice == KJavaScriptAccept; 00730 if( check_old_ecma ) 00731 setup_per_domain_policy(d,domain).m_bEnableJavaScript = 00732 javaScriptAdvice == KJavaScriptAccept; 00733 #ifdef DEBUG_SETTINGS 00734 setup_per_domain_policy(d,domain).dump("JavaScriptDomainAdvice 4 "+domain); 00735 #endif 00736 } 00737 00738 //save all the settings into the new keywords if they don't exist 00739 #if 0 00740 if( check_old_java ) 00741 { 00742 QStringList domainConfig; 00743 PolicyMap::Iterator it; 00744 for( it = d->javaDomainPolicy.begin(); it != d->javaDomainPolicy.end(); ++it ) 00745 { 00746 QByteArray javaPolicy = adviceToStr( it.value() ); 00747 QByteArray javaScriptPolicy = adviceToStr( KJavaScriptDunno ); 00748 domainConfig.append(QString::fromLatin1("%1:%2:%3").arg(it.key()).arg(javaPolicy).arg(javaScriptPolicy)); 00749 } 00750 cg.writeEntry( "JavaDomainSettings", domainConfig ); 00751 } 00752 00753 if( check_old_ecma ) 00754 { 00755 QStringList domainConfig; 00756 PolicyMap::Iterator it; 00757 for( it = d->javaScriptDomainPolicy.begin(); it != d->javaScriptDomainPolicy.end(); ++it ) 00758 { 00759 QByteArray javaPolicy = adviceToStr( KJavaScriptDunno ); 00760 QByteArray javaScriptPolicy = adviceToStr( it.value() ); 00761 domainConfig.append(QString::fromLatin1("%1:%2:%3").arg(it.key()).arg(javaPolicy).arg(javaScriptPolicy)); 00762 } 00763 cg.writeEntry( "ECMADomainSettings", domainConfig ); 00764 } 00765 #endif 00766 } 00767 } 00768 } 00769 00770 00775 static const KPerDomainSettings &lookup_hostname_policy( 00776 const KHTMLSettingsPrivate* const d, 00777 const QString& hostname) 00778 { 00779 #ifdef DEBUG_SETTINGS 00780 kDebug() << "lookup_hostname_policy(" << hostname << ")"; 00781 #endif 00782 if (hostname.isEmpty()) { 00783 #ifdef DEBUG_SETTINGS 00784 d->global.dump("global"); 00785 #endif 00786 return d->global; 00787 } 00788 00789 const PolicyMap::const_iterator notfound = d->domainPolicy.constEnd(); 00790 00791 // First check whether there is a perfect match. 00792 PolicyMap::const_iterator it = d->domainPolicy.find(hostname); 00793 if( it != notfound ) { 00794 #ifdef DEBUG_SETTINGS 00795 kDebug() << "perfect match"; 00796 (*it).dump(hostname); 00797 #endif 00798 // yes, use it (unless dunno) 00799 return *it; 00800 } 00801 00802 // Now, check for partial match. Chop host from the left until 00803 // there's no dots left. 00804 QString host_part = hostname; 00805 int dot_idx = -1; 00806 while( (dot_idx = host_part.indexOf(QChar('.'))) >= 0 ) { 00807 host_part.remove(0,dot_idx); 00808 it = d->domainPolicy.find(host_part); 00809 Q_ASSERT(notfound == d->domainPolicy.end()); 00810 if( it != notfound ) { 00811 #ifdef DEBUG_SETTINGS 00812 kDebug() << "partial match"; 00813 (*it).dump(host_part); 00814 #endif 00815 return *it; 00816 } 00817 // assert(host_part[0] == QChar('.')); 00818 host_part.remove(0,1); // Chop off the dot. 00819 } 00820 00821 // No domain-specific entry: use global domain 00822 #ifdef DEBUG_SETTINGS 00823 kDebug() << "no match"; 00824 d->global.dump("global"); 00825 #endif 00826 return d->global; 00827 } 00828 00829 bool KHTMLSettings::isOpenMiddleClickEnabled() 00830 { 00831 return d->m_bOpenMiddleClick; 00832 } 00833 00834 bool KHTMLSettings::isBackRightClickEnabled() 00835 { 00836 return false; // ## the feature moved to konqueror 00837 } 00838 00839 bool KHTMLSettings::accessKeysEnabled() const 00840 { 00841 return d->m_accessKeysEnabled; 00842 } 00843 00844 bool KHTMLSettings::isAdFilterEnabled() const 00845 { 00846 return d->m_adFilterEnabled; 00847 } 00848 00849 bool KHTMLSettings::isHideAdsEnabled() const 00850 { 00851 return d->m_hideAdsEnabled; 00852 } 00853 00854 bool KHTMLSettings::isAdFiltered( const QString &url ) const 00855 { 00856 if (d->m_adFilterEnabled) 00857 { 00858 if (!url.startsWith("data:")) 00859 { 00860 // Check the blacklist, and only if that matches, the whitelist 00861 return d->adBlackList.isUrlMatched(url) && !d->adWhiteList.isUrlMatched(url); 00862 } 00863 } 00864 return false; 00865 } 00866 00867 QString KHTMLSettings::adFilteredBy( const QString &url, bool *isWhiteListed ) const 00868 { 00869 QString m = d->adWhiteList.urlMatchedBy(url); 00870 if (!m.isEmpty()) 00871 { 00872 if (isWhiteListed != 0) 00873 *isWhiteListed = true; 00874 return (m); 00875 } 00876 00877 m = d->adBlackList.urlMatchedBy(url); 00878 if (!m.isEmpty()) 00879 { 00880 if (isWhiteListed != 0) 00881 *isWhiteListed = false; 00882 return (m); 00883 } 00884 00885 return (QString()); 00886 } 00887 00888 void KHTMLSettings::addAdFilter( const QString &url ) 00889 { 00890 KConfigGroup config = KSharedConfig::openConfig( "khtmlrc", KConfig::NoGlobals )->group( "Filter Settings" ); 00891 00892 QRegExp rx; 00893 00894 // Try compiling to avoid invalid stuff. Only support the basic syntax here... 00895 // ### refactor somewhat 00896 if (url.length()>2 && url[0]=='/' && url[url.length()-1] == '/') 00897 { 00898 QString inside = url.mid(1, url.length()-2); 00899 rx.setPattern(inside); 00900 } 00901 else 00902 { 00903 rx.setPatternSyntax(QRegExp::Wildcard); 00904 rx.setPattern(url); 00905 } 00906 00907 if (rx.isValid()) 00908 { 00909 int last=config.readEntry("Count", 0); 00910 QString key = "Filter-" + QString::number(last); 00911 config.writeEntry(key, url); 00912 config.writeEntry("Count",last+1); 00913 config.sync(); 00914 if (url.startsWith(QLatin1String("@@"))) 00915 d->adWhiteList.addFilter(url); 00916 else 00917 d->adBlackList.addFilter(url); 00918 } 00919 else 00920 { 00921 KMessageBox::error(0, 00922 rx.errorString(), 00923 i18n("Filter error")); 00924 } 00925 } 00926 00927 bool KHTMLSettings::isJavaEnabled( const QString& hostname ) const 00928 { 00929 return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJava; 00930 } 00931 00932 bool KHTMLSettings::isJavaScriptEnabled( const QString& hostname ) const 00933 { 00934 return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJavaScript; 00935 } 00936 00937 bool KHTMLSettings::isJavaScriptDebugEnabled( const QString& /*hostname*/ ) const 00938 { 00939 // debug setting is global for now, but could change in the future 00940 return d->m_bEnableJavaScriptDebug; 00941 } 00942 00943 bool KHTMLSettings::isJavaScriptErrorReportingEnabled( const QString& /*hostname*/ ) const 00944 { 00945 // error reporting setting is global for now, but could change in the future 00946 return d->m_bEnableJavaScriptErrorReporting; 00947 } 00948 00949 bool KHTMLSettings::isPluginsEnabled( const QString& hostname ) const 00950 { 00951 return lookup_hostname_policy(d,hostname.toLower()).m_bEnablePlugins; 00952 } 00953 00954 KHTMLSettings::KJSWindowOpenPolicy KHTMLSettings::windowOpenPolicy( 00955 const QString& hostname) const { 00956 return lookup_hostname_policy(d,hostname.toLower()).m_windowOpenPolicy; 00957 } 00958 00959 KHTMLSettings::KJSWindowMovePolicy KHTMLSettings::windowMovePolicy( 00960 const QString& hostname) const { 00961 return lookup_hostname_policy(d,hostname.toLower()).m_windowMovePolicy; 00962 } 00963 00964 KHTMLSettings::KJSWindowResizePolicy KHTMLSettings::windowResizePolicy( 00965 const QString& hostname) const { 00966 return lookup_hostname_policy(d,hostname.toLower()).m_windowResizePolicy; 00967 } 00968 00969 KHTMLSettings::KJSWindowStatusPolicy KHTMLSettings::windowStatusPolicy( 00970 const QString& hostname) const { 00971 return lookup_hostname_policy(d,hostname.toLower()).m_windowStatusPolicy; 00972 } 00973 00974 KHTMLSettings::KJSWindowFocusPolicy KHTMLSettings::windowFocusPolicy( 00975 const QString& hostname) const { 00976 return lookup_hostname_policy(d,hostname.toLower()).m_windowFocusPolicy; 00977 } 00978 00979 int KHTMLSettings::mediumFontSize() const 00980 { 00981 return d->m_fontSize; 00982 } 00983 00984 int KHTMLSettings::minFontSize() const 00985 { 00986 return d->m_minFontSize; 00987 } 00988 00989 QString KHTMLSettings::settingsToCSS() const 00990 { 00991 // lets start with the link properties 00992 QString str = "a:link {\ncolor: "; 00993 str += d->m_linkColor.name(); 00994 str += ';'; 00995 if(d->m_underlineLink) 00996 str += "\ntext-decoration: underline;"; 00997 00998 if( d->m_bChangeCursor ) 00999 { 01000 str += "\ncursor: pointer;"; 01001 str += "\n}\ninput[type=image] { cursor: pointer;"; 01002 } 01003 str += "\n}\n"; 01004 str += "a:visited {\ncolor: "; 01005 str += d->m_vLinkColor.name(); 01006 str += ';'; 01007 if(d->m_underlineLink) 01008 str += "\ntext-decoration: underline;"; 01009 01010 if( d->m_bChangeCursor ) 01011 str += "\ncursor: pointer;"; 01012 str += "\n}\n"; 01013 01014 if(d->m_hoverLink) 01015 str += "a:link:hover, a:visited:hover { text-decoration: underline; }\n"; 01016 01017 return str; 01018 } 01019 01020 const QString &KHTMLSettings::availableFamilies() 01021 { 01022 if ( !avFamilies ) { 01023 avFamilies = new QString; 01024 QFontDatabase db; 01025 QStringList families = db.families(); 01026 QStringList s; 01027 QRegExp foundryExp(" \\[.+\\]"); 01028 01029 //remove foundry info 01030 QStringList::Iterator f = families.begin(); 01031 const QStringList::Iterator fEnd = families.end(); 01032 01033 for ( ; f != fEnd; ++f ) { 01034 (*f).replace( foundryExp, ""); 01035 if (!s.contains(*f)) 01036 s << *f; 01037 } 01038 s.sort(); 01039 01040 *avFamilies = ',' + s.join(",") + ','; 01041 } 01042 01043 return *avFamilies; 01044 } 01045 01046 QString KHTMLSettings::lookupFont(int i) const 01047 { 01048 QString font; 01049 if (d->fonts.count() > i) 01050 font = d->fonts[i]; 01051 if (font.isEmpty()) 01052 font = d->defaultFonts[i]; 01053 return font; 01054 } 01055 01056 QString KHTMLSettings::stdFontName() const 01057 { 01058 return lookupFont(0); 01059 } 01060 01061 QString KHTMLSettings::fixedFontName() const 01062 { 01063 return lookupFont(1); 01064 } 01065 01066 QString KHTMLSettings::serifFontName() const 01067 { 01068 return lookupFont(2); 01069 } 01070 01071 QString KHTMLSettings::sansSerifFontName() const 01072 { 01073 return lookupFont(3); 01074 } 01075 01076 QString KHTMLSettings::cursiveFontName() const 01077 { 01078 return lookupFont(4); 01079 } 01080 01081 QString KHTMLSettings::fantasyFontName() const 01082 { 01083 return lookupFont(5); 01084 } 01085 01086 void KHTMLSettings::setStdFontName(const QString &n) 01087 { 01088 while(d->fonts.count() <= 0) 01089 d->fonts.append(QString()); 01090 d->fonts[0] = n; 01091 } 01092 01093 void KHTMLSettings::setFixedFontName(const QString &n) 01094 { 01095 while(d->fonts.count() <= 1) 01096 d->fonts.append(QString()); 01097 d->fonts[1] = n; 01098 } 01099 01100 QString KHTMLSettings::userStyleSheet() const 01101 { 01102 return d->m_userSheet; 01103 } 01104 01105 bool KHTMLSettings::isFormCompletionEnabled() const 01106 { 01107 return d->m_formCompletionEnabled; 01108 } 01109 01110 int KHTMLSettings::maxFormCompletionItems() const 01111 { 01112 return d->m_maxFormCompletionItems; 01113 } 01114 01115 const QString &KHTMLSettings::encoding() const 01116 { 01117 return d->m_encoding; 01118 } 01119 01120 bool KHTMLSettings::followSystemColors() const 01121 { 01122 return d->m_follow_system_colors; 01123 } 01124 01125 const QColor& KHTMLSettings::textColor() const 01126 { 01127 return d->m_textColor; 01128 } 01129 01130 const QColor& KHTMLSettings::baseColor() const 01131 { 01132 return d->m_baseColor; 01133 } 01134 01135 const QColor& KHTMLSettings::linkColor() const 01136 { 01137 return d->m_linkColor; 01138 } 01139 01140 const QColor& KHTMLSettings::vLinkColor() const 01141 { 01142 return d->m_vLinkColor; 01143 } 01144 01145 bool KHTMLSettings::autoLoadImages() const 01146 { 01147 return d->m_bAutoLoadImages; 01148 } 01149 01150 bool KHTMLSettings::unfinishedImageFrame() const 01151 { 01152 return d->m_bUnfinishedImageFrame; 01153 } 01154 01155 KHTMLSettings::KAnimationAdvice KHTMLSettings::showAnimations() const 01156 { 01157 return d->m_showAnimations; 01158 } 01159 01160 KHTMLSettings::KSmoothScrollingMode KHTMLSettings::smoothScrolling() const 01161 { 01162 return d->m_smoothScrolling; 01163 } 01164 01165 KHTMLSettings::KDNSPrefetch KHTMLSettings::dnsPrefetch() const 01166 { 01167 return d->m_dnsPrefetch; 01168 } 01169 01170 bool KHTMLSettings::isAutoDelayedActionsEnabled() const 01171 { 01172 return d->m_autoDelayedActionsEnabled; 01173 } 01174 01175 bool KHTMLSettings::jsErrorsEnabled() const 01176 { 01177 return d->m_jsErrorsEnabled; 01178 } 01179 01180 void KHTMLSettings::setJSErrorsEnabled(bool enabled) 01181 { 01182 d->m_jsErrorsEnabled = enabled; 01183 // save it 01184 KConfigGroup cg( KGlobal::config(), "HTML Settings"); 01185 cg.writeEntry("ReportJSErrors", enabled); 01186 cg.sync(); 01187 } 01188 01189 bool KHTMLSettings::allowTabulation() const 01190 { 01191 return d->m_allowTabulation; 01192 } 01193 01194 bool KHTMLSettings::autoSpellCheck() const 01195 { 01196 return d->m_autoSpellCheck; 01197 } 01198 01199 QList< QPair< QString, QChar > > KHTMLSettings::fallbackAccessKeysAssignments() const 01200 { 01201 return d->m_fallbackAccessKeysAssignments; 01202 } 01203 01204 void KHTMLSettings::setJSPopupBlockerPassivePopup(bool enabled) 01205 { 01206 d->m_jsPopupBlockerPassivePopup = enabled; 01207 // save it 01208 KConfigGroup cg( KGlobal::config(), "Java/JavaScript Settings"); 01209 cg.writeEntry("PopupBlockerPassivePopup", enabled); 01210 cg.sync(); 01211 } 01212 01213 bool KHTMLSettings::jsPopupBlockerPassivePopup() const 01214 { 01215 return d->m_jsPopupBlockerPassivePopup; 01216 } 01217 01218 #include "khtml_settings.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:58:54 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:58:54 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.