kdeui Library API Documentation

ktip.cpp

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 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 ******************************************************************/
00025 
00026 #include <qcheckbox.h>
00027 #include <qfile.h>
00028 #include <qhbox.h>
00029 #include <qlabel.h>
00030 #include <qlayout.h>
00031 #include <qpushbutton.h>
00032 #include <qregexp.h>
00033 #include <qtextstream.h>
00034 #include <qimage.h>
00035 
00036 #include <kaboutdata.h>
00037 #include <kapplication.h>
00038 #include <kconfig.h>
00039 #include <kdebug.h>
00040 #include <kglobal.h>
00041 #include <kiconloader.h>
00042 #include <klocale.h>
00043 #include <kpushbutton.h>
00044 #include <kseparator.h>
00045 #include <kstandarddirs.h>
00046 #include <kstdguiitem.h>
00047 #include <ktextbrowser.h>
00048 #include <kiconeffect.h>
00049 #include <kglobalsettings.h>
00050 #include <kwin.h>
00051 
00052 #include "ktip.h"
00053 
00054 
00055 KTipDatabase::KTipDatabase(const QString &_tipFile)
00056 {
00057     QString tipFile = _tipFile;
00058     if (tipFile.isEmpty())
00059     tipFile = QString::fromLatin1(KGlobal::instance()->aboutData()->appName()) + "/tips";
00060 
00061     loadTips(tipFile);
00062 
00063     if (!mTips.isEmpty())
00064     mCurrent = kapp->random() % mTips.count();
00065 }
00066 
00067 
00068 KTipDatabase::KTipDatabase( const QStringList& tipsFiles )
00069 {
00070    if ( tipsFiles.isEmpty() || ( ( tipsFiles.count() == 1 ) && tipsFiles.first().isEmpty() ) )
00071    {
00072        addTips(QString::fromLatin1(KGlobal::instance()->aboutData()->appName()) + "/tips");
00073    }
00074    else
00075    {
00076        for (QStringList::ConstIterator it = tipsFiles.begin(); it != tipsFiles.end(); ++it)
00077            addTips( *it );
00078    }
00079     if (!mTips.isEmpty())
00080     mCurrent = kapp->random() % mTips.count();
00081 
00082 }
00083 
00084 void KTipDatabase::loadTips(const QString &tipFile)
00085 {
00086     mTips.clear();
00087     addTips(tipFile);
00088 }
00089 
00090 // if you change something here, please update the script
00091 // preparetips, which depends on extracting exactly the same
00092 // text as done here.
00093 void KTipDatabase::addTips(const QString& tipFile )
00094 {
00095     QString fileName = locate("data", tipFile);
00096 
00097     if (fileName.isEmpty())
00098     {
00099     kdDebug() << "KTipDatabase::addTips: can't find '" << tipFile << "' in standard dirs" << endl;
00100         return;
00101     }
00102 
00103     QFile file(fileName);
00104     if (!file.open(IO_ReadOnly))
00105     {
00106     kdDebug() << "KTipDatabase::addTips: can't open '" << fileName << "' for reading" << endl;
00107     return;
00108     }
00109 
00110     QByteArray data = file.readAll();
00111     QString content = QString::fromUtf8(data.data(), data.size());
00112     const QRegExp rx("\\n+");
00113 
00114     int pos = -1;
00115     while ((pos = content.find("<html>", pos + 1, false)) != -1)
00116     {
00117        // to make translations work, tip extraction here must exactly 
00118        // match what is done by the preparetips script 
00119        QString tip = content 
00120            .mid(pos + 6, content.find("</html>", pos, false) - pos - 6)
00121            .replace(rx, "\n");
00122        if (!tip.endsWith("\n"))
00123            tip += "\n";
00124        if (tip.startsWith("\n")) 
00125             tip = tip.mid(1); 
00126         if (tip.isEmpty())
00127         {
00128             kdDebug() << "Empty tip found! Skipping! " << pos << endl;
00129             continue;
00130         }
00131     mTips.append(tip);
00132     }
00133 
00134     file.close();
00135 
00136 }
00137 
00138 void KTipDatabase::nextTip()
00139 {
00140     if (mTips.isEmpty())
00141     return ;
00142     mCurrent += 1;
00143     if (mCurrent >= (int) mTips.count())
00144     mCurrent = 0;
00145 }
00146 
00147 
00148 void KTipDatabase::prevTip()
00149 {
00150     if (mTips.isEmpty())
00151     return ;
00152     mCurrent -= 1;
00153     if (mCurrent < 0)
00154     mCurrent = mTips.count() - 1;
00155 }
00156 
00157 
00158 QString KTipDatabase::tip() const
00159 {
00160     if (mTips.isEmpty())
00161     return QString::null;
00162     return mTips[mCurrent];
00163 }
00164 
00165 KTipDialog *KTipDialog::mInstance = 0;
00166 
00167 
00168 KTipDialog::KTipDialog(KTipDatabase *db, QWidget *parent, const char *name)
00169   : KDialog(parent, name)
00170 {
00175     bool isTipDialog = (parent);
00176 
00177     QImage img;
00178     int h,s,v;
00179 
00180     mBlendedColor = KGlobalSettings::activeTitleColor();
00181     mBlendedColor.hsv(&h,&s,&v);
00182     mBlendedColor.setHsv(h, int(s*(71/76.0)), int(v*(67/93.0)));
00183 
00184     if (!isTipDialog)
00185     {
00186     img = QImage(locate("data", "kdewizard/pics/wizard_small.png"));
00187     // colorize and check to figure the correct color
00188     KIconEffect::colorize(img, mBlendedColor, 1.0);
00189     QRgb colPixel( img.pixel(0,0) );
00190 
00191     mBlendedColor = QColor(qRed(colPixel),qGreen(colPixel),qBlue(colPixel));
00192     }
00193 
00194     mBaseColor = KGlobalSettings::alternateBackgroundColor();
00195     mBaseColor.hsv(&h,&s,&v);
00196     mBaseColor.setHsv(h, int(s*(10/6.0)), int(v*(93/99.0)));
00197 
00198     mTextColor = KGlobalSettings::textColor();
00199 
00200 
00201     mDatabase = db;
00202 
00203     setCaption(i18n("Tip of the Day"));
00204     KWin::setIcons( winId(),
00205                     KGlobal::iconLoader()->loadIcon( "idea", KIcon::NoGroup, 32 ),
00206                     KGlobal::iconLoader()->loadIcon( "idea", KIcon::NoGroup, 16 ) );
00207 
00208     QVBoxLayout *vbox = new QVBoxLayout(this, marginHint(), spacingHint());
00209 
00210    if (isTipDialog)
00211     {
00212     QHBoxLayout *pl = new QHBoxLayout(vbox, 0, 0);
00213 
00214     QLabel *bulb = new QLabel(this);
00215     bulb->setPixmap(locate("data", "kdeui/pics/ktip-bulb.png"));
00216     pl->addWidget(bulb);
00217 
00218     QLabel *titlePane = new QLabel(this);
00219     titlePane->setBackgroundPixmap(locate("data", "kdeui/pics/ktip-background.png"));
00220     titlePane->setText(i18n("Did you know...?\n"));
00221     titlePane->setFont(QFont(KGlobalSettings::generalFont().family(), 20, QFont::Bold));
00222     titlePane->setAlignment(QLabel::AlignCenter);
00223     pl->addWidget(titlePane, 100);
00224     }
00225 
00226     QHBox *hbox = new QHBox(this);
00227     hbox->setSpacing(0);
00228     hbox->setFrameStyle(QFrame::Panel | QFrame::Sunken);
00229     vbox->addWidget(hbox);
00230 
00231     QHBox *tl = new QHBox(hbox);
00232     tl->setMargin(7);
00233     tl->setBackgroundColor(mBlendedColor);
00234 
00235     QHBox *topLeft = new QHBox(tl);
00236     topLeft->setMargin(15);
00237     topLeft->setBackgroundColor(mBaseColor);
00238 
00239     mTipText = new KTextBrowser(topLeft);
00240 
00241     mTipText->setWrapPolicy( QTextEdit::AtWordOrDocumentBoundary );
00242     mTipText->mimeSourceFactory()->addFilePath(
00243     KGlobal::dirs()->findResourceDir("data", "kdewizard/pics")+"kdewizard/pics/");
00244     mTipText->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
00245     mTipText->setHScrollBarMode(QScrollView::AlwaysOff);
00246     mTipText->setLinkUnderline(false);
00247 
00248     QStyleSheet *sheet = mTipText->styleSheet();
00249     QStyleSheetItem *item = sheet->item("a");
00250     item->setFontWeight(QFont::Bold);
00251     mTipText->setStyleSheet(sheet);
00252     QPalette pal = mTipText->palette();
00253     pal.setColor( QPalette::Active, QColorGroup::Link, mBlendedColor );
00254     pal.setColor( QPalette::Inactive, QColorGroup::Link, mBlendedColor );
00255     mTipText->setPalette(pal);
00256 
00257     QStringList icons = KGlobal::dirs()->resourceDirs("icon");
00258     QStringList::Iterator it;
00259     for (it = icons.begin(); it != icons.end(); ++it)
00260         mTipText->mimeSourceFactory()->addFilePath(*it);
00261 
00262     if (!isTipDialog)
00263     {
00264     QLabel *l = new QLabel(hbox);
00265     l->setPixmap(img);
00266     l->setBackgroundColor(mBlendedColor);
00267     l->setAlignment(Qt::AlignRight | Qt::AlignBottom);
00268 
00269     resize(550, 230);
00270         QSize sh = size();
00271 
00272         QRect rect = KGlobalSettings::splashScreenDesktopGeometry();
00273 
00274         move(rect.x() + (rect.width() - sh.width())/2,
00275     rect.y() + (rect.height() - sh.height())/2);
00276     }
00277 
00278     KSeparator* sep = new KSeparator( KSeparator::HLine, this);
00279     vbox->addWidget(sep);
00280 
00281     QHBoxLayout *hbox2 = new QHBoxLayout(vbox, 4);
00282 
00283     mTipOnStart = new QCheckBox(i18n("&Show tips on startup"), this);
00284     hbox2->addWidget(mTipOnStart, 1);
00285 
00286     KPushButton *prev = new KPushButton( KStdGuiItem::back(
00287             KStdGuiItem::UseRTL ), this );
00288     prev->setText( i18n("&Previous") );
00289     hbox2->addWidget(prev);
00290 
00291     KPushButton *next = new KPushButton( KStdGuiItem::forward(
00292             KStdGuiItem::UseRTL ), this );
00293     next->setText( i18n("Opposite to Previous","&Next") );
00294     hbox2->addWidget(next);
00295 
00296     KPushButton *ok = new KPushButton(KStdGuiItem::close(), this);
00297     ok->setDefault(true);
00298     hbox2->addWidget(ok);
00299 
00300     KConfigGroup config(kapp->config(), "TipOfDay");
00301     mTipOnStart->setChecked(config.readBoolEntry("RunOnStart", true));
00302 
00303     connect(next, SIGNAL(clicked()), this, SLOT(nextTip()));
00304     connect(prev, SIGNAL(clicked()), this, SLOT(prevTip()));
00305     connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
00306     connect(mTipOnStart, SIGNAL(toggled(bool)), this, SLOT(showOnStart(bool)));
00307 
00308     ok->setFocus();
00309 
00310     nextTip();
00311 }
00312 
00313 KTipDialog::~KTipDialog()
00314 {
00315     if( mInstance==this )
00316         mInstance = 0L;
00317 }
00318 
00319 void KTipDialog::showTip(const QString &tipFile, bool force)
00320 {
00321     showTip(kapp->mainWidget(), tipFile, force);
00322 }
00323 
00324 void KTipDialog::showTip(QWidget *parent, const QString &tipFile, bool force)
00325 {
00326   showMultiTip( parent, QStringList(tipFile), force );
00327 }
00328 
00329 void KTipDialog::showMultiTip(QWidget *parent, const QStringList &tipFiles, bool force)
00330 {
00331     KConfigGroup configGroup(kapp->config(), "TipOfDay");
00332 
00333     const bool runOnStart = configGroup.readBoolEntry("RunOnStart", true);
00334 
00335     if (!force)
00336     {
00337         if (!runOnStart)
00338         return;
00339 
00340         bool hasLastShown = configGroup.hasKey("TipLastShown");
00341         if (hasLastShown)
00342         {
00343            const int oneDay = 24*60*60;
00344            QDateTime lastShown = configGroup.readDateTimeEntry("TipLastShown");
00345            // Show tip roughly once a week
00346            if (lastShown.secsTo(QDateTime::currentDateTime()) < (oneDay + (kapp->random() % (10*oneDay))))
00347                return;
00348         }
00349         configGroup.writeEntry("TipLastShown", QDateTime::currentDateTime());
00350         kapp->config()->sync();
00351         if (!hasLastShown)
00352            return; // Don't show tip on first start
00353     }
00354 
00355     if (!mInstance)
00356     mInstance = new KTipDialog(new KTipDatabase(tipFiles), parent);
00357     else
00358     // The application might have changed the RunOnStart option in its own
00359     // configuration dialog, so we should update the checkbox.
00360       mInstance->mTipOnStart->setChecked(runOnStart);
00361 
00362       mInstance->show();
00363       mInstance->raise();
00364   }
00365 
00366   void KTipDialog::prevTip()
00367   {
00368       mDatabase->prevTip();
00369       mTipText->setText(QString::fromLatin1(
00370      "<qt text=\"%1\" bgcolor=\"%2\">%3</qt>")
00371      .arg(mTextColor.name())
00372      .arg(mBaseColor.name())
00373      .arg(i18n(mDatabase->tip().utf8())));
00374   }
00375 
00376   void KTipDialog::nextTip()
00377   {
00378       mDatabase->nextTip();
00379       mTipText->setText(QString::fromLatin1("<qt text=\"%1\" bgcolor=\"%2\">%3</qt>")
00380         .arg(mTextColor.name())
00381         .arg(mBaseColor.name())
00382         .arg(i18n(mDatabase->tip().utf8())));
00383   }
00384 
00385   void KTipDialog::showOnStart(bool on)
00386   {
00387       setShowOnStart(on);
00388   }
00389 
00390   void KTipDialog::setShowOnStart(bool on)
00391   {
00392       KConfigGroup config(kapp->config(), "TipOfDay");
00393       config.writeEntry("RunOnStart", on);
00394       config.sync();
00395   }
00396 
00397   bool KTipDialog::eventFilter(QObject *o, QEvent *e)
00398   {
00399     if (o == mTipText && e->type()== QEvent::KeyPress &&
00400         (((QKeyEvent *)e)->key() == Key_Return ||
00401         ((QKeyEvent *)e)->key() == Key_Space ))
00402         accept();
00403 
00404     // If the user presses Return or Space, we close the dialog as if the
00405     // default button was pressed even if the KTextBrowser has the keyboard
00406     // focus. This could have the bad side-effect that the user cannot use the
00407     // keyboard to open urls in the KTextBrowser, so we just let it handle
00408     // the key event _additionally_. (Antonio)
00409 
00410     return QWidget::eventFilter( o, e );
00411 }
00412 
00413 void KTipDialog::virtual_hook( int id, void* data )
00414 {
00415     KDialog::virtual_hook( id, data );
00416 }
00417 
00418 #include "ktip.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Aug 2 12:23:23 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003