diff options
Diffstat (limited to 'tdeui/ktip.cpp')
-rw-r--r-- | tdeui/ktip.cpp | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/tdeui/ktip.cpp b/tdeui/ktip.cpp new file mode 100644 index 000000000..8ccd23945 --- /dev/null +++ b/tdeui/ktip.cpp @@ -0,0 +1,447 @@ +/***************************************************************** + +Copyright (c) 2000-2003 Matthias Hoelzer-Kluepfel <mhk@kde.org> + Tobias Koenig <tokoe@kde.org> + Daniel Molkentin <molkentin@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <tqcheckbox.h> +#include <tqfile.h> +#include <tqhbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqregexp.h> +#include <tqtextstream.h> +#include <tqimage.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kpushbutton.h> +#include <kseparator.h> +#include <kstandarddirs.h> +#include <kstdguiitem.h> +#include <ktextbrowser.h> +#include <kiconeffect.h> +#include <kglobalsettings.h> + +#ifdef Q_WS_X11 +#include <kwin.h> +#endif + +#include "ktip.h" + + +KTipDatabase::KTipDatabase(const TQString &_tipFile) +{ + TQString tipFile = _tipFile; + if (tipFile.isEmpty()) + tipFile = TQString::tqfromLatin1(KGlobal::instance()->aboutData()->appName()) + "/tips"; + + loadTips(tipFile); + + if (!mTips.isEmpty()) + mCurrent = kapp->random() % mTips.count(); +} + + +KTipDatabase::KTipDatabase( const TQStringList& tipsFiles ) +{ + if ( tipsFiles.isEmpty() || ( ( tipsFiles.count() == 1 ) && tipsFiles.first().isEmpty() ) ) + { + addTips(TQString::tqfromLatin1(KGlobal::instance()->aboutData()->appName()) + "/tips"); + } + else + { + for (TQStringList::ConstIterator it = tipsFiles.begin(); it != tipsFiles.end(); ++it) + addTips( *it ); + } + if (!mTips.isEmpty()) + mCurrent = kapp->random() % mTips.count(); + +} + +void KTipDatabase::loadTips(const TQString &tipFile) +{ + mTips.clear(); + addTips(tipFile); +} + +// if you change something here, please update the script +// preparetips, which depends on extracting exactly the same +// text as done here. +void KTipDatabase::addTips(const TQString& tipFile ) +{ + TQString fileName = locate("data", tipFile); + + if (fileName.isEmpty()) + { + kdDebug() << "KTipDatabase::addTips: can't find '" << tipFile << "' in standard dirs" << endl; + return; + } + + TQFile file(fileName); + if (!file.open(IO_ReadOnly)) + { + kdDebug() << "KTipDatabase::addTips: can't open '" << fileName << "' for reading" << endl; + return; + } + + TQByteArray data = file.readAll(); + TQString content = TQString::fromUtf8(data.data(), data.size()); + const TQRegExp rx("\\n+"); + + int pos = -1; + while ((pos = content.find("<html>", pos + 1, false)) != -1) + { + // to make translations work, tip extraction here must exactly + // match what is done by the preparetips script + TQString tip = content + .mid(pos + 6, content.find("</html>", pos, false) - pos - 6) + .replace(rx, "\n"); + if (!tip.endsWith("\n")) + tip += "\n"; + if (tip.startsWith("\n")) + tip = tip.mid(1); + if (tip.isEmpty()) + { + kdDebug() << "Empty tip found! Skipping! " << pos << endl; + continue; + } + mTips.append(tip); + } + + file.close(); + +} + +void KTipDatabase::nextTip() +{ + if (mTips.isEmpty()) + return ; + mCurrent += 1; + if (mCurrent >= (int) mTips.count()) + mCurrent = 0; +} + + +void KTipDatabase::prevTip() +{ + if (mTips.isEmpty()) + return ; + mCurrent -= 1; + if (mCurrent < 0) + mCurrent = mTips.count() - 1; +} + + +TQString KTipDatabase::tip() const +{ + if (mTips.isEmpty()) + return TQString::null; + return mTips[mCurrent]; +} + +KTipDialog *KTipDialog::mInstance = 0; + + +KTipDialog::KTipDialog(KTipDatabase *db, TQWidget *parent, const char *name) + : KDialog(parent, name) +{ + /** + * Parent is 0L when TipDialog is used as a mainWidget. This should + * be the case only in ktip, so let's use the ktip layout. + */ + bool isTipDialog = (parent); + + TQImage img; + int h,s,v; + + mBlendedColor = KGlobalSettings::activeTitleColor(); + mBlendedColor.hsv(&h,&s,&v); + mBlendedColor.setHsv(h, int(s*(71/76.0)), int(v*(67/93.0))); + + if (!isTipDialog) + { + img = TQImage(locate("data", "kdewizard/pics/wizard_small.png")); + // colorize and check to figure the correct color + KIconEffect::colorize(img, mBlendedColor, 1.0); + QRgb colPixel( img.pixel(0,0) ); + + mBlendedColor = TQColor(tqRed(colPixel),tqGreen(colPixel),tqBlue(colPixel)); + } + + mBaseColor = KGlobalSettings::alternateBackgroundColor(); + mBaseColor.hsv(&h,&s,&v); + mBaseColor.setHsv(h, int(s*(10/6.0)), int(v*(93/99.0))); + + mTextColor = KGlobalSettings::textColor(); + + + mDatabase = db; + + setCaption(i18n("Tip of the Day")); +#ifdef Q_WS_X11 + KWin::setIcons( winId(), + KGlobal::iconLoader()->loadIcon( "idea", KIcon::NoGroup, 32 ), + KGlobal::iconLoader()->loadIcon( "idea", KIcon::NoGroup, 16 ) ); +#endif + TQVBoxLayout *vbox = new TQVBoxLayout(this, marginHint(), spacingHint()); + + if (isTipDialog) + { + TQHBoxLayout *pl = new TQHBoxLayout(vbox, 0, 0); + + TQLabel *bulb = new TQLabel(this); + bulb->setPixmap(locate("data", "tdeui/pics/ktip-bulb.png")); + pl->addWidget(bulb); + + TQLabel *titlePane = new TQLabel(this); + titlePane->setBackgroundPixmap(locate("data", "tdeui/pics/ktip-background.png")); + titlePane->setText(i18n("Did you know...?\n")); + titlePane->setFont(TQFont(KGlobalSettings::generalFont().family(), 20, TQFont::Bold)); + titlePane->tqsetAlignment(TQLabel::AlignCenter); + pl->addWidget(titlePane, 100); + } + + TQHBox *hbox = new TQHBox(this); + hbox->setSpacing(0); + hbox->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); + vbox->addWidget(hbox); + + TQHBox *tl = new TQHBox(hbox); + tl->setMargin(7); + tl->setBackgroundColor(mBlendedColor); + + TQHBox *topLeft = new TQHBox(tl); + topLeft->setMargin(15); + topLeft->setBackgroundColor(mBaseColor); + + mTipText = new KTextBrowser(topLeft); + + mTipText->setWrapPolicy( TQTextEdit::AtWordOrDocumentBoundary ); + mTipText->mimeSourceFactory()->addFilePath( + KGlobal::dirs()->findResourceDir("data", "kdewizard/pics")+"kdewizard/pics/"); + mTipText->setFrameStyle(TQFrame::NoFrame | TQFrame::Plain); + mTipText->setHScrollBarMode(TQScrollView::AlwaysOff); + mTipText->setLinkUnderline(false); + + TQStyleSheet *sheet = mTipText->styleSheet(); + TQStyleSheetItem *item = sheet->item("a"); + item->setFontWeight(TQFont::Bold); + mTipText->setStyleSheet(sheet); + TQPalette pal = mTipText->palette(); + pal.setColor( TQPalette::Active, TQColorGroup::Link, mBlendedColor ); + pal.setColor( TQPalette::Inactive, TQColorGroup::Link, mBlendedColor ); + mTipText->setPalette(pal); + + TQStringList icons = KGlobal::dirs()->resourceDirs("icon"); + TQStringList::Iterator it; + for (it = icons.begin(); it != icons.end(); ++it) + mTipText->mimeSourceFactory()->addFilePath(*it); + + if (!isTipDialog) + { + TQLabel *l = new TQLabel(hbox); + l->setPixmap(img); + l->setBackgroundColor(mBlendedColor); + l->tqsetAlignment(Qt::AlignRight | Qt::AlignBottom); + + resize(550, 230); + TQSize sh = size(); + + TQRect rect = KGlobalSettings::splashScreenDesktopGeometry(); + + move(rect.x() + (rect.width() - sh.width())/2, + rect.y() + (rect.height() - sh.height())/2); + } + + KSeparator* sep = new KSeparator( KSeparator::HLine, this); + vbox->addWidget(sep); + + TQHBoxLayout *hbox2 = new TQHBoxLayout(vbox, 4); + + mTipOnStart = new TQCheckBox(i18n("&Show tips on startup"), this); + hbox2->addWidget(mTipOnStart, 1); + + KPushButton *prev = new KPushButton( KStdGuiItem::back( + KStdGuiItem::UseRTL ), this ); + prev->setText( i18n("&Previous") ); + hbox2->addWidget(prev); + + KPushButton *next = new KPushButton( KStdGuiItem::forward( + KStdGuiItem::UseRTL ), this ); + next->setText( i18n("Opposite to Previous","&Next") ); + hbox2->addWidget(next); + + KPushButton *ok = new KPushButton(KStdGuiItem::close(), this); + ok->setDefault(true); + hbox2->addWidget(ok); + + KConfigGroup config(kapp->config(), "TipOfDay"); + mTipOnStart->setChecked(config.readBoolEntry("RunOnStart", true)); + + connect(next, TQT_SIGNAL(clicked()), this, TQT_SLOT(nextTip())); + connect(prev, TQT_SIGNAL(clicked()), this, TQT_SLOT(prevTip())); + connect(ok, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept())); + connect(mTipOnStart, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(showOnStart(bool))); + + ok->setFocus(); + + nextTip(); +} + +KTipDialog::~KTipDialog() +{ + if( mInstance==this ) + mInstance = 0L; +} + +void KTipDialog::showTip(const TQString &tipFile, bool force) +{ + showTip(kapp->mainWidget(), tipFile, force); +} + +void KTipDialog::showTip(TQWidget *parent, const TQString &tipFile, bool force) +{ + showMultiTip( parent, TQStringList(tipFile), force ); +} + +void KTipDialog::showMultiTip(TQWidget *parent, const TQStringList &tipFiles, bool force) +{ + KConfigGroup configGroup(kapp->config(), "TipOfDay"); + + const bool runOnStart = configGroup.readBoolEntry("RunOnStart", true); + + if (!force) + { + if (!runOnStart) + return; + + bool hasLastShown = configGroup.hasKey("TipLastShown"); + if (hasLastShown) + { + const int oneDay = 24*60*60; + TQDateTime lastShown = configGroup.readDateTimeEntry("TipLastShown"); + // Show tip roughly once a week + if (lastShown.secsTo(TQDateTime::tqcurrentDateTime()) < (oneDay + (kapp->random() % (10*oneDay)))) + return; + } + configGroup.writeEntry("TipLastShown", TQDateTime::tqcurrentDateTime()); + kapp->config()->sync(); + if (!hasLastShown) + return; // Don't show tip on first start + } + + if (!mInstance) + mInstance = new KTipDialog(new KTipDatabase(tipFiles), parent); + else + // The application might have changed the RunOnStart option in its own + // configuration dialog, so we should update the checkbox. + mInstance->mTipOnStart->setChecked(runOnStart); + + mInstance->show(); + mInstance->raise(); + } + +static TQString fixTip(TQString tip) +{ + TQRegExp iconRegExp("<img src=\"(.*)\">"); + iconRegExp.setMinimal(true); + if (iconRegExp.search(tip)>-1) { + TQString iconName = iconRegExp.cap(1); + if (!iconName.isEmpty()) + if (KGlobal::dirs()->findResource("icon", iconName).isEmpty()) + tip.replace("crystalsvg","hicolor"); + } + + return tip; +} + + void KTipDialog::prevTip() + { + mDatabase->prevTip(); + TQString currentTip = TQString::tqfromLatin1( + "<qt text=\"%1\" bgcolor=\"%2\">%3</qt>") + .arg(mTextColor.name()) + .arg(mBaseColor.name()) + .arg(i18n(mDatabase->tip().utf8())); + + + currentTip = fixTip(currentTip); + mTipText->setText(currentTip); + mTipText->setContentsPos(0, 0); + } + + void KTipDialog::nextTip() + { + mDatabase->nextTip(); + TQString currentTip = TQString::tqfromLatin1( + "<qt text=\"%1\" bgcolor=\"%2\">%3</qt>") + .arg(mTextColor.name()) + .arg(mBaseColor.name()) + .arg(i18n(mDatabase->tip().utf8())); + + + currentTip = fixTip(currentTip); + mTipText->setText(currentTip); + mTipText->setContentsPos(0, 0); + } + + void KTipDialog::showOnStart(bool on) + { + setShowOnStart(on); + } + + void KTipDialog::setShowOnStart(bool on) + { + KConfigGroup config(kapp->config(), "TipOfDay"); + config.writeEntry("RunOnStart", on); + config.sync(); + } + + bool KTipDialog::eventFilter(TQObject *o, TQEvent *e) + { + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(mTipText) && e->type()== TQEvent::KeyPress && + (((TQKeyEvent *)e)->key() == Key_Return || + ((TQKeyEvent *)e)->key() == Key_Space )) + accept(); + + // If the user presses Return or Space, we close the dialog as if the + // default button was pressed even if the KTextBrowser has the keyboard + // focus. This could have the bad side-effect that the user cannot use the + // keyboard to open urls in the KTextBrowser, so we just let it handle + // the key event _additionally_. (Antonio) + + return TQWidget::eventFilter( o, e ); +} + +void KTipDialog::virtual_hook( int id, void* data ) +{ + KDialog::virtual_hook( id, data ); +} + +#include "ktip.moc" |