00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 }
00375
00376 if ( !Private::mInstance )
00377 Private::mInstance = new KTipDialog( new KTipDatabase( tipFiles ), parent );
00378 else
00379
00380
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"