/* * knewsticker.cpp * * Copyright (c) 2000, 2001 Frerich Raabe * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the * accompanying file 'COPYING'. */ #include "knewsticker.h" #include "newsengine.h" #include "newsscroller.h" #include "configaccess.h" #include "newsiconmgr.h" #include "knewstickerconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KNewsTicker::KNewsTicker(const TQString &cfgFile, Type t, int actions, TQWidget *parent, const char *name) : ConfigIface(), DCOPObject("KNewsTicker"), KPanelApplet(cfgFile, t, actions, parent, name), m_instance(new TDEInstance("knewsticker")), m_dcopClient(new DCOPClient()), m_cfg(new ConfigAccess(config())), m_newsTimer(new TQTimer(this)), m_updateTimer(new TQTimer(this)), m_newsIconMgr(NewsIconMgr::self()), m_aboutData(new TDEAboutData("knewsticker", I18N_NOOP("KNewsTicker"), "v0.2", I18N_NOOP("A news ticker applet."), TDEAboutData::License_BSD, I18N_NOOP("(c) 2000, 2001 The KNewsTicker developers"))) { TQHBoxLayout *layout = new TQHBoxLayout(this); m_contextMenu = new KNewsTickerMenu(this); connect(m_contextMenu, TQ_SIGNAL(aboutToHide()), TQ_SLOT(slotContextMenuAboutToHide())); setCustomMenu(m_contextMenu); m_arrowButton = new KArrowButton(this); TQToolTip::add(m_arrowButton, i18n("Show menu")); connect(m_arrowButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotArrowButtonPressed())); m_arrowButton->setFocusPolicy(TQWidget::NoFocus); setupArrowButton(); layout->addWidget(m_arrowButton); m_scroller = new NewsScroller(this, m_cfg); layout->addWidget(m_scroller); m_dcopClient->registerAs("knewsticker", false); TQToolTip::add(m_scroller, TQString()); connect(m_scroller, TQ_SIGNAL(contextMenu()), TQ_SLOT(slotOpenContextMenu())); connect(m_newsTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotUpdateNews())); connect(m_updateTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotNotifyOfFailures())); m_aboutData->addAuthor("Frerich Raabe", I18N_NOOP("Original author"), "raabe@kde.org"); m_aboutData->addAuthor("Malte Starostik", I18N_NOOP("Hypertext headlines" " and much more"), "malte@kde.org"); m_aboutData->addAuthor("Wilco Greven", I18N_NOOP("Mouse wheel support"), "greven@kde.org"); m_aboutData->addAuthor("Adriaan de Groot", I18N_NOOP("Rotated scrolling text" " modes"), "adridg@sci.kun.nl"); reparseConfig(); TDEStartupInfo::appStarted(); } KNewsTicker::~KNewsTicker() { delete m_cfg; delete m_dcopClient; } int KNewsTicker::heightForWidth(int) const { return m_scroller->sizeHint().height() + m_arrowButton->height(); } int KNewsTicker::widthForHeight(int) const { return m_scroller->sizeHint().width() + m_arrowButton->width(); } void KNewsTicker::preferences() { KNewsTickerConfig dlg(m_cfg, this); if (dlg.exec() == TQDialog::Accepted) { reparseConfig(); } } void KNewsTicker::about() { TDEAboutApplication aboutDlg(m_aboutData); aboutDlg.exec(); } void KNewsTicker::help() { kapp->invokeHelp(TQString(), TQString::fromLatin1("knewsticker")); } void KNewsTicker::reportBug() { KBugReport bugReport(this, true, m_aboutData); bugReport.exec(); } void KNewsTicker::reparseConfig() { m_cfg->reparseConfiguration(); m_newsSources.clear(); TQStringList newsSources = m_cfg->newsSources(); TQStringList::ConstIterator it = newsSources.begin(); TQStringList::ConstIterator end = newsSources.end(); for (; it != end; ++it) { NewsSourceBase::Ptr ns = m_cfg->newsSource((*it)); if (!ns->data().enabled) continue; connect(ns, TQ_SIGNAL(newNewsAvailable(const NewsSourceBase::Ptr &, bool)), TQ_SLOT(slotNewsSourceUpdated(const NewsSourceBase::Ptr &, bool))); connect(ns, TQ_SIGNAL(invalidInput(const NewsSourceBase::Ptr &)), TQ_SLOT(slotNewsSourceFailed(const NewsSourceBase::Ptr &))); m_newsSources.append(ns); } setOfflineMode(m_cfg->offlineMode()); if (!m_cfg->offlineMode()) slotUpdateNews(); } void KNewsTicker::slotUpdateNews() { kdDebug(5005) << "slotUpdateNews()" << endl; m_newNews = false; m_updateTimer->start(KProtocolManager::responseTimeout(), true); m_failedNewsUpdates.clear(); m_pendingNewsUpdates.clear(); m_scroller->clear(); NewsSourceBase::List::Iterator it = m_newsSources.begin(); NewsSourceBase::List::Iterator end = m_newsSources.end(); for (; it != end; ++it) { m_pendingNewsUpdates += (*it)->data().name; (*it)->retrieveNews(); (*it)->getIcon(); } kdDebug(5005) << "m_pendingNewsUpdates = " << m_pendingNewsUpdates.join(",") << endl; } void KNewsTicker::slotNewsSourceUpdated(const NewsSourceBase::Ptr &ns, bool newNews) { kdDebug(5005) << "slotNewsSourceUpdate()" << endl; if (newNews) m_newNews = true; if (!ns->articles().isEmpty()) if (m_cfg->scrollMostRecentOnly()) m_scroller->addHeadline(ns->articles().first()); else { Article::List articles = ns->articles(); Article::List::ConstIterator artIt = articles.begin(); Article::List::ConstIterator artEnd = articles.end(); for (; artIt != artEnd; ++artIt) m_scroller->addHeadline(*artIt); } m_scroller->reset(true); m_pendingNewsUpdates.remove(ns->data().name); kdDebug(5005) << "Updated news source: '" << ns->data().name << "'" << "\n" << "m_pendingNewsUpdates = " << m_pendingNewsUpdates.join(",") << "\n" << "m_failedNewsUpdates = " << m_failedNewsUpdates.join(",") << endl; if (!m_pendingNewsUpdates.isEmpty()) return; m_updateTimer->stop(); if (!m_failedNewsUpdates.isEmpty()) slotNotifyOfFailures(); if (m_newNews) { KNotifyClient::Instance instance(m_instance); KNotifyClient::event(winId(), TQString::fromLatin1("NewNews")); } } void KNewsTicker::slotNewsSourceFailed(const NewsSourceBase::Ptr &ns) { m_failedNewsUpdates += ns->newsSourceName(); slotNewsSourceUpdated(ns); } void KNewsTicker::mousePressEvent(TQMouseEvent *e) { if (e->button() == TQt::RightButton) slotOpenContextMenu(); } void KNewsTicker::slotOpenContextMenu() { m_contextMenu->setFullMenu(true); m_contextMenu->exec(TQCursor::pos()); } void KNewsTicker::slotArrowButtonPressed() { TQPoint pos(m_arrowButton->mapToGlobal(TQPoint(0, 0))); TQSize size(m_arrowButton->size()); if (position() == KPanelApplet::pTop) { pos.setY(pos.y() + size.height() + 2); } else if (position() == KPanelApplet::pBottom) { const int y = pos.y() - m_contextMenu->sizeHint().height() - 2; pos.setY(TQMAX(0, y)); } else if (position() == KPanelApplet::pLeft ) { pos.setX(pos.x() + size.width() + 2); } else { // position() == KPanelApplet::pRight const int x = pos.x() - m_contextMenu->sizeHint().width() - 2; pos.setX(TQMAX(0, x)); } m_contextMenu->setFullMenu(true); m_contextMenu->exec(pos); } void KNewsTicker::positionChange(Position) { delete layout(); TQBoxLayout *layout; if (orientation() ==TQt::Horizontal) layout = new TQHBoxLayout(this); else layout = new TQVBoxLayout(this); if (m_arrowButton) { layout->addWidget(m_arrowButton); setupArrowButton(); } layout->addWidget(m_scroller); } void KNewsTicker::slotContextMenuAboutToHide() { if (m_arrowButton) m_arrowButton->setDown(false); } void KNewsTicker::slotNotifyOfFailures() { KNotifyClient::Instance instance(m_instance); TQString notification = TQString(); if (m_failedNewsUpdates.count() == 1) notification = i18n("Could not update news site '%1'.
" "The supplied resource file is probably invalid or" " broken.
").arg(m_failedNewsUpdates.first()); else if (m_failedNewsUpdates.count() > 1 && m_failedNewsUpdates.count() < 8) { notification = i18n("The following news sites had problems. Their" " resource files are probably invalid or broken.
    "); TQStringList::ConstIterator it = m_failedNewsUpdates.begin(); TQStringList::ConstIterator end = m_failedNewsUpdates.end(); for (; it != end; ++it) notification += TQString::fromLatin1("
  • %1
  • ").arg(*it); notification += TQString::fromLatin1("
"); } else notification = i18n("Failed to update several news" " sites. The Internet connection might be cut."); KNotifyClient::event(winId(), TQString::fromLatin1("InvalidRDF"), notification); } void KNewsTicker::setInterval(const uint interval) { m_cfg->setInterval(interval); if ( interval > 4 ) m_newsTimer->changeInterval(interval * 60 * 1000); } void KNewsTicker::setScrollingSpeed(const uint scrollingSpeed) { m_cfg->setScrollingSpeed(scrollingSpeed); m_scroller->reset(true); } void KNewsTicker::setMouseWheelSpeed(const uint mouseWheelSpeed) { m_cfg->setMouseWheelSpeed(mouseWheelSpeed); } void KNewsTicker::setScrollingDirection(const uint scrollingDirection) { m_cfg->setScrollingDirection(scrollingDirection); m_scroller->reset(true); } void KNewsTicker::setCustomNames(bool customNames) { m_cfg->setCustomNames(customNames); } void KNewsTicker::setScrollMostRecentOnly(bool scrollMostRecentOnly) { m_cfg->setScrollMostRecentOnly(scrollMostRecentOnly); m_scroller->reset(true); } void KNewsTicker::setOfflineMode(bool offlineMode) { if (offlineMode) m_newsTimer->stop(); else if ( m_cfg->interval() > 4 ) m_newsTimer->start(m_cfg->interval() * 1000 * 60); m_cfg->setOfflineMode(offlineMode); } void KNewsTicker::setUnderlineHighlighted(bool underlineHighlighted) { m_cfg->setUnderlineHighlighted(underlineHighlighted); m_scroller->reset(true); } void KNewsTicker::setShowIcons(bool showIcons) { m_cfg->setShowIcons(showIcons); m_scroller->reset(true); } void KNewsTicker::setSlowedScrolling(bool slowedScrolling) { m_cfg->setSlowedScrolling(slowedScrolling); } void KNewsTicker::setForegroundColor(const TQColor &foregroundColor) { m_cfg->setForegroundColor(foregroundColor); m_scroller->reset(false); } void KNewsTicker::setBackgroundColor(const TQColor &backgroundColor) { m_cfg->setBackgroundColor(backgroundColor); m_scroller->reset(false); } void KNewsTicker::setHighlightedColor(const TQColor &highlightedColor) { m_cfg->setHighlightedColor(highlightedColor); m_scroller->reset(false); } void KNewsTicker::setupArrowButton() { TQt::ArrowType at; if (orientation() ==TQt::Horizontal) { m_arrowButton->setFixedWidth(12); m_arrowButton->setMaximumHeight(128); at = (position() == KPanelApplet::pTop ? TQt::DownArrow : TQt::UpArrow); } else { m_arrowButton->setMaximumWidth(128); m_arrowButton->setFixedHeight(12); at = (position() == KPanelApplet::pLeft ? TQt::RightArrow : TQt::LeftArrow); } m_arrowButton->setArrowType(at); } KNewsTickerMenu::KNewsTickerMenu(KNewsTicker *parent, const char *name) : TDEPopupMenu(parent, name), m_parent(parent), m_fullMenu(false) { populateMenu(); } void KNewsTickerMenu::populateMenu() { clear(); /* * Perhaps this hardcoded stuff should be replaced by some kind of * themeing functionality? */ const TQPixmap lookIcon = SmallIcon(TQString::fromLatin1("viewmag")); const TQPixmap newArticleIcon = SmallIcon(TQString::fromLatin1("application-vnd.tde.info")); const TQPixmap oldArticleIcon = SmallIcon(TQString::fromLatin1("mime_empty")); const TQPixmap noArticlesIcon = SmallIcon(TQString::fromLatin1("remove")); unsigned int articleIdx = 0; const NewsSourceBase::List sources = m_parent->m_newsSources; NewsSourceBase::List::ConstIterator nIt = sources.begin(); for (; nIt != sources.end(); ++nIt) { NewsSourceBase::Ptr ns = *nIt; TDEPopupMenu *submenu = new TDEPopupMenu; int checkNewsId = submenu->insertItem(lookIcon, i18n("Check News"), this, TQ_SLOT(slotCheckNews(int)), 0, sources.findIndex(ns) + 1000); setItemParameter(checkNewsId, sources.findIndex(ns)); submenu->insertSeparator(); if (m_parent->m_pendingNewsUpdates.contains(ns->newsSourceName())) { submenu->insertItem(noArticlesIcon, i18n("Currently Being Updated, No Articles Available")); } else if (!ns->articles().isEmpty()) { const Article::List articles = ns->articles(); Article::List::ConstIterator artIt = articles.begin(); for (; artIt != articles.end(); ++artIt) { Article::Ptr a = *artIt; TQString headline = a->headline().replace('&', "&&"); int id; if ( a->read() ) id = submenu->insertItem(oldArticleIcon, headline, this, TQ_SLOT(slotOpenArticle(int)), 0, articleIdx+2000); else id = submenu->insertItem(newArticleIcon, headline, this, TQ_SLOT(slotOpenArticle(int)), 0, articleIdx+2000); kdDebug( 5005 ) << "Setting articles index for " << a->headline() << " to " << articleIdx << endl; setItemParameter( id, articleIdx++ ); } } else { submenu->insertItem(noArticlesIcon, i18n("No Articles Available")); } insertItem(ns->icon(), ns->newsSourceName().replace('&', "&&"), submenu); } if (!m_parent->m_cfg->newsSources().isEmpty()) insertSeparator(); insertItem(lookIcon, i18n("Check News"), m_parent, TQ_SLOT(slotUpdateNews())); int i = insertItem(i18n("Offline Mode"), this, TQ_SLOT(slotToggleOfflineMode()), 0, 4711 ); setItemChecked(i, m_parent->m_cfg->offlineMode()); if (m_fullMenu) { insertSeparator(); const TQPixmap logoIcon = SmallIcon(TQString::fromLatin1("knewsticker")); const TQPixmap helpIcon = SmallIcon(TQString::fromLatin1("help")); const TQPixmap confIcon = SmallIcon(TQString::fromLatin1("configure")); insertTitle(logoIcon, i18n("KNewsTicker"), 0, 0); insertItem(helpIcon, i18n("Help"), this, TQ_SLOT(slotShowHelp())); insertItem(logoIcon, i18n("About KNewsTicker"), this, TQ_SLOT(slotShowAbout())); insertSeparator(); insertItem(confIcon, i18n("Configure KNewsTicker..."), this, TQ_SLOT(slotConfigure())); } } void KNewsTickerMenu::slotShowHelp() { m_parent->help(); } void KNewsTickerMenu::slotShowAbout() { m_parent->about(); } void KNewsTickerMenu::slotConfigure() { m_parent->preferences(); } void KNewsTickerMenu::slotToggleOfflineMode() { m_parent->setOfflineMode(!m_parent->m_cfg->offlineMode()); setItemChecked( indexOf( 4711 ), !m_parent->m_cfg->offlineMode() ); } void KNewsTickerMenu::slotCheckNews(int idx) { m_parent->m_newsSources[ idx - 1000 ]->retrieveNews(); } void KNewsTickerMenu::slotOpenArticle(int idx) { unsigned int i = idx - 2000; const NewsSourceBase::List sources = m_parent->m_newsSources; NewsSourceBase::List::ConstIterator it = sources.begin(); while ( it != sources.end() ) { if ( ( *it )->articles().isEmpty() ) { ++it; continue; } if ( i <= ( *it )->articles().count() - 1 ) break; i -= ( *it )->articles().count(); ++it; } if ( it == sources.end() ) return; ( *it )->articles()[ i ]->open(); } extern "C" { TDE_EXPORT KPanelApplet* init(TQWidget *parent, const TQString &configFile) { TDEGlobal::locale()->insertCatalogue(TQString::fromLatin1("knewsticker")); return new KNewsTicker(configFile, KPanelApplet::Stretch, KPanelApplet::Preferences | KPanelApplet::About | KPanelApplet::Help | KPanelApplet::ReportBug, parent, "knewsticker"); } } #include "knewsticker.moc"