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 #include <dcopclient.h>
00026 #include <kaboutdata.h>
00027 #include <kaction.h>
00028 #include <kactionclasses.h>
00029 #include <kactioncollection.h>
00030 #include <kapplication.h>
00031 #include <kconfig.h>
00032 #include <kconfigdialog.h>
00033 #include <kfiledialog.h>
00034 #include <kglobalsettings.h>
00035 #include <khtmldefaults.h>
00036 #include <kinstance.h>
00037 #include <kmainwindow.h>
00038 #include <kmessagebox.h>
00039 #include <knotifyclient.h>
00040 #include <knotifydialog.h>
00041 #include <kpopupmenu.h>
00042 #include <kservice.h>
00043 #include <kstandarddirs.h>
00044 #include <kstdaction.h>
00045 #include <ktempfile.h>
00046 #include <ktrader.h>
00047 #include <kio/netaccess.h>
00048 #include <kparts/browserinterface.h>
00049 #include <kparts/genericfactory.h>
00050 #include <kparts/partmanager.h>
00051
00052 #include <qfile.h>
00053 #include <qobjectlist.h>
00054 #include <qstringlist.h>
00055 #include <qtimer.h>
00056 #include <qwidgetlist.h>
00057 #include <private/qucomextra_p.h>
00058
00059 #include <cerrno>
00060 #include <sys/types.h>
00061 #include <signal.h>
00062 #include <stdio.h>
00063 #include <stdlib.h>
00064 #include <unistd.h>
00065
00066 #include "aboutdata.h"
00067 #include "actionmanagerimpl.h"
00068 #include "akregator_part.h"
00069 #include "akregator_view.h"
00070 #include "akregatorconfig.h"
00071 #include "articlefilter.h"
00072 #include "articleinterceptor.h"
00073 #include "configdialog.h"
00074 #include "fetchqueue.h"
00075 #include "frame.h"
00076 #include "article.h"
00077 #include "kernel.h"
00078 #include "kcursorsaver.h"
00079 #include "notificationmanager.h"
00080 #include "pageviewer.h"
00081 #include "plugin.h"
00082 #include "pluginmanager.h"
00083 #include "storage.h"
00084 #include "storagefactory.h"
00085 #include "storagefactorydummyimpl.h"
00086 #include "storagefactoryregistry.h"
00087 #include "speechclient.h"
00088 #include "trayicon.h"
00089 #include "tagset.h"
00090 #include "tag.h"
00091
00092 namespace Akregator {
00093
00094 typedef KParts::GenericFactory<Part> AkregatorFactory;
00095 K_EXPORT_COMPONENT_FACTORY( libakregatorpart, AkregatorFactory )
00096
00097 BrowserExtension::BrowserExtension(Part *p, const char *name)
00098 : KParts::BrowserExtension( p, name )
00099 {
00100 m_part=p;
00101 }
00102
00103 void BrowserExtension::saveSettings()
00104 {
00105 m_part->saveSettings();
00106 }
00107
00108 class Part::ApplyFiltersInterceptor : public ArticleInterceptor
00109 {
00110 public:
00111 virtual void processArticle(Article& article)
00112 {
00113 Filters::ArticleFilterList list = Kernel::self()->articleFilterList();
00114 for (Filters::ArticleFilterList::ConstIterator it = list.begin(); it != list.end(); ++it)
00115 (*it).applyTo(article);
00116 }
00117 };
00118
00119 Part::Part( QWidget *parentWidget, const char * ,
00120 QObject *parent, const char *name, const QStringList& )
00121 : DCOPObject("AkregatorIface")
00122 , MyBasePart(parent, name)
00123 , m_standardListLoaded(false)
00124 , m_shuttingDown(false)
00125 , m_mergedPart(0)
00126 , m_view(0)
00127 , m_backedUpList(false)
00128 , m_storage(0)
00129 {
00130
00131 setInstance( AkregatorFactory::instance() );
00132
00133
00134 KNotifyClient::startDaemon();
00135
00136 m_standardFeedList = KGlobal::dirs()->saveLocation("data", "akregator/data") + "/feeds.opml";
00137
00138 m_tagSetPath = KGlobal::dirs()->saveLocation("data", "akregator/data") + "/tagset.xml";
00139
00140 Backend::StorageFactoryDummyImpl* dummyFactory = new Backend::StorageFactoryDummyImpl();
00141 Backend::StorageFactoryRegistry::self()->registerFactory(dummyFactory, dummyFactory->key());
00142 loadPlugins();
00143
00144 m_storage = 0;
00145 Backend::StorageFactory* factory = Backend::StorageFactoryRegistry::self()->getFactory(Settings::archiveBackend());
00146
00147 QStringList storageParams;
00148
00149 storageParams.append(QString("taggingEnabled=%1").arg(Settings::showTaggingGUI() ? "true" : "false"));
00150
00151 if (factory != 0)
00152 {
00153 if (factory->allowsMultipleWriteAccess())
00154 {
00155 m_storage = factory->createStorage(storageParams);
00156 }
00157 else
00158 {
00159 if (tryToLock(factory->name()))
00160 m_storage = factory->createStorage(storageParams);
00161 else
00162 m_storage = dummyFactory->createStorage(storageParams);
00163 }
00164 }
00165
00166
00167 if (!m_storage)
00168 {
00169 m_storage = Backend::StorageFactoryRegistry::self()->getFactory("dummy")->createStorage(storageParams);
00170
00171 KMessageBox::error(parentWidget, i18n("Unable to load storage backend plugin \"%1\". No feeds are archived.").arg(Settings::archiveBackend()), i18n("Plugin error") );
00172 }
00173
00174 Filters::ArticleFilterList list;
00175 list.readConfig(Settings::self()->config());
00176 Kernel::self()->setArticleFilterList(list);
00177
00178 m_applyFiltersInterceptor = new ApplyFiltersInterceptor();
00179 ArticleInterceptorManager::self()->addInterceptor(m_applyFiltersInterceptor);
00180
00181 m_storage->open(true);
00182 Kernel::self()->setStorage(m_storage);
00183 Backend::Storage::setInstance(m_storage);
00184
00185 loadTagSet(m_tagSetPath);
00186
00187 m_actionManager = new ActionManagerImpl(this);
00188 ActionManager::setInstance(m_actionManager);
00189
00190 m_view = new Akregator::View(this, parentWidget, m_actionManager, "akregator_view");
00191 m_actionManager->initView(m_view);
00192 m_actionManager->setTagSet(Kernel::self()->tagSet());
00193
00194 m_extension = new BrowserExtension(this, "ak_extension");
00195
00196 connect(m_view, SIGNAL(setWindowCaption(const QString&)), this, SIGNAL(setWindowCaption(const QString&)));
00197 connect(m_view, SIGNAL(setStatusBarText(const QString&)), this, SIGNAL(setStatusBarText(const QString&)));
00198 connect(m_view, SIGNAL(setProgress(int)), m_extension, SIGNAL(loadingProgress(int)));
00199 connect(m_view, SIGNAL(signalCanceled(const QString&)), this, SIGNAL(canceled(const QString&)));
00200 connect(m_view, SIGNAL(signalStarted(KIO::Job*)), this, SIGNAL(started(KIO::Job*)));
00201 connect(m_view, SIGNAL(signalCompleted()), this, SIGNAL(completed()));
00202
00203
00204 setWidget(m_view);
00205
00206 TrayIcon* trayIcon = new TrayIcon( getMainWindow() );
00207 TrayIcon::setInstance(trayIcon);
00208 m_actionManager->initTrayIcon(trayIcon);
00209
00210 connect(trayIcon, SIGNAL(showPart()), this, SIGNAL(showPart()));
00211
00212 if ( isTrayIconEnabled() )
00213 {
00214 trayIcon->show();
00215 NotificationManager::self()->setWidget(trayIcon, instance());
00216 }
00217 else
00218 NotificationManager::self()->setWidget(getMainWindow(), instance());
00219
00220 connect( trayIcon, SIGNAL(quitSelected()),
00221 kapp, SLOT(quit())) ;
00222
00223 connect( m_view, SIGNAL(signalUnreadCountChanged(int)), trayIcon, SLOT(slotSetUnread(int)) );
00224
00225 connect(kapp, SIGNAL(shutDown()), this, SLOT(slotOnShutdown()));
00226
00227 m_autosaveTimer = new QTimer(this);
00228 connect(m_autosaveTimer, SIGNAL(timeout()), this, SLOT(slotSaveFeedList()));
00229 m_autosaveTimer->start(5*60*1000);
00230
00231 setXMLFile("akregator_part.rc", true);
00232
00233 initFonts();
00234
00235 RSS::FileRetriever::setUserAgent(QString("Akregator/%1; librss/remnants").arg(AKREGATOR_VERSION));
00236 }
00237
00238 void Part::loadPlugins()
00239 {
00240
00241 KTrader::OfferList offers = PluginManager::query();
00242
00243 for( KTrader::OfferList::ConstIterator it = offers.begin(), end = offers.end(); it != end; ++it )
00244 {
00245 Akregator::Plugin* plugin = PluginManager::createFromService(*it);
00246 if (plugin)
00247 plugin->init();
00248 }
00249 }
00250
00251 void Part::slotOnShutdown()
00252 {
00253 m_shuttingDown = true;
00254
00255 const QString lockLocation = locateLocal("data", "akregator/lock");
00256 KSimpleConfig config(lockLocation);
00257 config.writeEntry("pid", -1);
00258 config.sync();
00259
00260 m_autosaveTimer->stop();
00261 saveSettings();
00262 slotSaveFeedList();
00263 saveTagSet(m_tagSetPath);
00264 m_view->slotOnShutdown();
00265
00266 delete TrayIcon::getInstance();
00267 TrayIcon::setInstance(0L);
00268 delete m_storage;
00269 m_storage = 0;
00270
00271 }
00272
00273 void Part::slotSettingsChanged()
00274 {
00275 NotificationManager::self()->setWidget(isTrayIconEnabled() ? TrayIcon::getInstance() : getMainWindow(), instance());
00276
00277 RSS::FileRetriever::setUseCache(Settings::useHTMLCache());
00278
00279 QStringList fonts;
00280 fonts.append(Settings::standardFont());
00281 fonts.append(Settings::fixedFont());
00282 fonts.append(Settings::sansSerifFont());
00283 fonts.append(Settings::serifFont());
00284 fonts.append(Settings::standardFont());
00285 fonts.append(Settings::standardFont());
00286 fonts.append("0");
00287 Settings::setFonts(fonts);
00288
00289 if (Settings::minimumFontSize() > Settings::mediumFontSize())
00290 Settings::setMediumFontSize(Settings::minimumFontSize());
00291 saveSettings();
00292 m_view->slotSettingsChanged();
00293 emit signalSettingsChanged();
00294 }
00295 void Part::saveSettings()
00296 {
00297 Kernel::self()->articleFilterList().writeConfig(Settings::self()->config());
00298 m_view->saveSettings();
00299 }
00300
00301 Part::~Part()
00302 {
00303 kdDebug() << "Part::~Part() enter" << endl;
00304 if (!m_shuttingDown)
00305 slotOnShutdown();
00306 kdDebug() << "Part::~Part(): leaving" << endl;
00307 ArticleInterceptorManager::self()->removeInterceptor(m_applyFiltersInterceptor);
00308 delete m_applyFiltersInterceptor;
00309 }
00310
00311 void Part::readProperties(KConfig* config)
00312 {
00313 m_backedUpList = false;
00314 openStandardFeedList();
00315
00316 if(m_view)
00317 m_view->readProperties(config);
00318 }
00319
00320 void Part::saveProperties(KConfig* config)
00321 {
00322 if (m_view)
00323 {
00324 slotSaveFeedList();
00325 m_view->saveProperties(config);
00326 }
00327 }
00328
00329 bool Part::openURL(const KURL& url)
00330 {
00331 m_file = url.path();
00332 return openFile();
00333 }
00334
00335 void Part::openStandardFeedList()
00336 {
00337 if ( !m_standardFeedList.isEmpty() && openURL(m_standardFeedList) )
00338 m_standardListLoaded = true;
00339 }
00340
00341 QDomDocument Part::createDefaultFeedList()
00342 {
00343 QDomDocument doc;
00344 QDomProcessingInstruction z = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
00345 doc.appendChild( z );
00346
00347 QDomElement root = doc.createElement( "opml" );
00348 root.setAttribute("version","1.0");
00349 doc.appendChild( root );
00350
00351 QDomElement head = doc.createElement( "head" );
00352 root.appendChild(head);
00353
00354 QDomElement text = doc.createElement( "text" );
00355 text.appendChild(doc.createTextNode(i18n("Feeds")));
00356 head.appendChild(text);
00357
00358 QDomElement body = doc.createElement( "body" );
00359 root.appendChild(body);
00360
00361 QDomElement mainFolder = doc.createElement( "outline" );
00362 mainFolder.setAttribute("text","KDE");
00363 body.appendChild(mainFolder);
00364
00365 QDomElement ak = doc.createElement( "outline" );
00366 ak.setAttribute("text",i18n("Akregator News"));
00367 ak.setAttribute("xmlUrl","http://akregator.sf.net/rss2.php");
00368 mainFolder.appendChild(ak);
00369
00370 QDomElement akb = doc.createElement( "outline" );
00371 akb.setAttribute("text",i18n("Akregator Blog"));
00372 akb.setAttribute("xmlUrl","http://akregator.pwsp.net/blog/?feed=rss2");
00373 mainFolder.appendChild(akb);
00374
00375 QDomElement dot = doc.createElement( "outline" );
00376 dot.setAttribute("text",i18n("KDE Dot News"));
00377 dot.setAttribute("xmlUrl","http://www.kde.org/dotkdeorg.rdf");
00378 mainFolder.appendChild(dot);
00379
00380 QDomElement plan = doc.createElement( "outline" );
00381 plan.setAttribute("text",i18n("Planet KDE"));
00382 plan.setAttribute("xmlUrl","http://planetkde.org/rss20.xml");
00383 mainFolder.appendChild(plan);
00384
00385 QDomElement apps = doc.createElement( "outline" );
00386 apps.setAttribute("text",i18n("KDE Apps"));
00387 apps.setAttribute("xmlUrl","http://www.kde.org/dot/kde-apps-content.rdf");
00388 mainFolder.appendChild(apps);
00389
00390 QDomElement look = doc.createElement( "outline" );
00391 look.setAttribute("text",i18n("KDE Look"));
00392 look.setAttribute("xmlUrl","http://www.kde.org/kde-look-content.rdf");
00393 mainFolder.appendChild(look);
00394
00395 QDomElement debianFolder = doc.createElement( "outline" );
00396 debianFolder.setAttribute("text","Debian");
00397 body.appendChild(debianFolder);
00398
00399 QDomElement pland = doc.createElement( "outline" );
00400 pland.setAttribute("text",i18n("Planet Debian"));
00401 pland.setAttribute("xmlUrl","http://planet.debian.org/rss20.xml");
00402 debianFolder.appendChild(pland);
00403
00404 QDomElement dtimes = doc.createElement( "outline" );
00405 dtimes.setAttribute("text",i18n("Debian Times"));
00406 dtimes.setAttribute("xmlUrl","http://times.debian.net/?format=rss20.xml");
00407 debianFolder.appendChild(dtimes);
00408
00409 QDomElement kubuntu = doc.createElement( "outline" );
00410 kubuntu.setAttribute("text",i18n("Kubuntu"));
00411 kubuntu.setAttribute("xmlUrl","http://kubuntu.org/kubuntu.rss");
00412 mainFolder.appendChild(kubuntu);
00413
00414 QDomElement fridge = doc.createElement( "outline" );
00415 fridge.setAttribute("text",i18n("Ubuntu Fridge"));
00416 fridge.setAttribute("xmlUrl","http://fridge.ubuntu.com/node/feed");
00417 mainFolder.appendChild(fridge);
00418
00419 QDomElement planetubuntu = doc.createElement( "outline" );
00420 planetubuntu.setAttribute("text",i18n("Planet Ubuntu"));
00421 planetubuntu.setAttribute("xmlUrl","http://planet.ubuntu.com/rss20.xml");
00422 mainFolder.appendChild(planetubuntu);
00423
00424 return doc;
00425 }
00426
00427 bool Part::openFile()
00428 {
00429 emit setStatusBarText(i18n("Opening Feed List...") );
00430
00431 QString str;
00432
00433 QFile file(m_file);
00434
00435 bool fileExists = file.exists();
00436 QString listBackup = m_storage->restoreFeedList();
00437
00438 QDomDocument doc;
00439
00440 if (!fileExists)
00441 {
00442 doc = createDefaultFeedList();
00443 }
00444 else
00445 {
00446 if (file.open(IO_ReadOnly))
00447 {
00448
00449 QTextStream stream(&file);
00450 stream.setEncoding(QTextStream::UnicodeUTF8);
00451 str = stream.read();
00452 file.close();
00453 }
00454
00455 if (!doc.setContent(str))
00456 {
00457
00458 if (file.size() > 0)
00459 {
00460 QString backup = m_file + "-backup." + QString::number(QDateTime::currentDateTime().toTime_t());
00461
00462 copyFile(backup);
00463
00464 KMessageBox::error(m_view, i18n("<qt>The standard feed list is corrupted (invalid XML). A backup was created:<p><b>%2</b></p></qt>").arg(backup), i18n("XML Parsing Error") );
00465 }
00466
00467 if (!doc.setContent(listBackup))
00468 doc = createDefaultFeedList();
00469 }
00470 }
00471
00472 if (!m_view->loadFeeds(doc))
00473 {
00474 if (file.size() > 0)
00475 {
00476 QString backup = m_file + "-backup." + QString::number(QDateTime::currentDateTime().toTime_t());
00477 copyFile(backup);
00478
00479 KMessageBox::error(m_view, i18n("<qt>The standard feed list is corrupted (no valid OPML). A backup was created:<p><b>%2</b></p></qt>").arg(backup), i18n("OPML Parsing Error") );
00480 }
00481 m_view->loadFeeds(createDefaultFeedList());
00482 }
00483
00484 emit setStatusBarText(QString::null);
00485
00486
00487 if( Settings::markAllFeedsReadOnStartup() )
00488 m_view->slotMarkAllFeedsRead();
00489
00490 if (Settings::fetchOnStartup())
00491 m_view->slotFetchAllFeeds();
00492
00493 return true;
00494 }
00495
00496 void Part::slotSaveFeedList()
00497 {
00498
00499 if (!m_standardListLoaded)
00500 return;
00501
00502
00503 if (!m_backedUpList)
00504 {
00505 QString backup = m_file + "~";
00506
00507 if (copyFile(backup))
00508 m_backedUpList = true;
00509 }
00510
00511 QString xmlStr = m_view->feedListToOPML().toString();
00512 m_storage->storeFeedList(xmlStr);
00513
00514 QFile file(m_file);
00515 if (file.open(IO_WriteOnly) == false)
00516 {
00517
00518 KMessageBox::error(m_view, i18n("Access denied: cannot save feed list (%1)").arg(m_file), i18n("Write error") );
00519 return;
00520 }
00521
00522
00523 QTextStream stream(&file);
00524 stream.setEncoding(QTextStream::UnicodeUTF8);
00525
00526
00527
00528
00529 stream << xmlStr << endl;
00530
00531 file.close();
00532 }
00533
00534 bool Part::isTrayIconEnabled() const
00535 {
00536 return Settings::showTrayIcon();
00537 }
00538
00539 bool Part::mergePart(KParts::Part* part)
00540 {
00541 if (part != m_mergedPart)
00542 {
00543 if (!factory())
00544 {
00545 kdDebug() << "Akregator::Part::mergePart(): factory() returns NULL" << endl;
00546 return false;
00547 }
00548 if (m_mergedPart)
00549 factory()->removeClient(m_mergedPart);
00550 if (part)
00551 factory()->addClient(part);
00552
00553 m_mergedPart = part;
00554 }
00555 return true;
00556 }
00557
00558 QWidget* Part::getMainWindow()
00559 {
00560
00561
00562 QWidgetList *l = kapp->topLevelWidgets();
00563 QWidgetListIt it( *l );
00564 QWidget *wid;
00565
00566
00567 while ( (wid = it.current()) != 0 )
00568 {
00569 ++it;
00570
00571 if (QString(wid->name()) == "akregator_mainwindow")
00572 {
00573 delete l;
00574 return wid;
00575 }
00576 }
00577
00578 QWidgetListIt it2( *l );
00579 while ( (wid = it2.current()) != 0 )
00580 {
00581 ++it2;
00582 if (QString(wid->name()).startsWith("kontact-mainwindow"))
00583 {
00584 delete l;
00585 return wid;
00586 }
00587 }
00588 delete l;
00589 return 0;
00590 }
00591
00592 void Part::loadTagSet(const QString& path)
00593 {
00594 QDomDocument doc;
00595
00596 QFile file(path);
00597 if (file.open(IO_ReadOnly))
00598 {
00599 doc.setContent(file.readAll());
00600 file.close();
00601 }
00602
00603 if (doc.isNull())
00604 {
00605 doc.setContent(m_storage->restoreTagSet());
00606 }
00607
00608 if (!doc.isNull())
00609 {
00610 Kernel::self()->tagSet()->readFromXML(doc);
00611 }
00612 else
00613 {
00614 Kernel::self()->tagSet()->insert(Tag("http://akregator.sf.net/tags/Interesting", i18n("Interesting")));
00615 }
00616 }
00617
00618 void Part::saveTagSet(const QString& path)
00619 {
00620 QString xmlStr = Kernel::self()->tagSet()->toXML().toString();
00621
00622 m_storage->storeTagSet(xmlStr);
00623
00624 QFile file(path);
00625
00626 if ( file.open(IO_WriteOnly) )
00627 {
00628
00629 QTextStream stream(&file);
00630 stream.setEncoding(QTextStream::UnicodeUTF8);
00631 stream << xmlStr << "\n";
00632 file.close();
00633 }
00634 }
00635
00636 void Part::importFile(const KURL& url)
00637 {
00638 QString filename;
00639
00640 bool isRemote = false;
00641
00642 if (url.isLocalFile())
00643 filename = url.path();
00644 else
00645 {
00646 isRemote = true;
00647
00648 if (!KIO::NetAccess::download(url, filename, m_view) )
00649 {
00650 KMessageBox::error(m_view, KIO::NetAccess::lastErrorString() );
00651 return;
00652 }
00653 }
00654
00655 QFile file(filename);
00656 if (file.open(IO_ReadOnly))
00657 {
00658
00659 QDomDocument doc;
00660 if (doc.setContent(file.readAll()))
00661 m_view->importFeeds(doc);
00662 else
00663 KMessageBox::error(m_view, i18n("Could not import the file %1 (no valid OPML)").arg(filename), i18n("OPML Parsing Error") );
00664 }
00665 else
00666 KMessageBox::error(m_view, i18n("The file %1 could not be read, check if it exists or if it is readable for the current user.").arg(filename), i18n("Read Error"));
00667
00668 if (isRemote)
00669 KIO::NetAccess::removeTempFile(filename);
00670 }
00671
00672 void Part::exportFile(const KURL& url)
00673 {
00674 if (url.isLocalFile())
00675 {
00676 QFile file(url.path());
00677
00678 if ( file.exists() &&
00679 KMessageBox::questionYesNo(m_view,
00680 i18n("The file %1 already exists; do you want to overwrite it?").arg(file.name()),
00681 i18n("Export"),
00682 i18n("Overwrite"),
00683 KStdGuiItem::cancel()) == KMessageBox::No )
00684 return;
00685
00686 if ( !file.open(IO_WriteOnly) )
00687 {
00688 KMessageBox::error(m_view, i18n("Access denied: cannot write to file %1").arg(file.name()), i18n("Write Error") );
00689 return;
00690 }
00691
00692 QTextStream stream(&file);
00693 stream.setEncoding(QTextStream::UnicodeUTF8);
00694
00695 stream << m_view->feedListToOPML().toString() << "\n";
00696 file.close();
00697 }
00698 else
00699 {
00700 KTempFile tmpfile;
00701 tmpfile.setAutoDelete(true);
00702
00703 QTextStream stream(tmpfile.file());
00704 stream.setEncoding(QTextStream::UnicodeUTF8);
00705
00706 stream << m_view->feedListToOPML().toString() << "\n";
00707 tmpfile.close();
00708
00709 if (!KIO::NetAccess::upload(tmpfile.name(), url, m_view))
00710 KMessageBox::error(m_view, KIO::NetAccess::lastErrorString() );
00711 }
00712 }
00713
00714 void Part::fileImport()
00715 {
00716 KURL url = KFileDialog::getOpenURL( QString::null,
00717 "*.opml *.xml|" + i18n("OPML Outlines (*.opml, *.xml)")
00718 +"\n*|" + i18n("All Files") );
00719
00720 if (!url.isEmpty())
00721 importFile(url);
00722 }
00723
00724 void Part::fileExport()
00725 {
00726 KURL url= KFileDialog::getSaveURL( QString::null,
00727 "*.opml *.xml|" + i18n("OPML Outlines (*.opml, *.xml)")
00728 +"\n*|" + i18n("All Files") );
00729
00730 if ( !url.isEmpty() )
00731 exportFile(url);
00732 }
00733
00734 void Part::fileGetFeeds()
00735 {
00736
00737
00738
00739 }
00740
00741 void Part::fileSendArticle(bool attach)
00742 {
00743
00744 QString title, text;
00745
00746 text = m_view->currentFrame()->part()->url().prettyURL();
00747 if(text.isEmpty() || text.isNull())
00748 return;
00749
00750 title = m_view->currentFrame()->title();
00751
00752 if(attach) {
00753 kapp->invokeMailer("",
00754 "",
00755 "",
00756 title,
00757 text,
00758 "",
00759 text);
00760 }
00761 else {
00762 kapp->invokeMailer("",
00763 "",
00764 "",
00765 title,
00766 text);
00767 }
00768 }
00769
00770 void Part::fetchAllFeeds()
00771 {
00772 m_view->slotFetchAllFeeds();
00773 }
00774
00775 void Part::fetchFeedUrl(const QString&s)
00776 {
00777 kdDebug() << "fetchFeedURL==" << s << endl;
00778 }
00779
00780 void Part::addFeedsToGroup(const QStringList& urls, const QString& group)
00781 {
00782 for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it)
00783 {
00784 kdDebug() << "Akregator::Part::addFeedToGroup adding feed with URL " << *it << " to group " << group << endl;
00785 m_view->addFeedToGroup(*it, group);
00786 }
00787 NotificationManager::self()->slotNotifyFeeds(urls);
00788 }
00789
00790 void Part::addFeed()
00791 {
00792 m_view->slotFeedAdd();
00793 }
00794
00795 KAboutData *Part::createAboutData()
00796 {
00797 return new Akregator::AboutData;
00798 }
00799
00800 void Part::showKNotifyOptions()
00801 {
00802 KAboutData* about = new Akregator::AboutData;
00803 KNotifyDialog::configure(m_view, "akregator_knotify_config", about);
00804 delete about;
00805 }
00806
00807 void Part::showOptions()
00808 {
00809 if ( KConfigDialog::showDialog( "settings" ) )
00810 return;
00811
00812 KConfigDialog* dialog = new ConfigDialog( m_view, "settings", Settings::self() );
00813
00814 connect( dialog, SIGNAL(settingsChanged()),
00815 this, SLOT(slotSettingsChanged()) );
00816 connect( dialog, SIGNAL(settingsChanged()),
00817 TrayIcon::getInstance(), SLOT(settingsChanged()) );
00818
00819 dialog->show();
00820 }
00821
00822 void Part::partActivateEvent(KParts::PartActivateEvent* event)
00823 {
00824 if (factory() && m_mergedPart)
00825 {
00826 if (event->activated())
00827 factory()->addClient(m_mergedPart);
00828 else
00829 factory()->removeClient(m_mergedPart);
00830 }
00831
00832 MyBasePart::partActivateEvent(event);
00833 }
00834
00835 KParts::Part* Part::hitTest(QWidget *widget, const QPoint &globalPos)
00836 {
00837 bool child = false;
00838 QWidget *me = this->widget();
00839 while (widget) {
00840 if (widget == me) {
00841 child = true;
00842 break;
00843 }
00844 if (!widget) {
00845 break;
00846 }
00847 widget = widget->parentWidget();
00848 }
00849 if (m_view && m_view->currentFrame() && child) {
00850 return m_view->currentFrame()->part();
00851 } else {
00852 return MyBasePart::hitTest(widget, globalPos);
00853 }
00854 }
00855
00856 void Part::initFonts()
00857 {
00858 QStringList fonts = Settings::fonts();
00859 if (fonts.isEmpty())
00860 {
00861 fonts.append(KGlobalSettings::generalFont().family());
00862 fonts.append(KGlobalSettings::fixedFont().family());
00863 fonts.append(KGlobalSettings::generalFont().family());
00864 fonts.append(KGlobalSettings::generalFont().family());
00865 fonts.append("0");
00866 }
00867 Settings::setFonts(fonts);
00868 if (Settings::standardFont().isEmpty())
00869 Settings::setStandardFont(fonts[0]);
00870 if (Settings::fixedFont().isEmpty())
00871 Settings::setFixedFont(fonts[1]);
00872 if (Settings::sansSerifFont().isEmpty())
00873 Settings::setSansSerifFont(fonts[2]);
00874 if (Settings::serifFont().isEmpty())
00875 Settings::setSerifFont(fonts[3]);
00876
00877 KConfig* conf = Settings::self()->config();
00878 conf->setGroup("HTML Settings");
00879
00880 KConfig konq("konquerorrc", true, false);
00881 konq.setGroup("HTML Settings");
00882
00883 if (!conf->hasKey("MinimumFontSize"))
00884 {
00885 int minfs;
00886 if (konq.hasKey("MinimumFontSize"))
00887 minfs = konq.readNumEntry("MinimumFontSize");
00888 else
00889 minfs = KGlobalSettings::generalFont().pointSize();
00890 kdDebug() << "Part::initFonts(): set MinimumFontSize to " << minfs << endl;
00891 Settings::setMinimumFontSize(minfs);
00892 }
00893
00894 if (!conf->hasKey("MediumFontSize"))
00895 {
00896 int medfs;
00897 if (konq.hasKey("MediumFontSize"))
00898 medfs = konq.readNumEntry("MediumFontSize");
00899 else
00900 medfs = KGlobalSettings::generalFont().pointSize();
00901 kdDebug() << "Part::initFonts(): set MediumFontSize to " << medfs << endl;
00902 Settings::setMediumFontSize(medfs);
00903 }
00904
00905 if (!conf->hasKey("UnderlineLinks"))
00906 {
00907 bool underline = true;
00908 if (konq.hasKey("UnderlineLinks"))
00909 underline = konq.readBoolEntry("UnderlineLinks");
00910
00911 kdDebug() << "Part::initFonts(): set UnderlineLinks to " << underline << endl;
00912 Settings::setUnderlineLinks(underline);
00913 }
00914
00915 }
00916
00917 bool Part::copyFile(const QString& backup)
00918 {
00919 QFile file(m_file);
00920
00921 if (file.open(IO_ReadOnly))
00922 {
00923 QFile backupFile(backup);
00924 if (backupFile.open(IO_WriteOnly))
00925 {
00926 QTextStream in(&file);
00927 QTextStream out(&backupFile);
00928 while (!in.atEnd())
00929 out << in.readLine();
00930 backupFile.close();
00931 file.close();
00932 return true;
00933 }
00934 else
00935 {
00936 file.close();
00937 return false;
00938 }
00939 }
00940 return false;
00941 }
00942
00943 static QString getMyHostName()
00944 {
00945 char hostNameC[256];
00946
00947 hostNameC[255] = 0;
00948
00949 if(gethostname(hostNameC, 255))
00950 hostNameC[0] = 0;
00951 return QString::fromLocal8Bit(hostNameC);
00952 }
00953
00954
00955 bool Part::tryToLock(const QString& backendName)
00956 {
00957
00958 QString appName = kapp->instanceName();
00959 if ( appName.isEmpty() )
00960 appName = "akregator";
00961
00962 QString programName;
00963 const KAboutData *about = kapp->aboutData();
00964 if ( about )
00965 programName = about->programName();
00966 if ( programName.isEmpty() )
00967 programName = i18n("Akregator");
00968
00969 QString lockLocation = locateLocal("data", "akregator/lock");
00970 KSimpleConfig config(lockLocation);
00971 int oldPid = config.readNumEntry("pid", -1);
00972 const QString oldHostName = config.readEntry("hostname");
00973 const QString oldAppName = config.readEntry( "appName", appName );
00974 const QString oldProgramName = config.readEntry( "programName", programName );
00975 const QString hostName = getMyHostName();
00976 bool first_instance = false;
00977 if ( oldPid == -1 )
00978 first_instance = true;
00979
00980
00981
00982 else if (hostName == oldHostName && oldPid != getpid()) {
00983 if ( kill(oldPid, 0) == -1 )
00984 first_instance = ( errno == ESRCH );
00985 }
00986
00987 if ( !first_instance )
00988 {
00989 QString msg;
00990 if ( oldHostName == hostName )
00991 {
00992
00993
00994
00995 if ( oldAppName == appName )
00996 msg = i18n("<qt>%1 already seems to be running on another display on "
00997 "this machine. <b>Running %2 more than once is not supported "
00998 "by the %3 backend and "
00999 "can cause the loss of archived articles and crashes at startup.</b> "
01000 "You should disable the archive for now "
01001 "unless you are sure that %2 is not already running.</qt>")
01002 .arg( programName, programName, backendName );
01003
01004
01005
01006
01007 else
01008 msg = i18n("<qt>%1 seems to be running on another display on this "
01009 "machine. <b>Running %1 and %2 at the same "
01010 "time is not supported by the %3 backend and can cause "
01011 "the loss of archived articles and crashes at startup.</b> "
01012 "You should disable the archive for now "
01013 "unless you are sure that %2 is not already running.</qt>")
01014 .arg( oldProgramName, programName, backendName );
01015 }
01016 else
01017 {
01018 if ( oldAppName == appName )
01019 msg = i18n("<qt>%1 already seems to be running on %2. <b>Running %1 more "
01020 "than once is not supported by the %3 backend and can cause "
01021 "the loss of archived articles and crashes at startup.</b> "
01022 "You should disable the archive for now "
01023 "unless you are sure that it is "
01024 "not already running on %2.</qt>")
01025 .arg( programName, oldHostName, backendName );
01026 else
01027 msg = i18n("<qt>%1 seems to be running on %3. <b>Running %1 and %2 at the "
01028 "same time is not supported by the %4 backend and can cause "
01029 "the loss of archived articles and crashes at startup.</b> "
01030 "You should disable the archive for now "
01031 "unless you are sure that %1 is "
01032 "not running on %3.</qt>")
01033 .arg( oldProgramName, programName, oldHostName, backendName );
01034 }
01035
01036 KCursorSaver idle( KBusyPtr::idle() );
01037 if ( KMessageBox::No ==
01038 KMessageBox::warningYesNo( 0, msg, QString::null,
01039 i18n("Force Access"),
01040 i18n("Disable Archive")) )
01041 {
01042 return false;
01043 }
01044 }
01045
01046 config.writeEntry("pid", getpid());
01047 config.writeEntry("hostname", hostName);
01048 config.writeEntry( "appName", appName );
01049 config.writeEntry( "programName", programName );
01050 config.sync();
01051 return true;
01052 }
01053
01054
01055 }
01056 #include "akregator_part.moc"