• Skip to content
  • Skip to link menu
KDE 4.2 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   mainLayout->setSpacing( spacingHint() );
00243 
00244   if ( isTipDialog ) {
00245     QLabel *titleLabel = new QLabel( this );
00246     titleLabel->setText( i18n( "Did you know...?\n" ) );
00247     titleLabel->setFont( QFont( KGlobalSettings::generalFont().family(), 20, QFont::Bold ) );
00248     titleLabel->setAlignment( Qt::AlignCenter );
00249     mainLayout->addWidget( titleLabel );
00250   }
00251 
00252   QHBoxLayout *browserLayout = new QHBoxLayout();
00253   browserLayout->setMargin( marginHint() );
00254   mainLayout->addLayout( browserLayout );
00255 
00256   d->tipText = new KTextBrowser( this );
00257 
00258   d->tipText->setOpenExternalLinks( true );
00259 
00260   d->tipText->setWordWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
00261 
00262   QStringList paths;
00263   paths << KGlobal::dirs()->resourceDirs( "icon" )
00264         << KGlobal::dirs()->findResourceDir( "data", "kdewizard/pics" ) + "kdewizard/pics/";
00265 
00266   d->tipText->setSearchPaths( paths );
00267 
00268   d->tipText->setFrameStyle( QFrame::NoFrame );
00269   d->tipText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00270   QPalette tipPal(d->tipText->palette());
00271   tipPal.setColor(QPalette::Base, Qt::transparent);
00272   d->tipText->setPalette(tipPal);
00273 
00274   browserLayout->addWidget( d->tipText );
00275 
00276   QLabel *label = new QLabel( this );
00277   label->setPixmap( KStandardDirs::locate( "data", "kdeui/pics/ktip-bulb.png" ) );
00278   label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
00279   browserLayout->addWidget( label );
00280 
00281   if ( !isTipDialog ) {
00282     resize( 520, 280 );
00283     QSize sh = size();
00284 
00285     QRect rect = KGlobalSettings::splashScreenDesktopGeometry();
00286 
00287     move( rect.x() + ( rect.width() - sh.width() ) / 2,
00288           rect.y() + ( rect.height() - sh.height() ) / 2 );
00289   }
00290 
00291   KSeparator* sep = new KSeparator( Qt::Horizontal );
00292   mainLayout->addWidget( sep );
00293 
00294   QHBoxLayout *buttonLayout = new QHBoxLayout();
00295 
00296   mainLayout->addLayout( buttonLayout );
00297 
00298   d->tipOnStart = new QCheckBox( i18n( "&Show tips on startup" ) );
00299   buttonLayout->addWidget( d->tipOnStart, 1 );
00300 
00301   KPushButton *prev = new KPushButton( KStandardGuiItem::back( KStandardGuiItem::UseRTL ) );
00302   prev->setText( i18n( "&Previous" ) );
00303   buttonLayout->addWidget( prev );
00304 
00305   KPushButton *next = new KPushButton( KStandardGuiItem::forward( KStandardGuiItem::UseRTL ));
00306   next->setText( i18nc( "Opposite to Previous", "&Next" ) );
00307   buttonLayout->addWidget( next );
00308 
00309   KPushButton *ok = new KPushButton( KStandardGuiItem::close());
00310   ok->setDefault( true );
00311   buttonLayout->addWidget( ok );
00312 
00313   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00314   d->tipOnStart->setChecked( config.readEntry( "RunOnStart", true ) );
00315 
00316   connect( next, SIGNAL( clicked() ), this, SLOT( _k_nextTip() ) );
00317   connect( prev, SIGNAL( clicked() ), this, SLOT( _k_prevTip() ) );
00318   connect( ok, SIGNAL( clicked() ), this, SLOT( accept() ) );
00319   connect( d->tipOnStart, SIGNAL( toggled( bool ) ), this, SLOT( _k_showOnStart( bool ) ) );
00320 
00321   ok->setFocus();
00322 
00323   d->_k_nextTip();
00324 }
00325 
00326 KTipDialog::~KTipDialog()
00327 {
00328   if ( Private::mInstance == this )
00329     Private::mInstance = 0L;
00330   delete d;
00331 }
00332 
00337 void KTipDialog::showTip( const QString &tipFile, bool force )
00338 {
00339   showTip( 0, tipFile, force );
00340 }
00341 
00342 void KTipDialog::showTip( QWidget *parent, const QString &tipFile, bool force )
00343 {
00344   showMultiTip( parent, QStringList( tipFile ), force );
00345 }
00346 
00347 void KTipDialog::showMultiTip( QWidget *parent, const QStringList &tipFiles, bool force )
00348 {
00349   KConfigGroup configGroup( KGlobal::config(), "TipOfDay" );
00350 
00351   const bool runOnStart = configGroup.readEntry( "RunOnStart", true );
00352 
00353   if ( !force ) {
00354     if ( !runOnStart )
00355       return;
00356 
00357     // showing the tooltips on startup suggests the tooltip
00358     // will be shown *each time* on startup, not $random days later
00359     // TODO either remove or uncomment this code, but make the situation clear
00360     /*bool hasLastShown = configGroup.hasKey( "TipLastShown" );
00361     if ( hasLastShown ) {
00362       const int oneDay = 24 * 60 * 60;
00363       QDateTime lastShown = configGroup.readEntry( "TipLastShown", QDateTime() );
00364 
00365       // Show tip roughly once a week
00366       if ( lastShown.secsTo( QDateTime::currentDateTime() ) < (oneDay + (KRandom::random() % (10 * oneDay))) )
00367         return;
00368     }
00369 
00370     configGroup.writeEntry( "TipLastShown", QDateTime::currentDateTime() );
00371 
00372     if ( !hasLastShown )
00373       return; // Don't show tip on first start*/
00374   }
00375 
00376   if ( !Private::mInstance )
00377     Private::mInstance = new KTipDialog( new KTipDatabase( tipFiles ), parent );
00378   else
00379       // The application might have changed the RunOnStart option in its own
00380       // configuration dialog, so we should update the checkbox.
00381       Private::mInstance->d->tipOnStart->setChecked( runOnStart );
00382 
00383   Private::mInstance->show();
00384   Private::mInstance->raise();
00385 }
00386 
00387 void KTipDialog::setShowOnStart( bool on )
00388 {
00389   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00390   config.writeEntry( "RunOnStart", on );
00391 }
00392 
00393 bool KTipDialog::eventFilter( QObject *object, QEvent *event )
00394 {
00395   if ( object == d->tipText && event->type() == QEvent::KeyPress &&
00396        (((QKeyEvent *)event)->key() == Qt::Key_Return ||
00397        ((QKeyEvent *)event)->key() == Qt::Key_Space ))
00398     accept();
00399 
00408   return QWidget::eventFilter( object, event );
00409 }
00410 
00411 
00412 #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
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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