• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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     ~Private()
00187     {
00188       delete database;
00189     }
00190 
00191     void _k_nextTip();
00192     void _k_prevTip();
00193     void _k_showOnStart( bool );
00194 
00195     KTipDialog *parent;
00196     KTipDatabase *database;
00197     QCheckBox *tipOnStart;
00198     KTextBrowser *tipText;
00199 
00200     static KTipDialog *mInstance;
00201 };
00202 
00203 KTipDialog *KTipDialog::Private::mInstance = 0;
00204 
00205 void KTipDialog::Private::_k_prevTip()
00206 {
00207   database->prevTip();
00208   tipText->setHtml( QString::fromLatin1( "<html><body>%1</body></html>" )
00209                   .arg( i18n( database->tip().toUtf8() ) ) );
00210 }
00211 
00212 void KTipDialog::Private::_k_nextTip()
00213 {
00214   database->nextTip();
00215   tipText->setHtml( QString::fromLatin1( "<html><body>%1</body></html>" )
00216                   .arg( i18n( database->tip().toUtf8() ) ) );
00217 }
00218 
00219 void KTipDialog::Private::_k_showOnStart( bool on )
00220 {
00221   parent->setShowOnStart( on );
00222 }
00223 
00224 
00225 KTipDialog::KTipDialog( KTipDatabase *database, QWidget *parent )
00226   : KDialog( parent ),
00227     d( new Private( this ) )
00228 {
00229   setButtons( KDialog::None );
00230   setCaption( i18n( "Tip of the Day" ) );
00231 
00236   bool isTipDialog = (parent != 0);
00237 
00238   d->database = database;
00239 
00240   setWindowIcon(KIcon("ktip"));
00241 
00242   QWidget *widget = new QWidget( this );
00243   setMainWidget( widget );
00244   QVBoxLayout *mainLayout = new QVBoxLayout( widget );
00245   mainLayout->setMargin( 0 );
00246 
00247   if ( isTipDialog ) {
00248     QLabel *titleLabel = new QLabel( this );
00249     titleLabel->setText( i18n( "Did you know...?\n" ) );
00250     titleLabel->setFont( QFont( KGlobalSettings::generalFont().family(), 20, QFont::Bold ) );
00251     titleLabel->setAlignment( Qt::AlignCenter );
00252     mainLayout->addWidget( titleLabel );
00253   }
00254 
00255   QHBoxLayout *browserLayout = new QHBoxLayout();
00256   mainLayout->addLayout( browserLayout );
00257 
00258   d->tipText = new KTextBrowser( this );
00259 
00260   d->tipText->setOpenExternalLinks( true );
00261 
00262   d->tipText->setWordWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
00263 
00264   QStringList paths;
00265   paths << KGlobal::dirs()->resourceDirs( "icon" )
00266         << KGlobal::dirs()->findResourceDir( "data", "kdewizard/pics" ) + "kdewizard/pics/";
00267 
00268   d->tipText->setSearchPaths( paths );
00269 
00270   d->tipText->setFrameStyle( QFrame::NoFrame );
00271   d->tipText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00272   QPalette tipPal(d->tipText->palette());
00273   tipPal.setColor(QPalette::Base, Qt::transparent);
00274   tipPal.setColor(QPalette::Text, tipPal.color(QPalette::WindowText));
00275   d->tipText->setPalette(tipPal);
00276 
00277   browserLayout->addWidget( d->tipText );
00278 
00279   QLabel *label = new QLabel( this );
00280   label->setPixmap( KStandardDirs::locate( "data", "kdeui/pics/ktip-bulb.png" ) );
00281   label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
00282   browserLayout->addWidget( label );
00283 
00284   if ( !isTipDialog ) {
00285     resize( 520, 280 );
00286     QSize sh = size();
00287 
00288     QRect rect = KGlobalSettings::splashScreenDesktopGeometry();
00289 
00290     move( rect.x() + ( rect.width() - sh.width() ) / 2,
00291           rect.y() + ( rect.height() - sh.height() ) / 2 );
00292   }
00293 
00294   KSeparator* sep = new KSeparator( Qt::Horizontal );
00295   mainLayout->addWidget( sep );
00296 
00297   QHBoxLayout *buttonLayout = new QHBoxLayout();
00298 
00299   mainLayout->addLayout( buttonLayout );
00300 
00301   d->tipOnStart = new QCheckBox( i18n( "&Show tips on startup" ) );
00302   buttonLayout->addWidget( d->tipOnStart, 1 );
00303 
00304   KPushButton *prev = new KPushButton( KStandardGuiItem::back( KStandardGuiItem::UseRTL ) );
00305   prev->setText( i18n( "&Previous" ) );
00306   buttonLayout->addWidget( prev );
00307 
00308   KPushButton *next = new KPushButton( KStandardGuiItem::forward( KStandardGuiItem::UseRTL ));
00309   next->setText( i18nc( "Opposite to Previous", "&Next" ) );
00310   buttonLayout->addWidget( next );
00311 
00312   KPushButton *ok = new KPushButton( KStandardGuiItem::close());
00313   ok->setDefault( true );
00314   buttonLayout->addWidget( ok );
00315 
00316   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00317   d->tipOnStart->setChecked( config.readEntry( "RunOnStart", true ) );
00318 
00319   connect( next, SIGNAL( clicked() ), this, SLOT( _k_nextTip() ) );
00320   connect( prev, SIGNAL( clicked() ), this, SLOT( _k_prevTip() ) );
00321   connect( ok, SIGNAL( clicked() ), this, SLOT( accept() ) );
00322   connect( d->tipOnStart, SIGNAL( toggled( bool ) ), this, SLOT( _k_showOnStart( bool ) ) );
00323 
00324   ok->setFocus();
00325 
00326   d->_k_nextTip();
00327 }
00328 
00329 KTipDialog::~KTipDialog()
00330 {
00331   if ( Private::mInstance == this )
00332     Private::mInstance = 0L;
00333   delete d;
00334 }
00335 
00340 void KTipDialog::showTip( const QString &tipFile, bool force )
00341 {
00342   showTip( 0, tipFile, force );
00343 }
00344 
00345 void KTipDialog::showTip( QWidget *parent, const QString &tipFile, bool force )
00346 {
00347   showMultiTip( parent, QStringList( tipFile ), force );
00348 }
00349 
00350 void KTipDialog::showMultiTip( QWidget *parent, const QStringList &tipFiles, bool force )
00351 {
00352   KConfigGroup configGroup( KGlobal::config(), "TipOfDay" );
00353 
00354   const bool runOnStart = configGroup.readEntry( "RunOnStart", true );
00355 
00356   if ( !force ) {
00357     if ( !runOnStart )
00358       return;
00359 
00360     // showing the tooltips on startup suggests the tooltip
00361     // will be shown *each time* on startup, not $random days later
00362     // TODO either remove or uncomment this code, but make the situation clear
00363     /*bool hasLastShown = configGroup.hasKey( "TipLastShown" );
00364     if ( hasLastShown ) {
00365       const int oneDay = 24 * 60 * 60;
00366       QDateTime lastShown = configGroup.readEntry( "TipLastShown", QDateTime() );
00367 
00368       // Show tip roughly once a week
00369       if ( lastShown.secsTo( QDateTime::currentDateTime() ) < (oneDay + (KRandom::random() % (10 * oneDay))) )
00370         return;
00371     }
00372 
00373     configGroup.writeEntry( "TipLastShown", QDateTime::currentDateTime() );
00374 
00375     if ( !hasLastShown )
00376       return; // Don't show tip on first start*/
00377   }
00378 
00379   if ( !Private::mInstance )
00380     Private::mInstance = new KTipDialog( new KTipDatabase( tipFiles ), parent );
00381   else
00382       // The application might have changed the RunOnStart option in its own
00383       // configuration dialog, so we should update the checkbox.
00384       Private::mInstance->d->tipOnStart->setChecked( runOnStart );
00385 
00386   Private::mInstance->show();
00387   Private::mInstance->raise();
00388 }
00389 
00390 void KTipDialog::setShowOnStart( bool on )
00391 {
00392   KConfigGroup config( KGlobal::config(), "TipOfDay" );
00393   config.writeEntry( "RunOnStart", on );
00394 }
00395 
00396 bool KTipDialog::eventFilter( QObject *object, QEvent *event )
00397 {
00398   if ( object == d->tipText && event->type() == QEvent::KeyPress &&
00399        (((QKeyEvent *)event)->key() == Qt::Key_Return ||
00400        ((QKeyEvent *)event)->key() == Qt::Key_Space ))
00401     accept();
00402 
00411   return QWidget::eventFilter( object, event );
00412 }
00413 
00414 
00415 #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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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