• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

ktip.cpp

Go to the documentation of this file.
00001 /*****************************************************************
00002 
00003 Copyright (c) 2000-2003 Matthias Hoelzer-Kluepfel <mhk@kde.org>
00004                         Tobias Koenig <tokoe@kde.org>
00005                         Daniel Molkentin <molkentin@kde.org>
00006 Copyright (c) 2008 Urs Wolfer <uwolfer @ kde.org>
00007 
00008 Permission is hereby granted, free of charge, to any person obtaining a copy
00009 of this software and associated documentation files (the "Software"), to deal
00010 in the Software without restriction, including without limitation the rights
00011 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012 copies of the Software, and to permit persons to whom the Software is
00013 furnished to do so, subject to the following conditions:
00014 
00015 The above copyright notice and this permission notice shall be included in
00016 all copies or substantial portions of the Software.
00017 
00018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00021 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00022 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00023 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00024 
00025 ******************************************************************/
00026 
00027 #include "ktip.h"
00028 
00029 #include <QtCore/QFile>
00030 #include <QtGui/QCheckBox>
00031 #include <QtGui/QKeyEvent>
00032 #include <QtGui/QLabel>
00033 #include <QtGui/QLayout>
00034 
00035 #include <kaboutdata.h>
00036 #include <kconfig.h>
00037 #include <kdebug.h>
00038 #include <kglobalsettings.h>
00039 #include <kcomponentdata.h>
00040 #include <klocale.h>
00041 #include <kpushbutton.h>
00042 #include <krandom.h>
00043 #include <kseparator.h>
00044 #include <kstandarddirs.h>
00045 #include <ktextbrowser.h>
00046 
00047 class KTipDatabase::Private
00048 {
00049   public:
00050     void loadTips( const QString &tipFile );
00051     void addTips( const QString &tipFile );
00052 
00053     QStringList tips;
00054     int currentTip;
00055 };
00056 
00057 void KTipDatabase::Private::loadTips( const QString &tipFile )
00058 {
00059   tips.clear();
00060   addTips( tipFile );
00061 }
00062 
00068 void KTipDatabase::Private::addTips( const QString &tipFile )
00069 {
00070   QString fileName = KStandardDirs::locate( "data", tipFile );
00071 
00072   if ( fileName.isEmpty() ) {
00073     kDebug() << "KTipDatabase::addTips: can't find '" << tipFile << "' in standard dirs";
00074     return;
00075   }
00076 
00077   QFile file( fileName );
00078   if ( !file.open( QIODevice::ReadOnly ) ) {
00079     kDebug() << "KTipDatabase::addTips: can't open '" << fileName << "' for reading";
00080     return;
00081   }
00082 
00083   QByteArray data = file.readAll();
00084   QString content = QString::fromUtf8( data.constData(), data.size() );
00085   const QRegExp rx( "\\n+" );
00086 
00087   int pos = -1;
00088   while ( ( pos = content.indexOf( "<html>", pos + 1, Qt::CaseInsensitive ) ) != -1 ) {
00093     QString tip = content
00094            .mid( pos + 6, content.indexOf( "</html>", pos, Qt::CaseInsensitive ) - pos - 6 )
00095            .replace( rx, "\n" );
00096 
00097     if ( !tip.endsWith( '\n' ) )
00098       tip += '\n';
00099 
00100     if ( tip.startsWith( '\n' ) )
00101       tip = tip.mid( 1 );
00102 
00103     if ( tip.isEmpty() ) {
00104       kDebug() << "Empty tip found! Skipping! " << pos;
00105       continue;
00106     }
00107 
00108     tips.append( tip );
00109   }
00110 
00111   file.close();
00112 }
00113 
00114 
00115 KTipDatabase::KTipDatabase( const QString &_tipFile )
00116   : d( new Private )
00117 {
00118   QString tipFile = _tipFile;
00119 
00120   if ( tipFile.isEmpty() )
00121     tipFile = KGlobal::mainComponent().aboutData()->appName() + "/tips";
00122 
00123   d->loadTips( tipFile );
00124 
00125   if ( !d->tips.isEmpty() )
00126     d->currentTip = KRandom::random() % d->tips.count();
00127 }
00128 
00129 KTipDatabase::KTipDatabase( const QStringList& tipsFiles )
00130   : d( new Private )
00131 {
00132   if ( tipsFiles.isEmpty() || ( ( tipsFiles.count() == 1 ) && tipsFiles.first().isEmpty() ) ) {
00133     d->addTips( KGlobal::mainComponent().aboutData()->appName() + "/tips" );
00134   } else {
00135     for ( QStringList::ConstIterator it = tipsFiles.begin(); it != tipsFiles.end(); ++it )
00136       d->addTips( *it );
00137   }
00138 
00139   if ( !d->tips.isEmpty() )
00140     d->currentTip = KRandom::random() % d->tips.count();
00141 }
00142 
00143 KTipDatabase::~KTipDatabase()
00144 {
00145     delete d;
00146 }
00147 
00148 void KTipDatabase::nextTip()
00149 {
00150   if ( d->tips.isEmpty() )
00151     return;
00152 
00153   d->currentTip += 1;
00154 
00155   if ( d->currentTip >= (int) d->tips.count() )
00156     d->currentTip = 0;
00157 }
00158 
00159 void KTipDatabase::prevTip()
00160 {
00161   if ( d->tips.isEmpty() )
00162     return;
00163 
00164   d->currentTip -= 1;
00165 
00166   if ( d->currentTip < 0 )
00167     d->currentTip = d->tips.count() - 1;
00168 }
00169 
00170 QString KTipDatabase::tip() const
00171 {
00172   if ( d->tips.isEmpty() )
00173     return QString();
00174 
00175   return d->tips[ d->currentTip ];
00176 }
00177 
00178 
00179 class KTipDialog::Private
00180 {
00181   public:
00182     Private( KTipDialog *_parent )
00183       : parent( _parent )
00184     {
00185     }
00186 
00187     void _k_nextTip();
00188     void _k_prevTip();
00189     void _k_showOnStart( bool );
00190 
00191     KTipDialog *parent;
00192     KTipDatabase *database;
00193     QCheckBox *tipOnStart;
00194     KTextBrowser *tipText;
00195 
00196     static KTipDialog *mInstance;
00197 };
00198 
00199 KTipDialog *KTipDialog::Private::mInstance = 0;
00200 
00201 void KTipDialog::Private::_k_prevTip()
00202 {
00203   database->prevTip();
00204   tipText->setHtml( QString::fromLatin1( "<html><body>%1</body></html>" )
00205                   .arg( i18n( database->tip().toUtf8() ) ) );
00206 }
00207 
00208 void KTipDialog::Private::_k_nextTip()
00209 {
00210   database->nextTip();
00211   tipText->setHtml( QString::fromLatin1( "<html><body>%1</body></html>" )
00212                   .arg( i18n( database->tip().toUtf8() ) ) );
00213 }
00214 
00215 void KTipDialog::Private::_k_showOnStart( bool on )
00216 {
00217   parent->setShowOnStart( on );
00218 }
00219 
00220 
00221 KTipDialog::KTipDialog( KTipDatabase *database, QWidget *parent )
00222   : KDialog( parent ),
00223     d( new Private( this ) )
00224 {
00225   setButtons( KDialog::None );
00226   setCaption( i18n( "Tip of the Day" ) );
00227 
00232   bool isTipDialog = (parent != 0);
00233 
00234   d->database = database;
00235 
00236   setWindowIcon(KIcon("ktip"));
00237 
00238   QWidget *widget = new QWidget( this );
00239   setMainWidget( widget );
00240   QVBoxLayout *mainLayout = new QVBoxLayout( widget );
00241   mainLayout->setMargin( 0 );
00242 
00243   if ( isTipDialog ) {
00244     QLabel *titleLabel = new QLabel( this );
00245     titleLabel->setText( i18n( "Did you know...?\n" ) );
00246     titleLabel->setFont( QFont( KGlobalSettings::generalFont().family(), 20, QFont::Bold ) );
00247     titleLabel->setAlignment( Qt::AlignCenter );
00248     mainLayout->addWidget( titleLabel );
00249   }
00250 
00251   QHBoxLayout *browserLayout = new QHBoxLayout();
00252   mainLayout->addLayout( browserLayout );
00253 
00254   d->tipText = new KTextBrowser( this );
00255 
00256   d->tipText->setOpenExternalLinks( true );
00257 
00258   d->tipText->setWordWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
00259 
00260   QStringList paths;
00261   paths << KGlobal::dirs()->resourceDirs( "icon" )
00262         << KGlobal::dirs()->findResourceDir( "data", "kdewizard/pics" ) + "kdewizard/pics/";
00263 
00264   d->tipText->setSearchPaths( paths );
00265 
00266   d->tipText->setFrameStyle( QFrame::NoFrame );
00267   d->tipText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00268   QPalette tipPal(d->tipText->palette());
00269   tipPal.setColor(QPalette::Base, Qt::transparent);
00270   tipPal.setColor(QPalette::Text, tipPal.color(QPalette::WindowText));
00271   d->tipText->setPalette(tipPal);
00272 
00273   browserLayout->addWidget( d->tipText );
00274 
00275   QLabel *label = new QLabel( this );
00276   label->setPixmap( KStandardDirs::locate( "data", "kdeui/pics/ktip-bulb.png" ) );
00277   label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
00278   browserLayout->addWidget( label );
00279 
00280   if ( !isTipDialog ) {
00281     resize( 520, 280 );
00282     QSize sh = size();
00283 
00284     QRect rect = KGlobalSettings::splashScreenDesktopGeometry();
00285 
00286     move( rect.x() + ( rect.width() - sh.width() ) / 2,
00287           rect.y() + ( rect.height() - sh.height() ) / 2 );
00288   }
00289 
00290   KSeparator* sep = new KSeparator( Qt::Horizontal );
00291   mainLayout->addWidget( sep );
00292 
00293   QHBoxLayout *buttonLayout = new QHBoxLayout();
00294 
00295   mainLayout->addLayout( buttonLayout );
00296 
00297   d->tipOnStart = new QCheckBox( i18n( "&Show tips on startup" ) );
00298   buttonLayout->addWidget( d->tipOnStart, 1 );
00299 
00300   KPushButton *prev = new KPushButton( KStandardGuiItem::back( KStandardGuiItem::UseRTL ) );
00301   prev->setText( i18n( "&Previous" ) );
00302   buttonLayout->addWidget( prev );
00303 
00304   KPushButton *next = new KPushButton( KStandardGuiItem::forward( KStandardGuiItem::UseRTL ));
00305   next->setText( i18nc( "Opposite to Previous", "&Next" ) );
00306   buttonLayout->addWidget( next );
00307 
00308   KPushButton *ok = new KPushButton( KStandardGuiItem::close());
00309   ok->setDefault( true );
00310   buttonLayout->addWidget( ok );
00311 
00312   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00313   d->tipOnStart->setChecked( config.readEntry( "RunOnStart", true ) );
00314 
00315   connect( next, SIGNAL( clicked() ), this, SLOT( _k_nextTip() ) );
00316   connect( prev, SIGNAL( clicked() ), this, SLOT( _k_prevTip() ) );
00317   connect( ok, SIGNAL( clicked() ), this, SLOT( accept() ) );
00318   connect( d->tipOnStart, SIGNAL( toggled( bool ) ), this, SLOT( _k_showOnStart( bool ) ) );
00319 
00320   ok->setFocus();
00321 
00322   d->_k_nextTip();
00323 }
00324 
00325 KTipDialog::~KTipDialog()
00326 {
00327   if ( Private::mInstance == this )
00328     Private::mInstance = 0L;
00329   delete d;
00330 }
00331 
00336 void KTipDialog::showTip( const QString &tipFile, bool force )
00337 {
00338   showTip( 0, tipFile, force );
00339 }
00340 
00341 void KTipDialog::showTip( QWidget *parent, const QString &tipFile, bool force )
00342 {
00343   showMultiTip( parent, QStringList( tipFile ), force );
00344 }
00345 
00346 void KTipDialog::showMultiTip( QWidget *parent, const QStringList &tipFiles, bool force )
00347 {
00348   KConfigGroup configGroup( KGlobal::config(), "TipOfDay" );
00349 
00350   const bool runOnStart = configGroup.readEntry( "RunOnStart", true );
00351 
00352   if ( !force ) {
00353     if ( !runOnStart )
00354       return;
00355 
00356     // showing the tooltips on startup suggests the tooltip
00357     // will be shown *each time* on startup, not $random days later
00358     // TODO either remove or uncomment this code, but make the situation clear
00359     /*bool hasLastShown = configGroup.hasKey( "TipLastShown" );
00360     if ( hasLastShown ) {
00361       const int oneDay = 24 * 60 * 60;
00362       QDateTime lastShown = configGroup.readEntry( "TipLastShown", QDateTime() );
00363 
00364       // Show tip roughly once a week
00365       if ( lastShown.secsTo( QDateTime::currentDateTime() ) < (oneDay + (KRandom::random() % (10 * oneDay))) )
00366         return;
00367     }
00368 
00369     configGroup.writeEntry( "TipLastShown", QDateTime::currentDateTime() );
00370 
00371     if ( !hasLastShown )
00372       return; // Don't show tip on first start*/
00373   }
00374 
00375   if ( !Private::mInstance )
00376     Private::mInstance = new KTipDialog( new KTipDatabase( tipFiles ), parent );
00377   else
00378       // The application might have changed the RunOnStart option in its own
00379       // configuration dialog, so we should update the checkbox.
00380       Private::mInstance->d->tipOnStart->setChecked( runOnStart );
00381 
00382   Private::mInstance->show();
00383   Private::mInstance->raise();
00384 }
00385 
00386 void KTipDialog::setShowOnStart( bool on )
00387 {
00388   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00389   config.writeEntry( "RunOnStart", on );
00390 }
00391 
00392 bool KTipDialog::eventFilter( QObject *object, QEvent *event )
00393 {
00394   if ( object == d->tipText && event->type() == QEvent::KeyPress &&
00395        (((QKeyEvent *)event)->key() == Qt::Key_Return ||
00396        ((QKeyEvent *)event)->key() == Qt::Key_Space ))
00397     accept();
00398 
00407   return QWidget::eventFilter( object, event );
00408 }
00409 
00410 
00411 #include "ktip.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal