diff --git a/akregator/src/akregator_part.cpp b/akregator/src/akregator_part.cpp index 9e9da5ceaa..87a7d70f30 100644 --- a/akregator/src/akregator_part.cpp +++ b/akregator/src/akregator_part.cpp @@ -1,839 +1,839 @@ /* This file is part of Akregator. Copyright (C) 2004 Stanislav Karchebny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aboutdata.h" #include "actionmanagerimpl.h" #include "akregator_part.h" #include "akregator_view.h" #include "akregatorconfig.h" #include "articlefilter.h" #include "articleinterceptor.h" #include "configdialog.h" #include "fetchqueue.h" #include "frame.h" #include "article.h" #include "kernel.h" #include "notificationmanager.h" #include "pageviewer.h" #include "plugin.h" #include "pluginmanager.h" #include "storage.h" #include "storagefactory.h" #include "storagefactorydummyimpl.h" #include "storagefactoryregistry.h" #include "speechclient.h" #include "trayicon.h" #include "tagset.h" #include "tag.h" namespace Akregator { typedef KParts::GenericFactory AkregatorFactory; K_EXPORT_COMPONENT_FACTORY( libakregatorpart, AkregatorFactory ) BrowserExtension::BrowserExtension(Part *p, const char *name) : KParts::BrowserExtension( p, name ) { m_part=p; } void BrowserExtension::saveSettings() { m_part->saveSettings(); } class Part::ApplyFiltersInterceptor : public ArticleInterceptor { public: virtual void processArticle(Article& article) { Filters::ArticleFilterList list = Kernel::self()->articleFilterList(); for (Filters::ArticleFilterList::ConstIterator it = list.begin(); it != list.end(); ++it) (*it).applyTo(article); } }; Part::Part( QWidget *parentWidget, const char * /*widgetName*/, QObject *parent, const char *name, const QStringList& ) : DCOPObject("AkregatorIface") , MyBasePart(parent, name) , m_standardListLoaded(false) , m_shuttingDown(false) , m_mergedPart(0) , m_backedUpList(false) , m_storage(0) { // we need an instance setInstance( AkregatorFactory::instance() ); // start knotifyclient if not already started. makes it work for people who doesn't use full kde, according to kmail devels KNotifyClient::startDaemon(); m_standardFeedList = KGlobal::dirs()->saveLocation("data", "akregator/data") + "/feeds.opml"; m_tagSetPath = KGlobal::dirs()->saveLocation("data", "akregator/data") + "/tagset.xml"; loadTagSet(m_tagSetPath); Backend::StorageFactoryDummyImpl* dummyFactory = new Backend::StorageFactoryDummyImpl(); Backend::StorageFactoryRegistry::self()->registerFactory(dummyFactory, dummyFactory->key()); loadPlugins(); // FIXME: also unload them! m_storage = Backend::StorageFactoryRegistry::self()->getFactory("metakit")->createStorage(QStringList()); // FIXME: read backend to use from config if (!m_storage) // Houston, we have a problem { m_storage = Backend::StorageFactoryRegistry::self()->getFactory("dummy")->createStorage(QStringList()); KMessageBox::error(m_view, i18n("Unable to load storage backend plugin \"%1\". No feeds are archived.").arg("metakit"), i18n("Plugin error") ); } Filters::ArticleFilterList list; list.readConfig(Settings::self()->config()); Kernel::self()->setArticleFilterList(list); m_applyFiltersInterceptor = new ApplyFiltersInterceptor(); ArticleInterceptorManager::self()->addInterceptor(m_applyFiltersInterceptor); m_storage->open(true); Kernel::self()->setStorage(m_storage); Backend::Storage::setInstance(m_storage); // TODO: kill this one m_actionManager = new ActionManagerImpl(this); ActionManager::setInstance(m_actionManager); m_view = new Akregator::View(this, parentWidget, m_actionManager, "akregator_view"); m_actionManager->initView(m_view); m_actionManager->setTagSet(Kernel::self()->tagSet()); m_extension = new BrowserExtension(this, "ak_extension"); connect(m_view, SIGNAL(setWindowCaption(const QString&)), this, SIGNAL(setWindowCaption(const QString&))); connect(m_view, SIGNAL(setStatusBarText(const QString&)), this, SIGNAL(setStatusBarText(const QString&))); connect(m_view, SIGNAL(setProgress(int)), m_extension, SIGNAL(loadingProgress(int))); connect(m_view, SIGNAL(signalCanceled(const QString&)), this, SIGNAL(canceled(const QString&))); connect(m_view, SIGNAL(signalStarted(KIO::Job*)), this, SIGNAL(started(KIO::Job*))); connect(m_view, SIGNAL(signalCompleted()), this, SIGNAL(completed())); // notify the part that this is our internal widget setWidget(m_view); TrayIcon* trayIcon = new TrayIcon( getMainWindow() ); TrayIcon::setInstance(trayIcon); m_actionManager->initTrayIcon(trayIcon); connect(trayIcon, SIGNAL(showPart()), this, SIGNAL(showPart())); if ( isTrayIconEnabled() ) { trayIcon->show(); NotificationManager::self()->setWidget(trayIcon, instance()); } else NotificationManager::self()->setWidget(getMainWindow(), instance()); connect( trayIcon, SIGNAL(quitSelected()), kapp, SLOT(quit())) ; connect( m_view, SIGNAL(signalUnreadCountChanged(int)), trayIcon, SLOT(slotSetUnread(int)) ); connect(kapp, SIGNAL(shutDown()), this, SLOT(slotOnShutdown())); m_autosaveTimer = new QTimer(this); connect(m_autosaveTimer, SIGNAL(timeout()), this, SLOT(slotSaveFeedList())); m_autosaveTimer->start(5*60*1000); // 5 minutes setXMLFile("akregator_part.rc", true); initFonts(); } void Part::loadPlugins() { // "[X-KDE-akregator-plugintype] == 'storage'" KTrader::OfferList offers = PluginManager::query(); for( KTrader::OfferList::ConstIterator it = offers.begin(), end = offers.end(); it != end; ++it ) { Akregator::Plugin* plugin = PluginManager::createFromService(*it); if (plugin) plugin->init(); } } void Part::slotOnShutdown() { m_shuttingDown = true; m_autosaveTimer->stop(); saveSettings(); slotSaveFeedList(); saveTagSet(m_tagSetPath); m_view->slotOnShutdown(); //delete m_view; delete m_storage; m_storage = 0; //delete m_actionManager; } void Part::slotSettingsChanged() { NotificationManager::self()->setWidget(isTrayIconEnabled() ? TrayIcon::getInstance() : getMainWindow(), instance()); RSS::FileRetriever::setUseCache(Settings::useHTMLCache()); QStringList fonts; fonts.append(Settings::standardFont()); fonts.append(Settings::fixedFont()); fonts.append(Settings::sansSerifFont()); fonts.append(Settings::serifFont()); fonts.append(Settings::standardFont()); fonts.append(Settings::standardFont()); fonts.append("0"); Settings::setFonts(fonts); if (Settings::minimumFontSize() > Settings::mediumFontSize()) Settings::setMediumFontSize(Settings::minimumFontSize()); saveSettings(); emit signalSettingsChanged(); } void Part::saveSettings() { Kernel::self()->articleFilterList().writeConfig(Settings::self()->config()); m_view->saveSettings(); } Part::~Part() { kdDebug() << "Part::~Part() enter" << endl; if (!m_shuttingDown) slotOnShutdown(); kdDebug() << "Part::~Part(): leaving" << endl; ArticleInterceptorManager::self()->removeInterceptor(m_applyFiltersInterceptor); delete m_applyFiltersInterceptor; } void Part::readProperties(KConfig* config) { m_backedUpList = false; openStandardFeedList(); if(m_view) m_view->readProperties(config); } void Part::saveProperties(KConfig* config) { if (m_view) { slotSaveFeedList(); m_view->saveProperties(config); } } bool Part::openURL(const KURL& url) { m_file = url.path(); return openFile(); } void Part::openStandardFeedList() { if ( !m_standardFeedList.isEmpty() && openURL(m_standardFeedList) ) m_standardListLoaded = true; } QDomDocument Part::createDefaultFeedList() { QDomDocument doc; QDomProcessingInstruction z = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\""); doc.appendChild( z ); QDomElement root = doc.createElement( "opml" ); root.setAttribute("version","1.0"); doc.appendChild( root ); QDomElement head = doc.createElement( "head" ); root.appendChild(head); QDomElement text = doc.createElement( "text" ); text.appendChild(doc.createTextNode(i18n("Feeds"))); head.appendChild(text); QDomElement body = doc.createElement( "body" ); root.appendChild(body); QDomElement mainFolder = doc.createElement( "outline" ); mainFolder.setAttribute("text","KDE"); body.appendChild(mainFolder); QDomElement ak = doc.createElement( "outline" ); ak.setAttribute("text",i18n("Akregator News")); ak.setAttribute("xmlUrl","http://akregator.sf.net/rss2.php"); mainFolder.appendChild(ak); QDomElement akb = doc.createElement( "outline" ); akb.setAttribute("text",i18n("Akregator Blog")); akb.setAttribute("xmlUrl","http://akregator.pwsp.net/blog/?feed=rss2"); mainFolder.appendChild(akb); QDomElement dot = doc.createElement( "outline" ); dot.setAttribute("text",i18n("KDE Dot News")); dot.setAttribute("xmlUrl","http://www.kde.org/dotkdeorg.rdf"); mainFolder.appendChild(dot); QDomElement plan = doc.createElement( "outline" ); plan.setAttribute("text",i18n("Planet KDE")); plan.setAttribute("xmlUrl","http://planetkde.org/rss20.xml"); mainFolder.appendChild(plan); QDomElement apps = doc.createElement( "outline" ); apps.setAttribute("text",i18n("KDE Apps")); apps.setAttribute("xmlUrl","http://www.kde.org/dot/kde-apps-content.rdf"); mainFolder.appendChild(apps); QDomElement look = doc.createElement( "outline" ); look.setAttribute("text",i18n("KDE Look")); look.setAttribute("xmlUrl","http://www.kde.org/kde-look-content.rdf"); mainFolder.appendChild(look); return doc; } bool Part::openFile() { QString str; // m_file is always local so we can use QFile on it QFile file(m_file); if (!file.exists()) { m_view->loadFeeds(createDefaultFeedList()); } else { if (file.open(IO_ReadOnly)) { // Read OPML feeds list and build QDom tree. QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); // FIXME not all opmls are in utf8 str = stream.read(); file.close(); } else { KMessageBox::error(m_view, i18n("Could not read standard feed list (%1). A default feed list will be used.").arg(m_file), i18n("Read Error") ); return false; } emit setStatusBarText(i18n("Opening Feed List...") ); QDomDocument doc; if (!doc.setContent(str)) { QString backup = m_file + "-backup." + QString::number(QDateTime::currentDateTime().toTime_t()); copyFile(backup); KMessageBox::error(m_view, i18n("The standard feed list is corrupted (invalid XML). A backup was created:

%2

").arg(backup), i18n("XML Parsing Error") ); doc = createDefaultFeedList(); } if (!m_view->loadFeeds(doc)) { QString backup = m_file + "-backup." + QString::number(QDateTime::currentDateTime().toTime_t()); copyFile(backup); KMessageBox::error(m_view, i18n("The standard feed list is corrupted (no valid OPML). A backup was created:

%2

").arg(backup), i18n("OPML Parsing Error") ); m_view->loadFeeds(createDefaultFeedList()); } emit setStatusBarText(QString::null); } if( Settings::markAllFeedsReadOnStartup() ) m_view->slotMarkAllFeedsRead(); if (Settings::fetchOnStartup()) m_view->slotFetchAllFeeds(); return true; } void Part::slotSaveFeedList() { // don't save to the standard feed list, when it wasn't completely loaded before if (!m_standardListLoaded) return; // the first time we overwrite the feed list, we create a backup if (!m_backedUpList) { QString backup = m_file + "~"; if (copyFile(backup)) m_backedUpList = true; } QFile file(m_file); if (file.open(IO_WriteOnly) == false) { //FIXME: allow to save the feedlist into different location -tpr 20041118 KMessageBox::error(m_view, i18n("Access denied: cannot save feed list (%1)").arg(m_file), i18n("Write error") ); return; } // use QTextStream to dump the text to the file QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); // Write OPML data file. // Archive data files are saved elsewhere. stream << m_view->feedListToOPML().toString(); file.close(); } bool Part::isTrayIconEnabled() const { return Settings::showTrayIcon(); } bool Part::mergePart(KParts::Part* part) { if (part != m_mergedPart) { if (!factory()) { kdDebug() << "Akregator::Part::mergePart(): factory() returns NULL" << endl; return false; } if (m_mergedPart) factory()->removeClient(m_mergedPart); if (part) factory()->addClient(part); m_mergedPart = part; } return true; } QWidget* Part::getMainWindow() { // this is a dirty fix to get the main window used for the tray icon QWidgetList *l = kapp->topLevelWidgets(); QWidgetListIt it( *l ); QWidget *wid; // check if there is an akregator main window while ( (wid = it.current()) != 0 ) { ++it; //kdDebug() << "win name: " << wid->name() << endl; if (QString(wid->name()) == "akregator_mainwindow") return wid; } // if not, check for kontact main window QWidgetListIt it2( *l ); while ( (wid = it2.current()) != 0 ) { ++it2; if (QString(wid->name()).startsWith("kontact-mainwindow")) return wid; } return 0; } void Part::loadTagSet(const QString& path) { QFile file(path); if (file.open(IO_ReadOnly)) { QDomDocument doc; if (doc.setContent(file.readAll())) Kernel::self()->tagSet()->readFromXML(doc); file.close(); } else { Kernel::self()->tagSet()->insert(Tag("http://akregator.sf.net/tags/Interesting", i18n("Interesting"))); } } void Part::saveTagSet(const QString& path) { QFile file(path); if ( file.open(IO_WriteOnly) ) { QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); stream << Kernel::self()->tagSet()->toXML().toString() << "\n"; file.close(); } } void Part::importFile(const KURL& url) { QString filename; bool isRemote = false; if (url.isLocalFile()) filename = url.path(); else { isRemote = true; if (!KIO::NetAccess::download(url, filename, m_view) ) { KMessageBox::error(m_view, KIO::NetAccess::lastErrorString() ); return; } } QFile file(filename); if (file.open(IO_ReadOnly)) { // Read OPML feeds list and build QDom tree. QDomDocument doc; if (doc.setContent(file.readAll())) m_view->importFeeds(doc); else KMessageBox::error(m_view, i18n("Could not import the file %1 (no valid OPML)").arg(filename), i18n("OPML Parsing Error") ); } else 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")); if (isRemote) KIO::NetAccess::removeTempFile(filename); } void Part::exportFile(const KURL& url) { if (url.isLocalFile()) { QFile file(url.path()); if ( file.exists() && KMessageBox::questionYesNo(m_view, i18n("The file %1 already exists; do you want to overwrite it?").arg(file.name()), i18n("Export"), i18n("Overwrite"), KStdGuiItem::cancel()) == KMessageBox::No ) return; if ( !file.open(IO_WriteOnly) ) { - KMessageBox::error(m_view, i18n("Access denied: cannot write to file %1").arg(file.name()), i18n("Write error") ); + KMessageBox::error(m_view, i18n("Access denied: cannot write to file %1").arg(file.name()), i18n("Write Error") ); return; } QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); stream << m_view->feedListToOPML().toString() << "\n"; file.close(); } else { KTempFile tmpfile; tmpfile.setAutoDelete(true); QTextStream stream(tmpfile.file()); stream.setEncoding(QTextStream::UnicodeUTF8); stream << m_view->feedListToOPML().toString() << "\n"; tmpfile.close(); if (!KIO::NetAccess::upload(tmpfile.name(), url, m_view)) KMessageBox::error(m_view, KIO::NetAccess::lastErrorString() ); } } void Part::fileImport() { KURL url = KFileDialog::getOpenURL( QString::null, "*.opml *.xml|" + i18n("OPML Outlines (*.opml, *.xml)") +"\n*|" + i18n("All Files") ); if (!url.isEmpty()) importFile(url); } void Part::fileExport() { KURL url= KFileDialog::getSaveURL( QString::null, "*.opml *.xml|" + i18n("OPML Outlines (*.opml, *.xml)") +"\n*|" + i18n("All Files") ); if ( !url.isEmpty() ) exportFile(url); } void Part::fileGetFeeds() { /*GetFeeds *gf = new GetFeeds(); gf->show();*/ //KNS::DownloadDialog::open("akregator/feeds", i18n("Get New Feeds")); } void Part::fileSendArticle(bool attach) { // FIXME: you have to open article to tab to be able to send... QString title, text; text = m_view->currentFrame()->part()->url().prettyURL(); if(text.isEmpty() || text.isNull()) return; title = m_view->currentFrame()->title(); if(attach) { kapp->invokeMailer("", "", "", title, text, "", text); } else { kapp->invokeMailer("", "", "", title, text); } } void Part::fetchAllFeeds() { m_view->slotFetchAllFeeds(); } void Part::fetchFeedUrl(const QString&s) { kdDebug() << "fetchFeedURL==" << s << endl; } void Part::addFeedsToGroup(const QStringList& urls, const QString& group) { for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it) { kdDebug() << "Akregator::Part::addFeedToGroup adding feed with URL " << *it << " to group " << group << endl; m_view->addFeedToGroup(*it, group); } NotificationManager::self()->slotNotifyFeeds(urls); } void Part::addFeed() { m_view->slotFeedAdd(); } KAboutData *Part::createAboutData() { return new Akregator::AboutData; } void Part::showKNotifyOptions() { KAboutData* about = new Akregator::AboutData; KNotifyDialog::configure(m_view, "akregator_knotify_config", about); delete about; } void Part::showOptions() { if ( KConfigDialog::showDialog( "settings" ) ) return; KConfigDialog* dialog = new ConfigDialog( m_view, "settings", Settings::self() ); connect( dialog, SIGNAL(settingsChanged()), this, SLOT(slotSettingsChanged()) ); connect( dialog, SIGNAL(settingsChanged()), TrayIcon::getInstance(), SLOT(settingsChanged()) ); dialog->show(); } void Part::partActivateEvent(KParts::PartActivateEvent* event) { if (factory() && m_mergedPart) { if (event->activated()) factory()->addClient(m_mergedPart); else factory()->removeClient(m_mergedPart); } MyBasePart::partActivateEvent(event); } KParts::Part* Part::hitTest(QWidget *widget, const QPoint &globalPos) { bool child = false; QWidget *me = this->widget(); while (widget) { if (widget == me) { child = true; break; } if (!widget) { break; } widget = widget->parentWidget(); } if (m_view && m_view->currentFrame() && child) { return m_view->currentFrame()->part(); } else { return MyBasePart::hitTest(widget, globalPos); } } void Part::initFonts() { QStringList fonts = Settings::fonts(); if (fonts.isEmpty()) { fonts.append(KGlobalSettings::generalFont().family()); fonts.append(KGlobalSettings::fixedFont().family()); fonts.append(KGlobalSettings::generalFont().family()); fonts.append(KGlobalSettings::generalFont().family()); fonts.append("0"); } Settings::setFonts(fonts); if (Settings::standardFont().isEmpty()) Settings::setStandardFont(fonts[0]); if (Settings::fixedFont().isEmpty()) Settings::setFixedFont(fonts[1]); if (Settings::sansSerifFont().isEmpty()) Settings::setSansSerifFont(fonts[2]); if (Settings::serifFont().isEmpty()) Settings::setSerifFont(fonts[3]); KConfig* conf = Settings::self()->config(); conf->setGroup("HTML Settings"); KConfig konq("konquerorrc", true, false); konq.setGroup("HTML Settings"); if (!conf->hasKey("MinimumFontSize")) { int minfs; if (konq.hasKey("MinimumFontSize")) minfs = konq.readNumEntry("MinimumFontSize"); else minfs = KGlobalSettings::generalFont().pointSize(); kdDebug() << "Part::initFonts(): set MinimumFontSize to " << minfs << endl; Settings::setMinimumFontSize(minfs); } if (!conf->hasKey("MediumFontSize")) { int medfs; if (konq.hasKey("MediumFontSize")) medfs = konq.readNumEntry("MediumFontSize"); else medfs = KGlobalSettings::generalFont().pointSize(); kdDebug() << "Part::initFonts(): set MediumFontSize to " << medfs << endl; Settings::setMediumFontSize(medfs); } if (!conf->hasKey("UnderlineLinks")) { bool underline = true; if (konq.hasKey("UnderlineLinks")) underline = konq.readBoolEntry("UnderlineLinks"); kdDebug() << "Part::initFonts(): set UnderlineLinks to " << underline << endl; Settings::setUnderlineLinks(underline); } } bool Part::copyFile(const QString& backup) { QFile file(m_file); if (file.open(IO_ReadOnly)) { QFile backupFile(backup); if (backupFile.open(IO_WriteOnly)) { QTextStream in(&file); QTextStream out(&backupFile); while (!in.atEnd()) out << in.readLine(); backupFile.close(); file.close(); return true; } else { file.close(); return false; } } return false; } } // namespace Akregator #include "akregator_part.moc" diff --git a/akregator/src/mk4storage/mk4confwidgetbase.ui b/akregator/src/mk4storage/mk4confwidgetbase.ui index b85db2d8e2..cc91559afd 100644 --- a/akregator/src/mk4storage/mk4confwidgetbase.ui +++ b/akregator/src/mk4storage/mk4confwidgetbase.ui @@ -1,178 +1,178 @@ Akregator::Backend::MK4ConfWidgetBase MK4ConfWidgetBase 0 0 377 115 - Metakit settings + Metakit Settings true true unnamed layout4 unnamed cbUseDefault Use default location true layout3 unnamed label Archive location: filereq false layout4 unnamed Horizontal Spacing2 Horizontal Expanding 140 20 buttonOk &OK true true buttonApply &Apply true buttonCancel &Cancel true buttonOk clicked() MK4ConfWidgetBase accept() buttonCancel clicked() MK4ConfWidgetBase reject() cbUseDefault toggled(bool) label setDisabled(bool) cbUseDefault <No Signal> cbUseDefault <No) kurlrequester.h klineedit.h kpushbutton.h diff --git a/akregator/src/settings_advancedbase.ui b/akregator/src/settings_advancedbase.ui index b68710bca8..03a5b35c26 100644 --- a/akregator/src/settings_advancedbase.ui +++ b/akregator/src/settings_advancedbase.ui @@ -1,143 +1,143 @@ Akregator::SettingsAdvancedBase Frank Osterfeld SettingsAdvanced 0 0 476 486 unnamed 0 groupBox3_3_2 Archive unnamed textLabel1 Archive backend: cbBackend pbBackendConfigure &Configure... spacer2 Vertical Expanding 21 270 groupBox3_3 - Article list + Article List unnamed kcfg_UseMarkReadDelay Mar&k selected article read after true kcfg_MarkReadDelay true sec 0 spacer4 Horizontal Expanding 30 20 kcfg_UseMarkReadDelay toggled(bool) kcfg_MarkReadDelay setEnabled(bool) kcombobox.h diff --git a/akregator/src/settings_browser.ui b/akregator/src/settings_browser.ui index b43001a86c..aa4d0a790c 100644 --- a/akregator/src/settings_browser.ui +++ b/akregator/src/settings_browser.ui @@ -1,206 +1,206 @@ Akregator::SettingsBrowser Gary Cramblitt SettingsBrowser 0 0 340 299 ExternalBrowser unnamed 0 buttonGroup1 For External Browsing false unnamed kcfg_ExternalBrowserUseKdeDefault Use default KDE web browser true kcfg_ExternalBrowserUseCustomCommand Use this command: kcfg_ExternalBrowserCustomCommand false firefox -remote 'openURL(%u,new-tab)' kcfg_CloseButtonOnTabs Show tab close button on hover spacer1 Vertical Expanding 31 16 layout2 unnamed Open in Tab Open in Background Tab Open in External Browser kcfg_LMBBehaviour 7 0 0 0 textLabel1 1 0 0 0 - Middle Mouse Click: + Middle mouse click: textLabel1_3 1 0 0 0 - Left Mouse Click: + Left mouse click: Open in Tab Open in Background Tab Open in External Browser kcfg_MMBBehaviour 7 0 0 0 kcfg_ExternalBrowserUseCustomCommand toggled(bool) kcfg_ExternalBrowserCustomCommand setEnabled(bool) diff --git a/certmanager/certificatewizard.ui b/certmanager/certificatewizard.ui index 906e6cfd0c..7edbd1a72b 100644 --- a/certmanager/certificatewizard.ui +++ b/certmanager/certificatewizard.ui @@ -1,558 +1,558 @@ CertificateWizard CertificateWizard 0 0 832 589 Key Generation Wizard 16 1 introPage Key Generation Wizard unnamed TextLabel1 <b>Welcome to the Key Generation Wizard.</b> <br> <br> In a few easy steps, this wizard will help you to create a new key pair and request a certificate for it. You can then use your certificate in order to sign messages, to encrypt messages and to decrypt messages that other people send to you in encrypted form. <p> The key pair will be generated in a decentralized manner. Please contact your local help desk if you are unsure how to obtain a certificate for your new key in your organization. spacer3 Vertical Expanding 20 40 WizardPage Key Parameters unnamed TextLabel2_2 On this page, you will configure the cryptographic key length and the type of certificate to create. WordBreak|AlignVCenter spacer14 Vertical Expanding 20 31 groupBox1 Cryptographic Key Length unnamed textLabel1 Choose &key length: keyLengthCB keyLengthCB spacer13 Horizontal Expanding 61 20 certTypeBG Certificate Usage unnamed signOnlyCB For &signing only encryptOnlyCB For &encrypting only bothCB For signing &and encrypting true spacer12 Vertical Expanding 21 60 personalDataPage Your Personal Data unnamed TextLabel2 On this page, you will enter some personal data that will be stored in your certificate and that will help other people to determine that it is actually you who is sending a message. WordBreak|AlignVCenter spacer6 Horizontal Expanding 440 20 insertAddressButton &Insert My Address This will insert your address if you have set the "Who am I" information in the address book spacer4 Vertical Expanding 20 40 edContainer 3 5 0 0 StyledPanel Sunken generatePage Decentralized Key Generation unnamed TextLabel4 <qt><p>On this page, you will create a key pair in a decentralized way. </p><p>You can either store the certificate request in a file for later transmission or send it to the Certificate Authority (CA) directly. Please check with your local help desk if you are unsure what to select here.</p><p> Once you are done with your settings, click <em>Generate Key Pair and Certificate Request</em> in order to generate your key pair and a corresponding certificate request.</p> <p><b>Note:</b> if you choose to send via email directly, a kmail composer will be opened; you can add detailed information for the CA there.</p><qt> WordBreak|AlignVCenter spacer5 Vertical Expanding 21 31 ButtonGroup7 5 1 0 0 Certificate Request Options unnamed 11 6 storeUR storeInFileRB &Store in a file: sendToCARB Send to CA as an &email message: true caEmailED brokenCA Add email to DN in request for broken CAs generatePB 0 30 - &Generate Key Pair and Certificate Request + &Generate Key Pair && Certificate Request Spacer12 Horizontal Expanding 118 16 Spacer13 Horizontal Expanding 119 16 finishPage - Your Certificate Request Is Ready To Be Sent + Your Certificate Request is Ready to Be Sent unnamed 11 6 TextLabel7 <qt> Your key pair has now been created and stored locally. The corresponding certificate request is now ready to be sent to the CA (certification authority) which will generate a certificate for you and send it back via email (unless you have selected storage in a file). Please review the certificate details shown below. <p> If you want to change anything, press Back and make your changes; otherwise, press Finish to send the certificate request to the CA. </qt> WordBreak|AlignVCenter certificateTE true generatePB clicked() CertificateWizard slotGenerateCertificate() sendToCARB toggled(bool) caEmailED setEnabled(bool) storeInFileRB toggled(bool) storeUR setEnabled(bool) caEmailED textChanged(const QString&) CertificateWizard slotEmailAddressChanged(const QString&) sendToCARB clicked() caEmailED setFocus() storeInFileRB clicked() storeUR setFocus() sendToCARB caEmailED certificateTE generatePB slotEmailAddressChanged(const QString&) slotGenerateCertificate() klineedit.h kpushbutton.h diff --git a/certmanager/lib/ui/directoryserviceswidgetbase.ui b/certmanager/lib/ui/directoryserviceswidgetbase.ui index 879cbd0623..1dabbca51d 100644 --- a/certmanager/lib/ui/directoryserviceswidgetbase.ui +++ b/certmanager/lib/ui/directoryserviceswidgetbase.ui @@ -1,342 +1,342 @@ DirectoryServicesWidgetBase DirectoryServicesWidgetBase 0 0 576 363 Directory Services Configuration unnamed 11 6 x500LA NoFrame Plain - X.&500 Directory services: + X.&500 directory services: x500LV layout2 unnamed Server Name true true Port true true Base DN true true User Name true true Password true true x500LV true Select Directory Services to Use Here <qt> <h1>X.500 Directory Services</h1> You can use X.500 directory services to retrieve certificates and certificate revocation lists that are not saved locally. Ask your local administrator if you want to make use of this feature and are unsure which directory service you can use. <p> If you do not use a directory service, you can still use local certificates. </qt> layout1 unnamed upButton downButton spacer5 Vertical Expanding 20 51 layout3 unnamed Spacer10 Horizontal Expanding 47 20 addServicePB &Add Service... Click to add a service <qt> <h1>Add a Directory Service</h1> By clicking this button, you can select a new directory service to be used for retrieving certificates and CRLs. You will be asked for the server name and an optional description. </qt> Spacer11 Horizontal Expanding 47 20 removeServicePB false &Remove Service Click to remove the currently selected service <qt> <h1>Remove Directory Service</h1> By clicking this button, you can remove the currently selected directory service in the list above. You will have a chance to rethink your decision before the entry is deleted from the list. </qt> Spacer12 Horizontal Expanding 47 20 Spacer9 Vertical Expanding 20 16 removeServicePB clicked() DirectoryServicesWidgetBase slotDeleteService() x500LV returnPressed(QListViewItem*) DirectoryServicesWidgetBase slotServiceSelected(QListViewItem*) x500LV doubleClicked(QListViewItem*) DirectoryServicesWidgetBase slotServiceSelected(QListViewItem*) x500LV selectionChanged(QListViewItem*) DirectoryServicesWidgetBase slotServiceChanged(QListViewItem*) addServicePB clicked() DirectoryServicesWidgetBase slotAddService() upButton clicked() DirectoryServicesWidgetBase slotMoveUp() downButton clicked() DirectoryServicesWidgetBase slotMoveDown() slotAddService() slotDeleteService() slotServiceChanged( QListViewItem* ) slotServiceSelected( QListViewItem* ) slotMoveUp() slotMoveDown() diff --git a/kaddressbook/features/distributionlistwidget.cpp b/kaddressbook/features/distributionlistwidget.cpp index de36cd16bd..0ae7159e6d 100644 --- a/kaddressbook/features/distributionlistwidget.cpp +++ b/kaddressbook/features/distributionlistwidget.cpp @@ -1,664 +1,664 @@ /* This file is part of KAddressBook. Copyright (c) 2002 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "distributionlistwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KDEPIM_NEW_DISTRLISTS #include typedef KPIM::DistributionList DistributionList; #else #include typedef KABC::DistributionList DistributionList; #endif #include #include #include #include "core.h" class DistributionListFactory : public KAB::ExtensionFactory { public: KAB::ExtensionWidget *extension( KAB::Core *core, QWidget *parent, const char *name ) { return new DistributionListWidget( core, parent, name ); } QString identifier() const { return "distribution_list_editor"; } }; extern "C" { void *init_libkaddrbk_distributionlist() { return ( new DistributionListFactory ); } } /** We have to catch when the 'Del' key is pressed, otherwise the event is forwarded to the ViewManager and it tries to remove a contact instead of the distribution list. */ class DeletePressedCatcher : public QObject { public: DeletePressedCatcher( DistributionListWidget *parent ) : QObject( parent, "DeletePressedCatcher" ), mWidget( parent ) { } protected: bool eventFilter( QObject*, QEvent *event ) { if ( event->type() == QEvent::AccelOverride ) { QKeyEvent *keyEvent = (QKeyEvent*)event; if ( keyEvent->key() == Qt::Key_Delete ) { keyEvent->accept(); mWidget->removeContact(); return true; } else return false; } else { return false; } } private: DistributionListWidget *mWidget; }; class ContactItem : public QListViewItem { public: ContactItem( DistributionListView *parent, const KABC::Addressee &addressee, const QString &email = QString::null ) : QListViewItem( parent ), mAddressee( addressee ), mEmail( email ) { setText( 0, addressee.realName() ); if ( email.isEmpty() ) { setText( 1, addressee.preferredEmail() ); setText( 2, i18n( "Yes" ) ); } else { setText( 1, email ); setText( 2, i18n( "No" ) ); } } KABC::Addressee addressee() const { return mAddressee; } QString email() const { return mEmail; } protected: bool acceptDrop( const QMimeSource* ) { return true; } private: KABC::Addressee mAddressee; QString mEmail; }; DistributionListWidget::DistributionListWidget( KAB::Core *core, QWidget *parent, const char *name ) : KAB::ExtensionWidget( core, parent, name ) #ifndef KDEPIM_NEW_DISTRLISTS , mManager( 0 ) #endif { QGridLayout *topLayout = new QGridLayout( this, 3, 4, KDialog::marginHint(), KDialog::spacingHint() ); mNameCombo = new QComboBox( this ); topLayout->addWidget( mNameCombo, 0, 0 ); connect( mNameCombo, SIGNAL( activated( int ) ), SLOT( updateContactView() ) ); mCreateListButton = new QPushButton( i18n( "New List..." ), this ); topLayout->addWidget( mCreateListButton, 0, 1 ); connect( mCreateListButton, SIGNAL( clicked() ), SLOT( createList() ) ); mEditListButton = new QPushButton( i18n( "Rename List..." ), this ); topLayout->addWidget( mEditListButton, 0, 2 ); connect( mEditListButton, SIGNAL( clicked() ), SLOT( editList() ) ); mRemoveListButton = new QPushButton( i18n( "Remove List" ), this ); topLayout->addWidget( mRemoveListButton, 0, 3 ); connect( mRemoveListButton, SIGNAL( clicked() ), SLOT( removeList() ) ); mContactView = new DistributionListView( this ); mContactView->addColumn( i18n( "Name" ) ); mContactView->addColumn( i18n( "Email" ) ); mContactView->addColumn( i18n( "Use Preferred" ) ); mContactView->setEnabled( false ); mContactView->setAllColumnsShowFocus( true ); mContactView->setFullWidth( true ); topLayout->addMultiCellWidget( mContactView, 1, 1, 0, 3 ); connect( mContactView, SIGNAL( selectionChanged() ), SLOT( selectionContactViewChanged() ) ); connect( mContactView, SIGNAL( dropped( QDropEvent*, QListViewItem* ) ), SLOT( dropped( QDropEvent*, QListViewItem* ) ) ); mAddContactButton = new QPushButton( i18n( "Add Contact" ), this ); mAddContactButton->setEnabled( false ); topLayout->addWidget( mAddContactButton, 2, 0 ); connect( mAddContactButton, SIGNAL( clicked() ), SLOT( addContact() ) ); mEntryCountLabel = new QLabel( this ); topLayout->addWidget( mEntryCountLabel, 2, 1 ); mChangeEmailButton = new QPushButton( i18n( "Change Email..." ), this ); topLayout->addWidget( mChangeEmailButton, 2, 2 ); connect( mChangeEmailButton, SIGNAL( clicked() ), SLOT( changeEmail() ) ); mRemoveContactButton = new QPushButton( i18n( "Remove Contact" ), this ); topLayout->addWidget( mRemoveContactButton, 2, 3 ); connect( mRemoveContactButton, SIGNAL( clicked() ), SLOT( removeContact() ) ); #ifdef KDEPIM_NEW_DISTRLISTS // When contacts are changed, update both distr list combo and contents of displayed distr list connect( core, SIGNAL( contactsUpdated() ), this, SLOT( updateNameCombo() ) ); #else mManager = new KABC::DistributionListManager( core->addressBook() ); connect( KABC::DistributionListWatcher::self(), SIGNAL( changed() ), this, SLOT( updateNameCombo() ) ); #endif connect( core->addressBook(), SIGNAL( addressBookChanged( AddressBook* ) ), this, SLOT( updateNameCombo() ) ); updateNameCombo(); QObject *catcher = new DeletePressedCatcher( this ); installEventFilter( catcher ); mContactView->installEventFilter( catcher ); KAcceleratorManager::manage( this ); } DistributionListWidget::~DistributionListWidget() { #ifndef KDEPIM_NEW_DISTRLISTS delete mManager; #endif } void DistributionListWidget::save() { #ifndef KDEPIM_NEW_DISTRLISTS mManager->save(); #endif } void DistributionListWidget::selectionContactViewChanged() { ContactItem *contactItem = static_cast( mContactView->selectedItem() ); bool state = contactItem; mChangeEmailButton->setEnabled( state ); mRemoveContactButton->setEnabled( state ); } bool DistributionListWidget::alreadyExists( const QString& distrListName ) const { #ifdef KDEPIM_NEW_DISTRLISTS return core()->distributionListNames().contains( distrListName ); #else return mManager->listNames().contains( distrListName ); #endif } void DistributionListWidget::createList() { QString newName = KInputDialog::getText( i18n( "New Distribution List" ), i18n( "Please enter name:" ), QString::null, 0, this ); if ( newName.isEmpty() ) return; if ( alreadyExists( newName ) ) { KMessageBox::sorry( this, i18n( "The name already exists" ) ); return; } #ifdef KDEPIM_NEW_DISTRLISTS KABC::Resource* resource = core()->requestResource( this ); if ( !resource ) return; KPIM::DistributionList dist; dist.setResource( resource ); dist.setName( newName ); core()->addressBook()->insertAddressee( dist ); // Creates undo-redo command, calls setModified, also triggers contactsUpdated, // which triggers updateNameCombo, so the new name appears changed( dist ); #else new KABC::DistributionList( mManager, newName ); updateNameCombo(); #endif // Select the new one in the list mNameCombo->setCurrentText( newName ); // Display the contents of the list we just selected (well, it's empty) updateContactView(); #ifndef KDEPIM_NEW_DISTRLISTS changed(); #endif } void DistributionListWidget::editList() { const QString oldName = mNameCombo->currentText(); const QString newName = KInputDialog::getText( i18n( "Rename Distribution List" ), i18n( "Please enter name:" ), oldName, 0, this ); if ( newName.isEmpty() ) return; if ( alreadyExists( newName ) ) { - KMessageBox::sorry( this, i18n( "The name already exists" ) ); + KMessageBox::sorry( this, i18n( "The name already exists." ) ); return; } #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) // not found [should be impossible] return; dist.setFormattedName( newName ); core()->addressBook()->insertAddressee( dist ); changed( dist ); #else KABC::DistributionList *list = mManager->list( oldName ); list->setName( newName ); updateNameCombo(); #endif // Select the new name in the list (updateNameCombo couldn't know we wanted that one) mNameCombo->setCurrentText( newName ); // Display the contents of the list we just selected updateContactView(); #ifndef KDEPIM_NEW_DISTRLISTS changed(); #endif } void DistributionListWidget::removeList() { int result = KMessageBox::warningContinueCancel( this, i18n( "Delete distribution list %1?" ) .arg( mNameCombo->currentText() ), QString::null, KGuiItem( i18n("Delete"), "editdelete") ); if ( result != KMessageBox::Continue ) return; #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) // not found [should be impossible] return; core()->addressBook()->removeAddressee( dist ); emit deleted( dist.uid() ); #else mManager->remove( mManager->list( mNameCombo->currentText() ) ); mNameCombo->removeItem( mNameCombo->currentItem() ); updateContactView(); changed(); #endif } void DistributionListWidget::addContact() { #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) { // not found kdDebug(5720) << k_funcinfo << mNameCombo->currentText() << " not found" << endl; return; } #else KABC::DistributionList *list = mManager->list( mNameCombo->currentText() ); if ( !list ) return; KABC::DistributionList& dist = *list; #endif const KABC::Addressee::List addrList = selectedContacts(); KABC::Addressee::List::ConstIterator it; for ( it = addrList.begin(); it != addrList.end(); ++it ) dist.insertEntry( *it ); #ifdef KDEPIM_NEW_DISTRLISTS core()->addressBook()->insertAddressee( dist ); changed( dist ); #else updateContactView(); changed(); #endif } void DistributionListWidget::removeContact() { #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) // not found return; #else KABC::DistributionList *list = mManager->list( mNameCombo->currentText() ); if ( !list ) return; KABC::DistributionList& dist = *list; #endif ContactItem *contactItem = static_cast( mContactView->selectedItem() ); if ( !contactItem ) return; dist.removeEntry( contactItem->addressee(), contactItem->email() ); delete contactItem; #ifdef KDEPIM_NEW_DISTRLISTS core()->addressBook()->insertAddressee( dist ); changed( dist ); #else changed(); #endif } void DistributionListWidget::changeEmail() { #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) // not found return; #else KABC::DistributionList *list = mManager->list( mNameCombo->currentText() ); if ( !list ) return; KABC::DistributionList& dist = *list; #endif ContactItem *contactItem = static_cast( mContactView->selectedItem() ); if ( !contactItem ) return; const QString email = EmailSelector::getEmail( contactItem->addressee().emails(), contactItem->email(), this ); dist.removeEntry( contactItem->addressee(), contactItem->email() ); dist.insertEntry( contactItem->addressee(), email ); #ifdef KDEPIM_NEW_DISTRLISTS core()->addressBook()->insertAddressee( dist ); changed( dist ); #else updateContactView(); changed(); #endif } void DistributionListWidget::updateContactView() { mContactView->clear(); bool isListSelected = false; #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist; if ( mNameCombo->count() != 0 ) dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); isListSelected = !dist.isEmpty(); #else KABC::DistributionList *list = mManager->list( mNameCombo->currentText() ); isListSelected = list != 0; #endif if ( !isListSelected ) { mEditListButton->setEnabled( false ); mRemoveListButton->setEnabled( false ); mChangeEmailButton->setEnabled( false ); mRemoveContactButton->setEnabled( false ); mContactView->setEnabled( false ); return; } mEditListButton->setEnabled( true ); mRemoveListButton->setEnabled( true ); mContactView->setEnabled( true ); uint entryCount = 0; #ifdef KDEPIM_NEW_DISTRLISTS const KPIM::DistributionList::Entry::List entries = dist.entries( core()->addressBook() ); KPIM::DistributionList::Entry::List::ConstIterator it; #else const KABC::DistributionList::Entry::List entries = list->entries(); KABC::DistributionList::Entry::List::ConstIterator it; #endif for ( it = entries.begin(); it != entries.end(); ++it, ++entryCount ) new ContactItem( mContactView, (*it).addressee, (*it).email ); bool state = mContactView->selectedItem() != 0; mChangeEmailButton->setEnabled( state ); mRemoveContactButton->setEnabled( state ); mEntryCountLabel->setText( i18n( "Count: %n contact", "Count: %n contacts", entryCount ) ); } void DistributionListWidget::updateNameCombo() { int pos = mNameCombo->currentItem(); mNameCombo->clear(); #ifdef KDEPIM_NEW_DISTRLISTS const QStringList names = core()->distributionListNames(); #else mManager->load(); const QStringList names = mManager->listNames(); #endif mNameCombo->insertStringList( names ); mNameCombo->setCurrentItem( QMIN( pos, (int)names.count() - 1 ) ); updateContactView(); } void DistributionListWidget::dropEvent( QDropEvent *e ) { if ( mNameCombo->count() == 0 ) return; #ifdef KDEPIM_NEW_DISTRLISTS KPIM::DistributionList dist = KPIM::DistributionList::findByName( core()->addressBook(), mNameCombo->currentText() ); if ( dist.isEmpty() ) return; #else KABC::DistributionList *list = mManager->list( mNameCombo->currentText() ); if ( !list ) return; KABC::DistributionList& dist = *list; #endif QString vcards; if ( KVCardDrag::decode( e, vcards ) ) { KABC::VCardConverter converter; const KABC::Addressee::List lst = converter.parseVCards( vcards ); for ( KABC::Addressee::List::ConstIterator it = lst.begin(); it != lst.end(); ++it ) dist.insertEntry( *it ); #ifdef KDEPIM_NEW_DISTRLISTS core()->addressBook()->insertAddressee( dist ); changed( dist ); #else changed(); updateContactView(); #endif } } void DistributionListWidget::contactsSelectionChanged() { mAddContactButton->setEnabled( contactsSelected() && mNameCombo->count() > 0 ); } QString DistributionListWidget::title() const { return i18n( "Distribution List Editor" ); } QString DistributionListWidget::identifier() const { return "distribution_list_editor"; } void DistributionListWidget::dropped( QDropEvent *e, QListViewItem* ) { dropEvent( e ); } #ifdef KDEPIM_NEW_DISTRLISTS void DistributionListWidget::changed( const KABC::Addressee& dist ) { emit modified( KABC::Addressee::List() << dist ); } #else void DistributionListWidget::changed() { save(); } #endif DistributionListView::DistributionListView( QWidget *parent, const char* name ) : KListView( parent, name ) { setDragEnabled( true ); setAcceptDrops( true ); setAllColumnsShowFocus( true ); } void DistributionListView::dragEnterEvent( QDragEnterEvent* e ) { bool canDecode = QTextDrag::canDecode( e ); e->accept( canDecode ); } void DistributionListView::viewportDragMoveEvent( QDragMoveEvent *e ) { bool canDecode = QTextDrag::canDecode( e ); e->accept( canDecode ); } void DistributionListView::viewportDropEvent( QDropEvent *e ) { emit dropped( e, 0 ); } void DistributionListView::dropEvent( QDropEvent *e ) { emit dropped( e, 0 ); } EmailSelector::EmailSelector( const QStringList &emails, const QString ¤t, QWidget *parent ) : KDialogBase( KDialogBase::Plain, i18n("Select Email Address"), Ok, Ok, parent ) { QFrame *topFrame = plainPage(); QBoxLayout *topLayout = new QVBoxLayout( topFrame ); mButtonGroup = new QButtonGroup( 1, Horizontal, i18n("Email Addresses"), topFrame ); mButtonGroup->setRadioButtonExclusive( true ); topLayout->addWidget( mButtonGroup ); QRadioButton *button = new QRadioButton( i18n("Preferred address"), mButtonGroup ); button->setDown( true ); mEmailMap.insert( mButtonGroup->id( button ), "" ); QStringList::ConstIterator it; for ( it = emails.begin(); it != emails.end(); ++it ) { button = new QRadioButton( *it, mButtonGroup ); mEmailMap.insert( mButtonGroup->id( button ), *it ); if ( (*it) == current ) button->setDown( true ); } } QString EmailSelector::selected() const { QButton *button = mButtonGroup->selected(); if ( button ) return mEmailMap[ mButtonGroup->id( button ) ]; return QString::null; } QString EmailSelector::getEmail( const QStringList &emails, const QString ¤t, QWidget *parent ) { EmailSelector dlg( emails, current, parent ); dlg.exec(); return dlg.selected(); } #include "distributionlistwidget.moc" diff --git a/kalarm/messagewin.cpp b/kalarm/messagewin.cpp index af3024acad..6d713a555a 100644 --- a/kalarm/messagewin.cpp +++ b/kalarm/messagewin.cpp @@ -1,1602 +1,1602 @@ /* * messagewin.cpp - displays an alarm message * Program: kalarm * Copyright (C) 2001 - 2005 by David Jarvie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kalarm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITHOUT_ARTS #include #else #include #include #include #include #endif #include #include #include "alarmcalendar.h" #include "deferdlg.h" #include "editdlg.h" #include "functions.h" #include "kalarmapp.h" #include "mainwindow.h" #include "preferences.h" #include "synchtimer.h" #include "messagewin.moc" using namespace KCal; #ifndef WITHOUT_ARTS static const char* KMIX_APP_NAME = "kmix"; static const char* KMIX_DCOP_OBJECT = "Mixer0"; static const char* KMIX_DCOP_WINDOW = "kmix-mainwindow#1"; #endif static const char* KMAIL_DCOP_OBJECT = "KMailIface"; // The delay for enabling message window buttons if a zero delay is // configured, i.e. the windows are placed far from the cursor. static const int proximityButtonDelay = 1000; // (milliseconds) static const int proximityMultiple = 10; // multiple of button height distance from cursor for proximity // A text label widget which can be scrolled and copied with the mouse class MessageText : public QTextEdit { public: MessageText(const QString& text, const QString& context = QString::null, QWidget* parent = 0, const char* name = 0) : QTextEdit(text, context, parent, name) { setReadOnly(true); setWordWrap(QTextEdit::NoWrap); } int scrollBarHeight() const { return horizontalScrollBar()->height(); } int scrollBarWidth() const { return verticalScrollBar()->width(); } virtual QSize sizeHint() const { return QSize(contentsWidth() + scrollBarWidth(), contentsHeight() + scrollBarHeight()); } }; class MWMimeSourceFactory : public QMimeSourceFactory { public: MWMimeSourceFactory(const QString& absPath, KTextBrowser*); virtual ~MWMimeSourceFactory(); virtual const QMimeSource* data(const QString& abs_name) const; private: // Prohibit the following methods virtual void setData(const QString&, QMimeSource*) {} virtual void setExtensionType(const QString&, const char*) {} QString mTextFile; QCString mMimeType; mutable const QMimeSource* mLast; }; // Basic flags for the window static const Qt::WFlags WFLAGS = Qt::WStyle_StaysOnTop | Qt::WDestructiveClose; QValueList MessageWin::mWindowList; /****************************************************************************** * Construct the message window for the specified alarm. * Other alarms in the supplied event may have been updated by the caller, so * the whole event needs to be stored for updating the calendar file when it is * displayed. */ MessageWin::MessageWin(const KAEvent& event, const KAAlarm& alarm, bool reschedule_event, bool allowDefer) : MainWindowBase(0, "MessageWin", WFLAGS | Qt::WGroupLeader | Qt::WStyle_ContextHelp | (Preferences::modalMessages() ? 0 : Qt::WX11BypassWM)), mMessage(event.cleanText()), mFont(event.font()), mBgColour(event.bgColour()), mFgColour(event.fgColour()), mDateTime((alarm.type() & KAAlarm::REMINDER_ALARM) ? event.mainDateTime() : alarm.dateTime()), mEventID(event.id()), mAudioFile(event.audioFile()), mVolume(event.soundVolume()), mFadeVolume(event.fadeVolume()), mFadeSeconds(QMIN(event.fadeSeconds(), 86400)), mAlarmType(alarm.type()), mAction(event.action()), mKMailSerialNumber(event.kmailSerialNumber()), mRestoreHeight(0), mAudioRepeat(event.repeatSound()), mConfirmAck(event.confirmAck()), mShowEdit(!mEventID.isEmpty()), mNoDefer(!allowDefer || alarm.repeatAtLogin()), mInvalid(false), mArtsDispatcher(0), mPlayObject(0), mOldVolume(-1), mEvent(event), mEditButton(0), mDeferButton(0), mSilenceButton(0), mDeferDlg(0), mWinModule(0), mFlags(event.flags()), mLateCancel(event.lateCancel()), mErrorWindow(false), mNoPostAction(false), mRecreating(false), mBeep(event.beep()), mSpeak(event.speak()), mRescheduleEvent(reschedule_event), mShown(false), mPositioning(false), mNoCloseConfirm(false) { kdDebug(5950) << "MessageWin::MessageWin(event)" << endl; // Set to save settings automatically, but don't save window size. // File alarm window size is saved elsewhere. setAutoSaveSettings(QString::fromLatin1("MessageWin"), false); initView(); mWindowList.append(this); } /****************************************************************************** * Construct the message window for a specified error message. */ MessageWin::MessageWin(const KAEvent& event, const DateTime& alarmDateTime, const QStringList& errmsgs) : MainWindowBase(0, "MessageWin", WFLAGS | Qt::WGroupLeader | Qt::WStyle_ContextHelp), mMessage(event.cleanText()), mDateTime(alarmDateTime), mEventID(event.id()), mAlarmType(KAAlarm::MAIN_ALARM), mAction(event.action()), mKMailSerialNumber(0), mErrorMsgs(errmsgs), mRestoreHeight(0), mConfirmAck(false), mShowEdit(false), mNoDefer(true), mInvalid(false), mArtsDispatcher(0), mPlayObject(0), mEvent(event), mEditButton(0), mDeferButton(0), mSilenceButton(0), mDeferDlg(0), mWinModule(0), mErrorWindow(true), mNoPostAction(true), mRecreating(false), mRescheduleEvent(false), mShown(false), mPositioning(false), mNoCloseConfirm(false) { kdDebug(5950) << "MessageWin::MessageWin(errmsg)" << endl; initView(); mWindowList.append(this); } /****************************************************************************** * Construct the message window for restoration by session management. * The window is initialised by readProperties(). */ MessageWin::MessageWin() : MainWindowBase(0, "MessageWin", WFLAGS), mArtsDispatcher(0), mPlayObject(0), mSilenceButton(0), mDeferDlg(0), mWinModule(0), mErrorWindow(false), mNoPostAction(true), mRecreating(false), mRescheduleEvent(false), mShown(false), mPositioning(false), mNoCloseConfirm(false) { kdDebug(5950) << "MessageWin::MessageWin()\n"; mWindowList.append(this); } /****************************************************************************** * Destructor. Perform any post-alarm actions before tidying up. */ MessageWin::~MessageWin() { kdDebug(5950) << "MessageWin::~MessageWin()\n"; stopPlay(); delete mWinModule; mWinModule = 0; mWindowList.remove(this); if (!mRecreating) { if (!mNoPostAction && !mEvent.postAction().isEmpty()) theApp()->alarmCompleted(mEvent); if (!mWindowList.count()) theApp()->quitIf(); } } /****************************************************************************** * Construct the message window. */ void MessageWin::initView() { bool reminder = (!mErrorWindow && (mAlarmType & KAAlarm::REMINDER_ALARM)); int leading = fontMetrics().leading(); setCaption((mAlarmType & KAAlarm::REMINDER_ALARM) ? i18n("Reminder") : i18n("Message")); QWidget* topWidget = new QWidget(this, "messageWinTop"); setCentralWidget(topWidget); QVBoxLayout* topLayout = new QVBoxLayout(topWidget, KDialog::marginHint(), KDialog::spacingHint()); if (mDateTime.isValid()) { // Show the alarm date/time, together with an "Advance reminder" text where appropriate QFrame* frame = 0; QVBoxLayout* layout = topLayout; if (reminder) { frame = new QFrame(topWidget); frame->setFrameStyle(QFrame::Box | QFrame::Raised); topLayout->addWidget(frame, 0, Qt::AlignHCenter); layout = new QVBoxLayout(frame, leading + frame->frameWidth(), leading); } // Alarm date/time QLabel* label = new QLabel(frame ? frame : topWidget); label->setText(mDateTime.isDateOnly() ? KGlobal::locale()->formatDate(mDateTime.date(), true) : KGlobal::locale()->formatDateTime(mDateTime.dateTime())); if (!frame) label->setFrameStyle(QFrame::Box | QFrame::Raised); label->setFixedSize(label->sizeHint()); layout->addWidget(label, 0, Qt::AlignHCenter); QWhatsThis::add(label, i18n("The scheduled date/time for the message (as opposed to the actual time of display).")); if (frame) { label = new QLabel(frame); label->setText(i18n("Reminder")); label->setFixedSize(label->sizeHint()); layout->addWidget(label, 0, Qt::AlignHCenter); frame->setFixedSize(frame->sizeHint()); } } if (!mErrorWindow) { // It's a normal alarm message window switch (mAction) { case KAEvent::FILE: { // Display the file name QLabel* label = new QLabel(mMessage, topWidget); label->setFrameStyle(QFrame::Box | QFrame::Raised); label->setFixedSize(label->sizeHint()); QWhatsThis::add(label, i18n("The file whose contents are displayed below")); topLayout->addWidget(label, 0, Qt::AlignHCenter); // Display contents of file bool opened = false; bool dir = false; QString tmpFile; KURL url(mMessage); if (KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow())) { QFile qfile(tmpFile); QFileInfo info(qfile); if (!(dir = info.isDir())) { opened = true; KTextBrowser* view = new KTextBrowser(topWidget, "fileContents"); MWMimeSourceFactory msf(tmpFile, view); view->setMinimumSize(view->sizeHint()); topLayout->addWidget(view); // Set the default size to 20 lines square. // Note that after the first file has been displayed, this size // is overridden by the user-set default stored in the config file. // So there is no need to calculate an accurate size. int h = 20*view->fontMetrics().lineSpacing() + 2*view->frameWidth(); view->resize(QSize(h, h).expandedTo(view->sizeHint())); QWhatsThis::add(view, i18n("The contents of the file to be displayed")); } KIO::NetAccess::removeTempFile(tmpFile); } if (!opened) { // File couldn't be opened bool exists = KIO::NetAccess::exists(url, true, MainWindow::mainMainWindow()); mErrorMsgs += dir ? i18n("File is a folder") : exists ? i18n("Failed to open file") : i18n("File not found"); } break; } case KAEvent::MESSAGE: { // Message label // Using MessageText instead of QLabel allows scrolling and mouse copying MessageText* text = new MessageText(mMessage, QString::null, topWidget); text->setFrameStyle(QFrame::NoFrame); text->setPaper(mBgColour); text->setPaletteForegroundColor(mFgColour); text->setFont(mFont); int lineSpacing = text->fontMetrics().lineSpacing(); QSize s = text->sizeHint(); int h = s.height(); text->setMaximumHeight(h + text->scrollBarHeight()); text->setMinimumHeight(QMIN(h, lineSpacing*4)); text->setMaximumWidth(s.width() + text->scrollBarWidth()); QWhatsThis::add(text, i18n("The alarm message")); int vspace = lineSpacing/2; int hspace = lineSpacing - KDialog::marginHint(); topLayout->addSpacing(vspace); topLayout->addStretch(); // Don't include any horizontal margins if message is 2/3 screen width if (!mWinModule) mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP); if (text->sizeHint().width() >= mWinModule->workArea().width()*2/3) topLayout->addWidget(text, 1, Qt::AlignHCenter); else { QBoxLayout* layout = new QHBoxLayout(topLayout); layout->addSpacing(hspace); layout->addWidget(text, 1, Qt::AlignHCenter); layout->addSpacing(hspace); } if (!reminder) topLayout->addStretch(); break; } case KAEvent::COMMAND: case KAEvent::EMAIL: default: break; } if (reminder) { // Reminder: show remaining time until the actual alarm mRemainingText = new QLabel(topWidget); mRemainingText->setFrameStyle(QFrame::Box | QFrame::Raised); mRemainingText->setMargin(leading); if (mDateTime.isDateOnly() || QDate::currentDate().daysTo(mDateTime.date()) > 0) { setRemainingTextDay(); MidnightTimer::connect(this, SLOT(setRemainingTextDay())); // update every day } else { setRemainingTextMinute(); MinuteTimer::connect(this, SLOT(setRemainingTextMinute())); // update every minute } topLayout->addWidget(mRemainingText, 0, Qt::AlignHCenter); topLayout->addSpacing(KDialog::spacingHint()); topLayout->addStretch(); } } else { // It's an error message switch (mAction) { case KAEvent::EMAIL: { // Display the email addresses and subject. QFrame* frame = new QFrame(topWidget); frame->setFrameStyle(QFrame::Box | QFrame::Raised); QWhatsThis::add(frame, i18n("The email to send")); topLayout->addWidget(frame, 0, Qt::AlignHCenter); QGridLayout* grid = new QGridLayout(frame, 2, 2, KDialog::marginHint(), KDialog::spacingHint()); QLabel* label = new QLabel(i18n("Email addressee", "To:"), frame); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 0, 0, Qt::AlignLeft); label = new QLabel(mEvent.emailAddresses("\n"), frame); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 0, 1, Qt::AlignLeft); label = new QLabel(i18n("Email subject", "Subject:"), frame); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 1, 0, Qt::AlignLeft); label = new QLabel(mEvent.emailSubject(), frame); label->setFixedSize(label->sizeHint()); grid->addWidget(label, 1, 1, Qt::AlignLeft); break; } case KAEvent::COMMAND: case KAEvent::FILE: case KAEvent::MESSAGE: default: // Just display the error message strings break; } } if (!mErrorMsgs.count()) topWidget->setBackgroundColor(mBgColour); else { setCaption(i18n("Error")); QBoxLayout* layout = new QHBoxLayout(topLayout); layout->setMargin(2*KDialog::marginHint()); layout->addStretch(); QLabel* label = new QLabel(topWidget); label->setPixmap(DesktopIcon("error")); label->setFixedSize(label->sizeHint()); layout->addWidget(label, 0, Qt::AlignRight); QBoxLayout* vlayout = new QVBoxLayout(layout); for (QStringList::Iterator it = mErrorMsgs.begin(); it != mErrorMsgs.end(); ++it) { label = new QLabel(*it, topWidget); label->setFixedSize(label->sizeHint()); vlayout->addWidget(label, 0, Qt::AlignLeft); } layout->addStretch(); } QGridLayout* grid = new QGridLayout(1, 4); topLayout->addLayout(grid); grid->setColStretch(0, 1); // keep the buttons right-adjusted in the window int gridIndex = 1; // Close button mOkButton = new KPushButton(KStdGuiItem::close(), topWidget); // Prevent accidental acknowledgement of the message if the user is typing when the window appears mOkButton->clearFocus(); mOkButton->setFocusPolicy(QWidget::ClickFocus); // don't allow keyboard selection mOkButton->setFixedSize(mOkButton->sizeHint()); connect(mOkButton, SIGNAL(clicked()), SLOT(close())); grid->addWidget(mOkButton, 0, gridIndex++, AlignHCenter); QWhatsThis::add(mOkButton, i18n("Acknowledge the alarm")); if (mShowEdit) { // Edit button mEditButton = new QPushButton(i18n("&Edit..."), topWidget); mEditButton->setFocusPolicy(QWidget::ClickFocus); // don't allow keyboard selection mEditButton->setFixedSize(mEditButton->sizeHint()); connect(mEditButton, SIGNAL(clicked()), SLOT(slotEdit())); grid->addWidget(mEditButton, 0, gridIndex++, AlignHCenter); QWhatsThis::add(mEditButton, i18n("Edit the alarm.")); } if (!mNoDefer) { // Defer button mDeferButton = new QPushButton(i18n("&Defer..."), topWidget); mDeferButton->setFocusPolicy(QWidget::ClickFocus); // don't allow keyboard selection mDeferButton->setFixedSize(mDeferButton->sizeHint()); connect(mDeferButton, SIGNAL(clicked()), SLOT(slotDefer())); grid->addWidget(mDeferButton, 0, gridIndex++, AlignHCenter); QWhatsThis::add(mDeferButton, i18n("Defer the alarm until later.\n" "You will be prompted to specify when the alarm should be redisplayed.")); setDeferralLimit(mEvent); // ensure that button is disabled when alarm can't be deferred any more } #ifndef WITHOUT_ARTS if (!mAudioFile.isEmpty() && (mVolume || mFadeVolume > 0)) { // Silence button to stop sound repetition QPixmap pixmap = MainBarIcon("player_stop"); mSilenceButton = new QPushButton(topWidget); mSilenceButton->setPixmap(pixmap); mSilenceButton->setFixedSize(mSilenceButton->sizeHint()); connect(mSilenceButton, SIGNAL(clicked()), SLOT(stopPlay())); grid->addWidget(mSilenceButton, 0, gridIndex++, AlignHCenter); QToolTip::add(mSilenceButton, i18n("Stop sound")); QWhatsThis::add(mSilenceButton, i18n("Stop playing the sound")); // To avoid getting in a mess, disable the button until sound playing has been set up mSilenceButton->setEnabled(false); } #endif KIconLoader iconLoader; if (mKMailSerialNumber) { // KMail button QPixmap pixmap = iconLoader.loadIcon(QString::fromLatin1("kmail"), KIcon::MainToolbar); mKMailButton = new QPushButton(topWidget); mKMailButton->setPixmap(pixmap); mKMailButton->setFixedSize(mKMailButton->sizeHint()); connect(mKMailButton, SIGNAL(clicked()), SLOT(slotShowKMailMessage())); grid->addWidget(mKMailButton, 0, gridIndex++, AlignHCenter); QToolTip::add(mKMailButton, i18n("Locate this email in KMail", "Locate in KMail")); QWhatsThis::add(mKMailButton, i18n("Locate and highlight this email in KMail")); } else mKMailButton = 0; // KAlarm button QPixmap pixmap = iconLoader.loadIcon(QString::fromLatin1(kapp->aboutData()->appName()), KIcon::MainToolbar); mKAlarmButton = new QPushButton(topWidget); mKAlarmButton->setPixmap(pixmap); mKAlarmButton->setFixedSize(mKAlarmButton->sizeHint()); connect(mKAlarmButton, SIGNAL(clicked()), SLOT(displayMainWindow())); grid->addWidget(mKAlarmButton, 0, gridIndex++, AlignHCenter); QString actKAlarm = i18n("Activate %1").arg(kapp->aboutData()->programName()); QToolTip::add(mKAlarmButton, actKAlarm); QWhatsThis::add(mKAlarmButton, actKAlarm); // Disable all buttons initially, to prevent accidental clicking on if they happen to be // under the mouse just as the window appears. mOkButton->setEnabled(false); if (mDeferButton) mDeferButton->setEnabled(false); if (mEditButton) mEditButton->setEnabled(false); if (mKMailButton) mKMailButton->setEnabled(false); mKAlarmButton->setEnabled(false); topLayout->activate(); setMinimumSize(QSize(grid->sizeHint().width() + 2*KDialog::marginHint(), sizeHint().height())); WId winid = winId(); unsigned long wstate = (Preferences::modalMessages() ? NET::Modal : 0) | NET::Sticky | NET::StaysOnTop; KWin::setState(winid, wstate); KWin::setOnAllDesktops(winid, true); } /****************************************************************************** * Set the remaining time text in a reminder window. * Called at the start of every day (at the user-defined start-of-day time). */ void MessageWin::setRemainingTextDay() { QString text; int days = QDate::currentDate().daysTo(mDateTime.date()); if (days == 0 && !mDateTime.isDateOnly()) { // The alarm is due today, so start refreshing every minute MidnightTimer::disconnect(this, SLOT(setRemainingTextDay())); setRemainingTextMinute(); MinuteTimer::connect(this, SLOT(setRemainingTextMinute())); // update every minute } else { if (days == 0) text = i18n("Today"); else if (days % 7) text = i18n("Tomorrow", "in %n days' time", days); else text = i18n("in 1 week's time", "in %n weeks' time", days/7); } mRemainingText->setText(text); } /****************************************************************************** * Set the remaining time text in a reminder window. * Called on every minute boundary. */ void MessageWin::setRemainingTextMinute() { QString text; int mins = (QDateTime::currentDateTime().secsTo(mDateTime.dateTime()) + 59) / 60; if (mins < 60) text = i18n("in 1 minute's time", "in %n minutes' time", mins); else if (mins % 60 == 0) text = i18n("in 1 hour's time", "in %n hours' time", mins/60); else if (mins % 60 == 1) text = i18n("in 1 hour 1 minute's time", "in %n hours 1 minute's time", mins/60); else text = i18n("in 1 hour %1 minutes' time", "in %n hours %1 minutes' time", mins/60).arg(mins%60); mRemainingText->setText(text); } /****************************************************************************** * Save settings to the session managed config file, for restoration * when the program is restored. */ void MessageWin::saveProperties(KConfig* config) { if (mShown && !mErrorWindow) { config->writeEntry(QString::fromLatin1("EventID"), mEventID); config->writeEntry(QString::fromLatin1("AlarmType"), mAlarmType); config->writeEntry(QString::fromLatin1("Message"), mMessage); config->writeEntry(QString::fromLatin1("Type"), mAction); config->writeEntry(QString::fromLatin1("Font"), mFont); config->writeEntry(QString::fromLatin1("BgColour"), mBgColour); config->writeEntry(QString::fromLatin1("FgColour"), mFgColour); config->writeEntry(QString::fromLatin1("ConfirmAck"), mConfirmAck); if (mDateTime.isValid()) { config->writeEntry(QString::fromLatin1("Time"), mDateTime.dateTime()); config->writeEntry(QString::fromLatin1("DateOnly"), mDateTime.isDateOnly()); } #ifndef WITHOUT_ARTS if (mAudioRepeat && mSilenceButton && mSilenceButton->isEnabled()) { // Only need to restart sound file playing if it's being repeated config->writePathEntry(QString::fromLatin1("AudioFile"), mAudioFile); config->writeEntry(QString::fromLatin1("Volume"), static_cast(mVolume * 100)); } #endif config->writeEntry(QString::fromLatin1("Height"), height()); config->writeEntry(QString::fromLatin1("NoDefer"), mNoDefer); config->writeEntry(QString::fromLatin1("KMailSerial"), mKMailSerialNumber); } else config->writeEntry(QString::fromLatin1("Invalid"), true); } /****************************************************************************** * Read settings from the session managed config file. * This function is automatically called whenever the app is being restored. * Read in whatever was saved in saveProperties(). */ void MessageWin::readProperties(KConfig* config) { mInvalid = config->readBoolEntry(QString::fromLatin1("Invalid"), false); mEventID = config->readEntry(QString::fromLatin1("EventID")); mAlarmType = KAAlarm::Type(config->readNumEntry(QString::fromLatin1("AlarmType"))); mMessage = config->readEntry(QString::fromLatin1("Message")); mAction = KAEvent::Action(config->readNumEntry(QString::fromLatin1("Type"))); mFont = config->readFontEntry(QString::fromLatin1("Font")); mBgColour = config->readColorEntry(QString::fromLatin1("BgColour")); mFgColour = config->readColorEntry(QString::fromLatin1("FgColour")); mConfirmAck = config->readBoolEntry(QString::fromLatin1("ConfirmAck")); QDateTime invalidDateTime; QDateTime dt = config->readDateTimeEntry(QString::fromLatin1("Time"), &invalidDateTime); bool dateOnly = config->readBoolEntry(QString::fromLatin1("DateOnly")); mDateTime.set(dt, dateOnly); #ifndef WITHOUT_ARTS mAudioFile = config->readPathEntry(QString::fromLatin1("AudioFile")); mVolume = static_cast(config->readNumEntry(QString::fromLatin1("Volume"))) / 100; mFadeVolume = -1; mFadeSeconds = 0; if (!mAudioFile.isEmpty()) mAudioRepeat = true; #endif mRestoreHeight = config->readNumEntry(QString::fromLatin1("Height")); mNoDefer = config->readBoolEntry(QString::fromLatin1("NoDefer")); mKMailSerialNumber = config->readUnsignedLongNumEntry(QString::fromLatin1("KMailSerial")); mShowEdit = false; if (mAlarmType != KAAlarm::INVALID_ALARM) { // Recreate the event from the calendar file (if possible) if (!mEventID.isEmpty()) { const Event* kcalEvent = AlarmCalendar::activeCalendar()->event(mEventID); if (!kcalEvent) { // It's not in the active calendar, so try the displaying calendar AlarmCalendar* cal = AlarmCalendar::displayCalendar(); if (cal->isOpen()) kcalEvent = cal->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING)); } if (kcalEvent) { mEvent.set(*kcalEvent); mEvent.setUid(KAEvent::ACTIVE); // in case it came from the display calendar mShowEdit = true; } } initView(); } } /****************************************************************************** * Returns the existing message window (if any) which is displaying the event * with the specified ID. */ MessageWin* MessageWin::findEvent(const QString& eventID) { for (QValueList::Iterator it = mWindowList.begin(); it != mWindowList.end(); ++it) { MessageWin* w = *it; if (w->mEventID == eventID && !w->mErrorWindow) return w; } return 0; } /****************************************************************************** * Beep and play the audio file, as appropriate. */ void MessageWin::playAudio() { if (mBeep) { // Beep using two methods, in case the sound card/speakers are switched off or not working KNotifyClient::beep(); // beep through the sound card & speakers QApplication::beep(); // beep through the internal speaker } if (!mAudioFile.isEmpty()) { if (!mVolume && mFadeVolume <= 0) return; // ensure zero volume doesn't play anything #ifdef WITHOUT_ARTS QString play = mAudioFile; QString file = QString::fromLatin1("file:"); if (mAudioFile.startsWith(file)) play = mAudioFile.mid(file.length()); KAudioPlayer::play(QFile::encodeName(play)); #else // An audio file is specified. Because loading it may take some time, // call it on a timer to allow the window to display first. QTimer::singleShot(0, this, SLOT(slotPlayAudio())); #endif } else if (mSpeak) { // The message is to be spoken. In case of error messges, // call it on a timer to allow the window to display first. QTimer::singleShot(0, this, SLOT(slotSpeak())); } } /****************************************************************************** * Speak the message. * Called asynchronously to avoid delaying the display of the message. */ void MessageWin::slotSpeak() { DCOPClient* client = kapp->dcopClient(); if (!client->isApplicationRegistered("kttsd")) { // kttsd is not running, so start it QString error; if (kapp->startServiceByDesktopName("kttsd", QStringList(), &error)) { kdDebug(5950) << "MessageWin::slotSpeak(): failed to start kttsd: " << error << endl; KMessageBox::detailedError(0, i18n("Unable to speak message"), error); return; } } QByteArray data; QDataStream arg(data, IO_WriteOnly); arg << mMessage << ""; if (!client->send("kttsd", "KSpeech", "sayMessage(QString,QString)", data)) { kdDebug(5950) << "MessageWin::slotSpeak(): sayMessage() DCOP error" << endl; - KMessageBox::detailedError(0, i18n("Unable to speak message"), i18n("DCOP call sayMessage failed")); + KMessageBox::detailedError(0, i18n("Unable to speak message"), i18n("DCOP Call sayMessage failed")); } } /****************************************************************************** * Play the audio file. * Called asynchronously to avoid delaying the display of the message. */ void MessageWin::slotPlayAudio() { #ifndef WITHOUT_ARTS // First check that it exists, to avoid possible crashes if the filename is badly specified MainWindow* mmw = MainWindow::mainMainWindow(); KURL url(mAudioFile); if (!url.isValid() || !KIO::NetAccess::exists(url, true, mmw) || !KIO::NetAccess::download(url, mLocalAudioFile, mmw)) { kdError(5950) << "MessageWin::playAudio(): Open failure: " << mAudioFile << endl; KMessageBox::error(this, i18n("Cannot open audio file:\n%1").arg(mAudioFile)); return; } if (!mArtsDispatcher) { mFadeTimer = 0; mPlayTimer = new QTimer(this); connect(mPlayTimer, SIGNAL(timeout()), SLOT(checkAudioPlay())); mArtsDispatcher = new KArtsDispatcher; mPlayedOnce = false; mAudioFileStart = QTime::currentTime(); initAudio(true); if (!mPlayObject->object().isNull()) checkAudioPlay(); #if KDE_VERSION >= 308 if (!mUsingKMix && mVolume >= 0) { // Output error message now that everything else has been done. // (Outputting it earlier would delay things until it is acknowledged.) KMessageBox::information(this, i18n("Unable to set master volume\n(Error accessing KMix:\n%1)").arg(mKMixError), QString::null, QString::fromLatin1("KMixError")); kdWarning(5950) << "Unable to set master volume (KMix: " << mKMixError << ")\n"; } #endif } #endif } #ifndef WITHOUT_ARTS /****************************************************************************** * Set up the audio file for playing. */ void MessageWin::initAudio(bool firstTime) { KArtsServer aserver; Arts::SoundServerV2 sserver = aserver.server(); KDE::PlayObjectFactory factory(sserver); mPlayObject = factory.createPlayObject(mLocalAudioFile, true); if (firstTime) { // Save the existing sound volume setting for restoration afterwards, // and set the desired volume for the alarm. mUsingKMix = false; float volume = mVolume; // initial volume if (volume >= 0) { // The volume has been specified if (mFadeVolume >= 0) volume = mFadeVolume; // fading, so adjust the initial volume // Get the current master volume from KMix int vol = getKMixVolume(); if (vol >= 0) { mOldVolume = vol; // success mUsingKMix = true; setKMixVolume(static_cast(volume * 100)); } } if (!mUsingKMix) { /* Adjust within the current master volume, because either * a) the volume is not specified, in which case we want to play * at 100% of the current master volume setting, or * b) KMix is not available to set the master volume. */ mOldVolume = sserver.outVolume().scaleFactor(); // save volume for restoration afterwards sserver.outVolume().scaleFactor(volume >= 0 ? volume : 1); } } mSilenceButton->setEnabled(true); mPlayed = false; connect(mPlayObject, SIGNAL(playObjectCreated()), SLOT(checkAudioPlay())); if (!mPlayObject->object().isNull()) checkAudioPlay(); } #endif /****************************************************************************** * Called when the audio file has loaded and is ready to play, or on a timer * when play is expected to have completed. * If it is ready to play, start playing it (for the first time or repeated). * If play has not yet completed, wait a bit longer. */ void MessageWin::checkAudioPlay() { #ifndef WITHOUT_ARTS if (!mPlayObject) return; if (mPlayObject->state() == Arts::posIdle) { // The file has loaded and is ready to play, or play has completed if (mPlayedOnce && !mAudioRepeat) { // Play has completed stopPlay(); return; } // Start playing the file, either for the first time or again kdDebug(5950) << "MessageWin::checkAudioPlay(): start\n"; if (!mPlayedOnce) { // Start playing the file for the first time QTime now = QTime::currentTime(); mAudioFileLoadSecs = mAudioFileStart.secsTo(now); if (mAudioFileLoadSecs < 0) mAudioFileLoadSecs += 86400; if (mVolume >= 0 && mFadeVolume >= 0 && mFadeSeconds > 0) { // Set up volume fade mAudioFileStart = now; mFadeTimer = new QTimer(this); connect(mFadeTimer, SIGNAL(timeout()), SLOT(slotFade())); mFadeTimer->start(1000); // adjust volume every second } mPlayedOnce = true; } if (mAudioFileLoadSecs < 3) { /* The aRts library takes several attempts before a PlayObject can * be replayed, leaving a gap of perhaps 5 seconds between plays. * So if loading the file takes a short time, it's better to reload * the PlayObject rather than try to replay the same PlayObject. */ if (mPlayed) { // Playing has completed. Start playing again. delete mPlayObject; initAudio(false); if (mPlayObject->object().isNull()) return; } mPlayed = true; mPlayObject->play(); } else { // The file is slow to load, so attempt to replay the PlayObject static Arts::poTime t0((long)0, (long)0, 0, std::string()); Arts::poTime current = mPlayObject->currentTime(); if (current.seconds || current.ms) mPlayObject->seek(t0); else mPlayObject->play(); } } // The sound file is still playing Arts::poTime overall = mPlayObject->overallTime(); Arts::poTime current = mPlayObject->currentTime(); int time = 1000*(overall.seconds - current.seconds) + overall.ms - current.ms; if (time < 0) time = 0; kdDebug(5950) << "MessageWin::checkAudioPlay(): wait for " << (time+100) << "ms\n"; mPlayTimer->start(time + 100, true); #endif } /****************************************************************************** * Called when play completes, the Silence button is clicked, or the window is * closed, to reset the sound volume and terminate audio access. */ void MessageWin::stopPlay() { #ifndef WITHOUT_ARTS if (mArtsDispatcher) { // Restore the sound volume to what it was before the sound file // was played, provided that nothing else has modified it since. if (!mUsingKMix) { KArtsServer aserver; Arts::StereoVolumeControl svc = aserver.server().outVolume(); float currentVolume = svc.scaleFactor(); float eventVolume = mVolume; if (eventVolume < 0) eventVolume = 1; if (currentVolume == eventVolume) svc.scaleFactor(mOldVolume); } else if (mVolume >= 0) { int eventVolume = static_cast(mVolume * 100); int currentVolume = getKMixVolume(); // Volume returned isn't always exactly equal to volume set if (currentVolume < 0 || abs(currentVolume - eventVolume) < 5) setKMixVolume(static_cast(mOldVolume)); } } delete mPlayObject; mPlayObject = 0; delete mArtsDispatcher; mArtsDispatcher = 0; if (!mLocalAudioFile.isEmpty()) { KIO::NetAccess::removeTempFile(mLocalAudioFile); // removes it only if it IS a temporary file mLocalAudioFile = QString::null; } if (mSilenceButton) mSilenceButton->setEnabled(false); #endif } /****************************************************************************** * Called every second to fade the volume when the audio file starts playing. */ void MessageWin::slotFade() { #ifndef WITHOUT_ARTS QTime now = QTime::currentTime(); int elapsed = mAudioFileStart.secsTo(now); if (elapsed < 0) elapsed += 86400; // it's the next day float volume; if (elapsed >= mFadeSeconds) { // The fade has finished. Set to normal volume. volume = mVolume; delete mFadeTimer; mFadeTimer = 0; if (!mVolume) { kdDebug(5950) << "MessageWin::slotFade(0)\n"; stopPlay(); return; } } else volume = mFadeVolume + ((mVolume - mFadeVolume) * elapsed) / mFadeSeconds; kdDebug(5950) << "MessageWin::slotFade(" << volume << ")\n"; if (mArtsDispatcher) { if (mUsingKMix) setKMixVolume(static_cast(volume * 100)); else if (mArtsDispatcher) { KArtsServer aserver; aserver.server().outVolume().scaleFactor(volume); } } #endif } #ifndef WITHOUT_ARTS /****************************************************************************** * Get the master volume from KMix. * Reply < 0 if failure. */ int MessageWin::getKMixVolume() { if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError)) // start KMix if it isn't already running return -1; QByteArray data, replyData; QCString replyType; QDataStream arg(data, IO_WriteOnly); if (!kapp->dcopClient()->call(mKMixName, KMIX_DCOP_OBJECT, "masterVolume()", data, replyType, replyData) || replyType != "int") return -1; int result; QDataStream reply(replyData, IO_ReadOnly); reply >> result; return (result >= 0) ? result : 0; } /****************************************************************************** * Set the master volume using KMix. */ void MessageWin::setKMixVolume(int percent) { if (!mUsingKMix) return; if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError)) // start KMix if it isn't already running return; QByteArray data; QDataStream arg(data, IO_WriteOnly); arg << percent; if (!kapp->dcopClient()->send(mKMixName, KMIX_DCOP_OBJECT, "setMasterVolume(int)", data)) kdError(5950) << "MessageWin::setKMixVolume(): kmix dcop call failed\n"; } #endif /****************************************************************************** * Raise the alarm window, re-output any required audio notification, and * reschedule the alarm in the calendar file. */ void MessageWin::repeat(const KAAlarm& alarm) { if (mDeferDlg) { // Cancel any deferral dialogue so that the user notices something's going on, // and also because the deferral time limit will have changed. delete mDeferDlg; mDeferDlg = 0; } const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID); if (kcalEvent) { mAlarmType = alarm.type(); // store new alarm type for use if it is later deferred if (!mDeferDlg || Preferences::modalMessages()) { raise(); playAudio(); } KAEvent event(*kcalEvent); mDeferButton->setEnabled(true); setDeferralLimit(event); // ensure that button is disabled when alarm can't be deferred any more theApp()->alarmShowing(event, mAlarmType, mDateTime); } } /****************************************************************************** * Display the window. * If windows are being positioned away from the mouse cursor, it is initially * positioned at the top left to slightly reduce the number of times the * windows need to be moved in showEvent(). */ void MessageWin::show() { if (Preferences::messageButtonDelay() == 0) move(0, 0); MainWindowBase::show(); } /****************************************************************************** * Returns the window's recommended size exclusive of its frame. * For message windows, the size if limited to fit inside the working area of * the desktop. */ QSize MessageWin::sizeHint() const { if (mAction != KAEvent::MESSAGE) return MainWindowBase::sizeHint(); if (!mWinModule) mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP); QSize frame = frameGeometry().size(); QSize contents = geometry().size(); QSize desktop = mWinModule->workArea().size(); QSize maxSize(desktop.width() - (frame.width() - contents.width()), desktop.height() - (frame.height() - contents.height())); return MainWindowBase::sizeHint().boundedTo(maxSize); } /****************************************************************************** * Called when the window is shown. * The first time, output any required audio notification, and reschedule or * delete the event from the calendar file. */ void MessageWin::showEvent(QShowEvent* se) { MainWindowBase::showEvent(se); if (!mShown) { if (mErrorWindow) enableButtons(); // don't bother repositioning error messages else { /* Set the window size. * Note that the frame thickness is not yet known when this * method is called, so for large windows the size needs to be * set again later. */ QSize s = sizeHint(); // fit the window round the message if (mAction == KAEvent::FILE && !mErrorMsgs.count()) KAlarm::readConfigWindowSize("FileMessage", s); resize(s); mButtonDelay = Preferences::messageButtonDelay() * 1000; if (!mButtonDelay) { /* Try to ensure that the window can't accidentally be acknowledged * by the user clicking the mouse just as it appears. * To achieve this, move the window so that the OK button is as far away * from the cursor as possible. If the buttons are still too close to the * cursor, disable the buttons for a short time. * N.B. This can't be done in show(), since the geometry of the window * is not known until it is displayed. Unfortunately by moving the * window in showEvent(), a flicker is unavoidable. * See the Qt documentation on window geometry for more details. */ // PROBLEM: The frame size is not known yet! if (!mWinModule) mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP); QRect desk = mWinModule->workArea(); QPoint cursor = QCursor::pos(); QRect frame = frameGeometry(); QRect rect = geometry(); // Find the offsets from the outside of the frame to the edges of the OK button QRect button(mOkButton->mapToParent(QPoint(0, 0)), mOkButton->mapToParent(mOkButton->rect().bottomRight())); int buttonLeft = button.left() + rect.left() - frame.left(); int buttonRight = width() - button.right() + frame.right() - rect.right(); int buttonTop = button.top() + rect.top() - frame.top(); int buttonBottom = height() - button.bottom() + frame.bottom() - rect.bottom(); int centrex = (desk.width() + buttonLeft - buttonRight) / 2; int centrey = (desk.height() + buttonTop - buttonBottom) / 2; int x = (cursor.x() < centrex) ? desk.right() - frame.width() : desk.left(); int y = (cursor.y() < centrey) ? desk.bottom() - frame.height() : desk.top(); // Find the enclosing rectangle for the new button positions // and check if the cursor is too near QRect buttons = mOkButton->geometry().unite(mKAlarmButton->geometry()); buttons.moveBy(rect.left() + x - frame.left(), rect.top() + y - frame.top()); int minDistance = proximityMultiple * mOkButton->height(); if ((abs(cursor.x() - buttons.left()) < minDistance || abs(cursor.x() - buttons.right()) < minDistance) && (abs(cursor.y() - buttons.top()) < minDistance || abs(cursor.y() - buttons.bottom()) < minDistance)) mButtonDelay = proximityButtonDelay; // too near - disable buttons initially if (x != frame.left() || y != frame.top()) { mPositioning = true; move(x, y); } } if (!mPositioning) displayComplete(); // play audio, etc. if (mAction == KAEvent::MESSAGE) { // Set the window size once the frame size is known QTimer::singleShot(0, this, SLOT(setMaxSize())); } } mShown = true; } } /****************************************************************************** * Called when the window has been moved. */ void MessageWin::moveEvent(QMoveEvent* e) { MainWindowBase::moveEvent(e); if (mPositioning) { // The window has just been initially positioned mPositioning = false; displayComplete(); // play audio, etc. } } /****************************************************************************** * Reset the iniital window size if it exceeds the working area of the desktop. */ void MessageWin::setMaxSize() { QSize s = sizeHint(); if (width() > s.width() || height() > s.height()) resize(s); } /****************************************************************************** * Called when the window has been displayed properly (in its correct position), * to play sounds and reschedule the event. */ void MessageWin::displayComplete() { playAudio(); if (mRescheduleEvent) theApp()->alarmShowing(mEvent, mAlarmType, mDateTime); // Enable the window's buttons either now or after the configured delay if (mButtonDelay > 0) QTimer::singleShot(mButtonDelay, this, SLOT(enableButtons())); else enableButtons(); } /****************************************************************************** * Enable the window's buttons. */ void MessageWin::enableButtons() { mOkButton->setEnabled(true); mKAlarmButton->setEnabled(true); if (mDeferButton) mDeferButton->setEnabled(true); if (mEditButton) mEditButton->setEnabled(true); if (mKMailButton) mKMailButton->setEnabled(true); } /****************************************************************************** * Called when the window's size has changed (before it is painted). */ void MessageWin::resizeEvent(QResizeEvent* re) { if (mRestoreHeight) { // Restore the window height on session restoration if (mRestoreHeight != re->size().height()) { QSize size = re->size(); size.setHeight(mRestoreHeight); resize(size); } else if (isVisible()) mRestoreHeight = 0; } else { if (mShown && mAction == KAEvent::FILE && !mErrorMsgs.count()) KAlarm::writeConfigWindowSize("FileMessage", re->size()); MainWindowBase::resizeEvent(re); } } /****************************************************************************** * Called when a close event is received. * Only quits the application if there is no system tray icon displayed. */ void MessageWin::closeEvent(QCloseEvent* ce) { if (mConfirmAck && !mNoCloseConfirm && !theApp()->sessionClosingDown()) { // Ask for confirmation of acknowledgement. Use warningYesNo() because its default is No. if (KMessageBox::warningYesNo(this, i18n("Do you really want to acknowledge this alarm?"), i18n("Acknowledge Alarm"), i18n("&Acknowledge"), KStdGuiItem::cancel()) != KMessageBox::Yes) { ce->ignore(); return; } } if (!mEventID.isNull()) { // Delete from the display calendar KAlarm::deleteDisplayEvent(KAEvent::uid(mEventID, KAEvent::DISPLAYING)); } MainWindowBase::closeEvent(ce); } /****************************************************************************** * Called when the KMail button is clicked. * Tells KMail to display the email message displayed in this message window. */ void MessageWin::slotShowKMailMessage() { kdDebug(5950) << "MessageWin::slotShowKMailMessage()\n"; if (!mKMailSerialNumber) return; QString err = KAlarm::runKMail(false); if (!err.isNull()) { KMessageBox::sorry(this, err); return; } QCString replyType; QByteArray data, replyData; QDataStream arg(data, IO_WriteOnly); arg << (Q_UINT32)mKMailSerialNumber << QString::null; if (kapp->dcopClient()->call("kmail", KMAIL_DCOP_OBJECT, "showMail(Q_UINT32,QString)", data, replyType, replyData) && replyType == "bool") { bool result; QDataStream replyStream(replyData, IO_ReadOnly); replyStream >> result; if (result) return; // success } kdError(5950) << "MessageWin::slotShowKMailMessage(): kmail dcop call failed\n"; KMessageBox::sorry(this, i18n("Unable to locate this email in KMail")); } /****************************************************************************** * Called when the Edit... button is clicked. * Displays the alarm edit dialog. */ void MessageWin::slotEdit() { EditAlarmDlg editDlg(false, i18n("Edit Alarm"), this, "editDlg", &mEvent); if (editDlg.exec() == QDialog::Accepted) { KAEvent event; editDlg.getEvent(event); // Update the displayed lists and the calendar file KAlarm::UpdateStatus status; if (AlarmCalendar::activeCalendar()->event(mEventID)) { // The old alarm hasn't expired yet, so replace it status = KAlarm::modifyEvent(mEvent, event, 0); Undo::saveEdit(mEvent, event); } else { // The old event has expired, so simply create a new one status = KAlarm::addEvent(event, 0); Undo::saveAdd(event); } if (status == KAlarm::UPDATE_KORG_ERR) KAlarm::displayUpdateError(this, KAlarm::KORG_ERR_MODIFY); KAlarm::outputAlarmWarnings(&editDlg, &event); // Close the alarm window mNoCloseConfirm = true; // allow window to close without confirmation prompt close(); } } /****************************************************************************** * Set up to disable the defer button when the deferral limit is reached. */ void MessageWin::setDeferralLimit(const KAEvent& event) { if (mDeferButton) { mDeferLimit = event.deferralLimit().dateTime(); MidnightTimer::connect(this, SLOT(checkDeferralLimit())); // check every day checkDeferralLimit(); } } /****************************************************************************** * Check whether the deferral limit has been reached. * If so, disable the Defer button. * N.B. Ideally, just a single QTimer::singleShot() call would be made to disable * the defer button at the corret time. But for a 32-bit integer, the * milliseconds parameter overflows in about 25 days, so instead a daily * check is done until the day when the deferral limit is reached, followed * by a non-overflowing QTimer::singleShot() call. */ void MessageWin::checkDeferralLimit() { if (!mDeferButton || !mDeferLimit.isValid()) return; int n = QDate::currentDate().daysTo(mDeferLimit.date()); if (n > 0) return; MidnightTimer::disconnect(this, SLOT(checkDeferralLimit())); if (n == 0) { // The deferral limit will be reached today n = QTime::currentTime().secsTo(mDeferLimit.time()); if (n > 0) { QTimer::singleShot(n * 1000, this, SLOT(checkDeferralLimit())); return; } } mDeferButton->setEnabled(false); } /****************************************************************************** * Called when the Defer... button is clicked. * Displays the defer message dialog. */ void MessageWin::slotDefer() { mDeferDlg = new DeferAlarmDlg(i18n("Defer Alarm"), QDateTime::currentDateTime().addSecs(60), false, this, "deferDlg"); mDeferDlg->setLimit(mEventID); if (!Preferences::modalMessages()) lower(); if (mDeferDlg->exec() == QDialog::Accepted) { DateTime dateTime = mDeferDlg->getDateTime(); const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID); if (kcalEvent) { // The event still exists in the calendar file. KAEvent event(*kcalEvent); bool repeat = event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true); KAlarm::updateEvent(event, 0, true, !repeat); } else { KAEvent event; kcalEvent = AlarmCalendar::displayCalendar()->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING)); if (kcalEvent) { event.reinstateFromDisplaying(KAEvent(*kcalEvent)); event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true); } else { // The event doesn't exist any more !?!, so create a new one event.set(dateTime.dateTime(), mMessage, mBgColour, mFgColour, mFont, mAction, mLateCancel, mFlags); event.setAudioFile(mAudioFile, mVolume, mFadeVolume, mFadeSeconds); event.setArchive(); event.setEventID(mEventID); } // Add the event back into the calendar file, retaining its ID // and not updating KOrganizer KAlarm::addEvent(event, 0, true, false); if (kcalEvent) { event.setUid(KAEvent::EXPIRED); KAlarm::deleteEvent(event, false); } } if (theApp()->wantRunInSystemTray()) { // Alarms are to be displayed only if the system tray icon is running, // so start it if necessary so that the deferred alarm will be shown. theApp()->displayTrayIcon(true); } mNoCloseConfirm = true; // allow window to close without confirmation prompt close(); } else raise(); delete mDeferDlg; mDeferDlg = 0; } /****************************************************************************** * Called when the KAlarm icon button in the message window is clicked. * Displays the main window, with the appropriate alarm selected. */ void MessageWin::displayMainWindow() { KAlarm::displayMainWindowSelected(mEventID); } /*============================================================================= = Class MWMimeSourceFactory * Gets the mime type of a text file from not only its extension (as per * QMimeSourceFactory), but also from its contents. This allows the detection * of plain text files without file name extensions. =============================================================================*/ MWMimeSourceFactory::MWMimeSourceFactory(const QString& absPath, KTextBrowser* view) : QMimeSourceFactory(), mMimeType("text/plain"), mLast(0) { view->setMimeSourceFactory(this); QString type = KMimeType::findByPath(absPath)->name(); switch (KAlarm::fileType(type)) { case KAlarm::TextPlain: case KAlarm::TextFormatted: mMimeType = type.latin1(); // fall through to 'TextApplication' case KAlarm::TextApplication: default: // It's assumed to be a text file mTextFile = absPath; view->QTextBrowser::setSource(absPath); break; case KAlarm::Image: // It's an image file QString text = ""; view->setText(text); break; } setFilePath(QFileInfo(absPath).dirPath(true)); } MWMimeSourceFactory::~MWMimeSourceFactory() { delete mLast; } const QMimeSource* MWMimeSourceFactory::data(const QString& abs_name) const { if (abs_name == mTextFile) { QFileInfo fi(abs_name); if (fi.isReadable()) { QFile f(abs_name); if (f.open(IO_ReadOnly) && f.size()) { QByteArray ba(f.size()); f.readBlock(ba.data(), ba.size()); QStoredDrag* sr = new QStoredDrag(mMimeType); sr->setEncodedData(ba); delete mLast; mLast = sr; return sr; } } } return QMimeSourceFactory::data(abs_name); } diff --git a/karm/printdialog.cpp b/karm/printdialog.cpp index 51603a8c55..b2e4635d9a 100644 --- a/karm/printdialog.cpp +++ b/karm/printdialog.cpp @@ -1,117 +1,117 @@ /* * This file only: * Copyright (C) 2003 Mark Bucciarelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include // i18n #include #include "printdialog.h" #include PrintDialog::PrintDialog() : KDialogBase(0, "PrintDialog", true, i18n("Print Dialog"), Ok|Cancel, Ok, true ) { QWidget *page = new QWidget( this ); setMainWidget(page); int year, month; QVBoxLayout *layout = new QVBoxLayout(page, KDialog::spacingHint()); layout->addSpacing(10); layout->addStretch(1); // Date Range QGroupBox *rangeGroup = new QGroupBox(1, Horizontal, i18n("Date Range"), page); layout->addWidget(rangeGroup); QWidget *rangeWidget = new QWidget(rangeGroup); QHBoxLayout *rangeLayout = new QHBoxLayout(rangeWidget, 0, spacingHint()); rangeLayout->addWidget(new QLabel(i18n("From:"), rangeWidget)); _from = new KDateEdit(rangeWidget); // Default from date to beginning of the month year = QDate::currentDate().year(); month = QDate::currentDate().month(); _from->setDate(QDate(year, month, 1)); rangeLayout->addWidget(_from); rangeLayout->addWidget(new QLabel(i18n("To:"), rangeWidget)); _to = new KDateEdit(rangeWidget); rangeLayout->addWidget(_to); layout->addSpacing(10); layout->addStretch(1); _allTasks = new QComboBox( page ); _allTasks->insertItem( i18n( "Selected Task" ) ); _allTasks->insertItem( i18n( "All Tasks" ) ); layout->addWidget( _allTasks ); _perWeek = new QCheckBox( i18n( "Summarize per week" ), page ); layout->addWidget( _perWeek ); - _totalsOnly = new QCheckBox( i18n( "Totals Only" ), page ); + _totalsOnly = new QCheckBox( i18n( "Totals only" ), page ); layout->addWidget( _totalsOnly ); layout->addSpacing(10); layout->addStretch(1); } QDate PrintDialog::from() const { return _from->date(); } QDate PrintDialog::to() const { return _to->date(); } bool PrintDialog::perWeek() const { return _perWeek->isChecked(); } bool PrintDialog::allTasks() const { return _allTasks->currentItem() == 1; } bool PrintDialog::totalsOnly() const { return _totalsOnly->isChecked(); } #include "printdialog.moc" diff --git a/kitchensync/libkonnector2/filters/calendarfilter.cpp b/kitchensync/libkonnector2/filters/calendarfilter.cpp index f6ac68154f..fbbb12c210 100644 --- a/kitchensync/libkonnector2/filters/calendarfilter.cpp +++ b/kitchensync/libkonnector2/filters/calendarfilter.cpp @@ -1,280 +1,280 @@ /* This file is part of KitchenSync. Copyright (c) 2005 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "calendarsyncee.h" #include "calendarfilter.h" using namespace KSync; K_EXPORT_KS_FILTER( libksfilter_calendar, CalendarFilter ) CalendarFilter::CalendarFilter( QObject *parent ) : Filter( parent, "CalendarFilter" ) { setName( i18n( "Calendar Filter" ) ); } CalendarFilter::~CalendarFilter() { } bool CalendarFilter::supports( Syncee *syncee ) { return (dynamic_cast( syncee ) != 0); } QWidget *CalendarFilter::configWidget( QWidget *parent ) { CalendarConfigWidget *wdg = new CalendarConfigWidget( parent, "CalendarConfigWidget" ); KPimPrefs prefs; prefs.usrReadConfig(); wdg->setCategories( prefs.mCustomCategories ); wdg->setSelectedCategories( mSelectedCategories ); wdg->setUseDate( mFilterByDate ); wdg->setStartDate( mStartDate ); wdg->setEndDate( mEndDate ); return wdg; } void CalendarFilter::configWidgetClosed( QWidget *widget ) { CalendarConfigWidget *wdg = static_cast( widget ); mSelectedCategories = wdg->selectedCategories(); mFilterByDate = wdg->useDate(); mStartDate = wdg->startDate(); mEndDate = wdg->endDate(); } void CalendarFilter::convert( Syncee *syncee ) { filterSyncee( dynamic_cast( syncee ), mSelectedCategories, mStartDate, mEndDate ); } void CalendarFilter::reconvert( Syncee *syncee ) { unfilterSyncee( dynamic_cast( syncee ) ); } void CalendarFilter::doLoad() { mSelectedCategories = config()->readListEntry( "SelectedCategories" ); mFilterByDate = config()->readBoolEntry( "FilterByDate", false ); mStartDate = config()->readDateTimeEntry( "StartDate" ).date(); mEndDate = config()->readDateTimeEntry( "EndDate" ).date(); } void CalendarFilter::doSave() { config()->writeEntry( "SelectedCategories", mSelectedCategories ); config()->writeEntry( "FilterByDate", mFilterByDate ); config()->writeEntry( "StartDate", QDateTime( mStartDate ) ); config()->writeEntry( "EndDate", QDateTime( mEndDate ) ); } void CalendarFilter::filterSyncee( CalendarSyncee *syncee, const QStringList &categories, const QDate &startDate, const QDate &endDate ) { mFilteredEntries.clear(); if ( categories.isEmpty() ) // do not filter return; QStringList::ConstIterator it; CalendarSyncEntry *entry; for ( entry = syncee->firstEntry(); entry; entry = syncee->nextEntry() ) { bool found = false; for ( it = categories.begin(); it != categories.end(); ++it ) if ( entry->incidence()->categories().contains( *it ) ) { if ( mFilterByDate ) { if ( entry->incidence()->dtStart().date() >= startDate && entry->incidence()->dtStart().date() <= endDate ) found = true; } else found = true; break; } if ( !found ) mFilteredEntries.append( entry ); } QPtrListIterator entryIt( mFilteredEntries ); while ( entryIt.current() ) { syncee->removeEntry( entryIt.current() ); ++entryIt; } } void CalendarFilter::unfilterSyncee( CalendarSyncee *syncee ) { QPtrListIterator entryIt( mFilteredEntries ); while ( entryIt.current() ) { syncee->addEntry( entryIt.current() ); ++entryIt; } } CalendarConfigWidget::CalendarConfigWidget( QWidget *parent, const char *name ) : QWidget( parent, name ) { QVBoxLayout *layout = new QVBoxLayout( this ); - QGroupBox *box = new QGroupBox( 2, Qt::Vertical, i18n( "Events and Todos" ), this ); + QGroupBox *box = new QGroupBox( 2, Qt::Vertical, i18n( "Events && Todos" ), this ); mView = new KListView( box ); mView->addColumn( i18n( "Categories" ) ); mView->setFullWidth( true ); QWhatsThis::add( mView, i18n( "Select the categories for which the events and todos shall be synchronized. When no category is selected, all events and todos will be included." ) ); QWidget *timeWidget = new QWidget( box ); QGridLayout *wdgLayout = new QGridLayout( timeWidget, 3, 3, KDialog::marginHint(), KDialog::spacingHint() ); mUseDate = new QCheckBox( i18n( "Use time range" ), timeWidget ); wdgLayout->addMultiCellWidget( mUseDate, 0, 0, 0, 1 ); QWhatsThis::add( mUseDate, i18n( "Synchronize only events and todos in a special time range." ) ); mStartLabel = new QLabel( i18n( "start date", "From:" ), timeWidget ); mStartDate = new KDateEdit( timeWidget ); mStartLabel->setBuddy( mStartDate ); mEndLabel = new QLabel( i18n( "end date", "Till:" ), timeWidget ); mEndDate = new KDateEdit( timeWidget ); mEndLabel->setBuddy( mEndDate ); wdgLayout->addWidget( mStartLabel, 1, 0, Qt::AlignRight ); wdgLayout->addWidget( mStartDate, 1, 1 ); wdgLayout->addWidget( mEndLabel, 2, 0, Qt::AlignRight ); wdgLayout->addWidget( mEndDate, 2, 1 ); wdgLayout->setColStretch( 2, 10 ); QWhatsThis::add( box, i18n( "Only the events and todos in the given date range will be synchronized." ) ); layout->addWidget( box ); connect( mUseDate, SIGNAL( toggled( bool ) ), this, SLOT( useDateChanged( bool ) ) ); } void CalendarConfigWidget::setCategories( const QStringList &categories ) { mView->clear(); QStringList::ConstIterator it; for ( it = categories.begin(); it != categories.end(); ++it ) new QCheckListItem( mView, *it, QCheckListItem::CheckBox ); } void CalendarConfigWidget::setSelectedCategories( const QStringList &categories ) { QListViewItemIterator itemIt( mView ); QStringList::ConstIterator it; while ( itemIt.current() ) { bool found = false; for ( it = categories.begin(); it != categories.end(); ++it ) { if ( itemIt.current()->text( 0 ) == *it ) { found = true; break; } } QCheckListItem *item = static_cast( itemIt.current() ); item->setOn( found ); ++itemIt; } } QStringList CalendarConfigWidget::selectedCategories() const { QStringList categories; QListViewItemIterator itemIt( mView, QListViewItemIterator::Checked ); while ( itemIt.current() ) categories.append( itemIt.current()->text( 0 ) ); return categories; } void CalendarConfigWidget::setStartDate( const QDate &date ) { mStartDate->setDate( date ); } QDate CalendarConfigWidget::startDate() const { return mStartDate->date(); } void CalendarConfigWidget::setEndDate( const QDate &date ) { mEndDate->setDate( date ); } QDate CalendarConfigWidget::endDate() const { return mEndDate->date(); } void CalendarConfigWidget::setUseDate( bool value ) { mUseDate->setChecked( value ); useDateChanged( value ); } bool CalendarConfigWidget::useDate() const { return mUseDate->isChecked(); } void CalendarConfigWidget::useDateChanged( bool value ) { mStartLabel->setEnabled( value ); mStartDate->setEnabled( value ); mEndDate->setEnabled( value ); mEndLabel->setEnabled( value ); } #include "calendarfilter.moc" diff --git a/kitchensync/libkonnector2/plugins/local/localkonnector.cpp b/kitchensync/libkonnector2/plugins/local/localkonnector.cpp index 54be2ba445..9dfcc324b7 100644 --- a/kitchensync/libkonnector2/plugins/local/localkonnector.cpp +++ b/kitchensync/libkonnector2/plugins/local/localkonnector.cpp @@ -1,225 +1,225 @@ /* This file is part of KitchenSync. Copyright (c) 2003 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "localkonnector.h" #include "localkonnectorconfig.h" #include #include #include #include #include #include #include #include #include #include using namespace KSync; extern "C" { void *init_liblocalkonnector() { KGlobal::locale()->insertCatalogue( "konnector_local" ); return new KRES::PluginFactory(); } } LocalKonnector::LocalKonnector( const KConfig *config ) : Konnector( config ), mConfigWidget( 0 ), mCalendar( KPimPrefs::timezone() ), mProgressItem( 0 ) { if ( config ) { mCalendarFile = config->readPathEntry( "CalendarFile" ); mAddressBookFile = config->readPathEntry( "AddressBookFile" ); mBookmarkFile = config->readPathEntry( "BookmarkFile" ); } mMd5sumCal = generateMD5Sum( mCalendarFile ) + "_localkonnector_cal.log"; mMd5sumAbk = generateMD5Sum( mAddressBookFile ) + "_localkonnector_abk.log"; mMd5sumBkm = generateMD5Sum( mBookmarkFile ) + "_localkonnector_bkm.log"; mAddressBookSyncee = new AddressBookSyncee( &mAddressBook ); mAddressBookSyncee->setTitle( i18n( "Local" ) ); mCalendarSyncee = new CalendarSyncee( &mCalendar ); mCalendarSyncee->setTitle( i18n( "Local" ) ); mSyncees.append( mCalendarSyncee ); mSyncees.append( mAddressBookSyncee ); mSyncees.append( new BookmarkSyncee( &mBookmarkManager ) ); mAddressBookResourceFile = new KABC::ResourceFile( mAddressBookFile ); mAddressBook.addResource( mAddressBookResourceFile ); } LocalKonnector::~LocalKonnector() { } void LocalKonnector::writeConfig( KConfig *config ) { Konnector::writeConfig( config ); config->writePathEntry( "CalendarFile", mCalendarFile ); config->writePathEntry( "AddressBookFile", mAddressBookFile ); config->writePathEntry( "BookmarkFile", mAddressBookFile ); } bool LocalKonnector::readSyncees() { kdDebug() << "LocalKonnector::readSyncee()" << endl; mProgressItem = progressItem( i18n( "Start loading local data..." ) ); if ( !mCalendarFile.isEmpty() ) { kdDebug() << "LocalKonnector::readSyncee(): calendar: " << mCalendarFile << endl; mCalendar.close(); mProgressItem->setStatus( i18n( "Load Calendar..." ) ); if ( mCalendar.load( mCalendarFile ) ) { kdDebug() << "Read succeeded." << endl; mCalendarSyncee->reset(); mCalendarSyncee->setIdentifier( mCalendarFile ); kdDebug() << "IDENTIFIER: " << mCalendarSyncee->identifier() << endl; /* apply SyncInformation here this will also create the SyncEntries */ CalendarSyncHistory cHelper( mCalendarSyncee, storagePath() + "/"+mMd5sumCal ); cHelper.load(); mProgressItem->setStatus( i18n( "Calendar loaded." ) ); } else { - mProgressItem->setStatus( i18n( "Loading Calendar failed." ) ); + mProgressItem->setStatus( i18n( "Loading calendar failed." ) ); emit synceeReadError( this ); kdDebug() << "Read failed." << endl; return false; } } mProgressItem->setProgress( 50 ); if ( !mAddressBookFile.isEmpty() ) { kdDebug() << "LocalKonnector::readSyncee(): addressbook: " << mAddressBookFile << endl; mProgressItem->setStatus( i18n( "Load AddressBook..." ) ); mAddressBookResourceFile->setFileName( mAddressBookFile ); if ( !mAddressBook.load() ) { mProgressItem->setStatus( i18n( "Loading AddressBook failed." ) ); emit synceeReadError( this ); kdDebug() << "Read failed." << endl; return false; } kdDebug() << "Read succeeded." << endl; mAddressBookSyncee->reset(); mAddressBookSyncee->setIdentifier( mAddressBook.identifier() ); kdDebug() << "IDENTIFIER: " << mAddressBookSyncee->identifier() << endl; KABC::AddressBook::Iterator it; for ( it = mAddressBook.begin(); it != mAddressBook.end(); ++it ) { KSync::AddressBookSyncEntry entry( *it, mAddressBookSyncee ); mAddressBookSyncee->addEntry( entry.clone() ); } /* let us apply Sync Information */ AddressBookSyncHistory aHelper( mAddressBookSyncee, storagePath() + "/"+mMd5sumAbk ); aHelper.load(); mProgressItem->setStatus( i18n( "AddressBook loaded." ) ); } // TODO: Read Bookmarks mProgressItem->setProgress( 100 ); mProgressItem->setComplete(); mProgressItem = 0; emit synceesRead( this ); return true; } bool LocalKonnector::connectDevice() { return true; } bool LocalKonnector::disconnectDevice() { return true; } KSync::KonnectorInfo LocalKonnector::info() const { return KonnectorInfo( i18n("Dummy Konnector"), QIconSet(), "agenda", // icon name false ); } QStringList LocalKonnector::supportedFilterTypes() const { QStringList types; types << "addressbook" << "calendar" << "bookmarks"; return types; } bool LocalKonnector::writeSyncees() { if ( !mCalendarFile.isEmpty() ) { purgeRemovedEntries( mCalendarSyncee ); if ( !mCalendar.save( mCalendarFile ) ) return false; CalendarSyncHistory cHelper( mCalendarSyncee, storagePath() + "/"+mMd5sumCal ); cHelper.save(); } if ( !mAddressBookFile.isEmpty() ) { purgeRemovedEntries( mAddressBookSyncee ); KABC::Ticket *ticket; ticket = mAddressBook.requestSaveTicket( mAddressBookResourceFile ); if ( !ticket ) { kdWarning() << "LocalKonnector::writeSyncees(). Couldn't get ticket for " << "addressbook." << endl; emit synceeWriteError( this ); return false; } if ( !mAddressBook.save( ticket ) ) return false; AddressBookSyncHistory aHelper( mAddressBookSyncee, storagePath() + "/"+mMd5sumAbk ); aHelper.save(); } // TODO: Write Bookmarks emit synceesWritten( this ); return true; } #include "localkonnector.moc" diff --git a/kmail/configuredialog.cpp b/kmail/configuredialog.cpp index aabc78fb17..7d98becb84 100644 --- a/kmail/configuredialog.cpp +++ b/kmail/configuredialog.cpp @@ -1,4767 +1,4767 @@ /* -*- mode: C++; c-file-style: "gnu" -*- * kmail: KDE mail client * This file: Copyright (C) 2000 Espen Sand, espen@kde.org * Copyright (C) 2001-2003 Marc Mutz, mutz@kde.org * Contains code segments and ideas from earlier kmail dialog code. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ // This must be first #include // my headers: #include "configuredialog.h" #include "configuredialog_p.h" #include "globalsettings.h" #include "replyphrases.h" // other KMail headers: #include "kmkernel.h" #include "simplestringlisteditor.h" #include "accountdialog.h" using KMail::AccountDialog; #include "colorlistbox.h" #include "kmacctseldlg.h" #include "messagesender.h" #include "kmtransport.h" #include "kmfoldermgr.h" #include #include "identitylistview.h" using KMail::IdentityListView; using KMail::IdentityListViewItem; #include "kcursorsaver.h" #include "accountmanager.h" #include #include #include #include "folderrequester.h" using KMail::FolderRequester; #include "accountcombobox.h" #include "imapaccountbase.h" using KMail::ImapAccountBase; #include "folderstorage.h" #include "kmfolder.h" #include "kmmainwidget.h" #include "recentaddresses.h" using KRecentAddress::RecentAddresses; #include "completionordereditor.h" #include "ldapclient.h" using KMail::IdentityListView; using KMail::IdentityListViewItem; #include "identitydialog.h" using KMail::IdentityDialog; // other kdenetwork headers: #include #include using KMime::DateFormatter; #include #include #include #include #include // other KDE headers: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt headers: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // other headers: #include #include #ifndef _PATH_SENDMAIL #define _PATH_SENDMAIL "/usr/sbin/sendmail" #endif #ifdef DIM #undef DIM #endif #define DIM(x) sizeof(x) / sizeof(*x) namespace { struct EnumConfigEntryItem { const char * key; // config key value, as appears in config file const char * desc; // description, to be i18n()ized }; struct EnumConfigEntry { const char * group; const char * key; const char * desc; const EnumConfigEntryItem * items; int numItems; int defaultItem; }; struct BoolConfigEntry { const char * group; const char * key; const char * desc; bool defaultValue; }; static const char * lockedDownWarning = I18N_NOOP("

This setting has been fixed by your administrator.

" "

If you think this is an error, please contact him.

"); void checkLockDown( QWidget * w, const KConfigBase & c, const char * key ) { if ( c.entryIsImmutable( key ) ) { w->setEnabled( false ); QToolTip::add( w, i18n( lockedDownWarning ) ); } else { QToolTip::remove( w ); } } void populateButtonGroup( QButtonGroup * g, const EnumConfigEntry & e ) { g->setTitle( i18n( e.desc ) ); g->layout()->setSpacing( KDialog::spacingHint() ); for ( int i = 0 ; i < e.numItems ; ++i ) g->insert( new QRadioButton( i18n( e.items[i].desc ), g ), i ); } void populateCheckBox( QCheckBox * b, const BoolConfigEntry & e ) { b->setText( i18n( e.desc ) ); } void loadWidget( QCheckBox * b, const KConfigBase & c, const BoolConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); checkLockDown( b, c, e.key ); b->setChecked( c.readBoolEntry( e.key, e.defaultValue ) ); } void loadWidget( QButtonGroup * g, const KConfigBase & c, const EnumConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); Q_ASSERT( g->count() == e.numItems ); checkLockDown( g, c, e.key ); const QString s = c.readEntry( e.key, e.items[e.defaultItem].key ); for ( int i = 0 ; i < e.numItems ; ++i ) if ( s == e.items[i].key ) { g->setButton( i ); return; } g->setButton( e.defaultItem ); } void saveCheckBox( QCheckBox * b, KConfigBase & c, const BoolConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); c.writeEntry( e.key, b->isChecked() ); } void saveButtonGroup( QButtonGroup * g, KConfigBase & c, const EnumConfigEntry & e ) { Q_ASSERT( c.group() == e.group ); Q_ASSERT( g->count() == e.numItems ); c.writeEntry( e.key, e.items[ g->id( g->selected() ) ].key ); } template inline void loadProfile( T_Widget * g, const KConfigBase & c, const T_Entry & e ) { if ( c.hasKey( e.key ) ) loadWidget( g, c, e ); } } ConfigureDialog::ConfigureDialog( QWidget *parent, const char *name, bool modal ) : KCMultiDialog( KDialogBase::IconList, KGuiItem( i18n( "&Load Profile..." ) ), KGuiItem(), User2, i18n( "Configure" ), parent, name, modal ) , mProfileDialog( 0 ) { KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() ); showButton( User1, true ); addModule ( "kmail_config_identity", false ); addModule ( "kmail_config_accounts", false ); addModule ( "kmail_config_appearance", false ); addModule ( "kmail_config_composer", false ); addModule ( "kmail_config_security", false ); addModule ( "kmail_config_misc", false ); // We store the size of the dialog on hide, because otherwise // the KCMultiDialog starts with the size of the first kcm, not // the largest one. This way at least after the first showing of // the largest kcm the size is kept. KConfigGroup geometry( KMKernel::config(), "Geometry" ); int width = geometry.readNumEntry( "ConfigureDialogWidth" ); int height = geometry.readNumEntry( "ConfigureDialogHeight" ); if ( width != 0 && height != 0 ) { setMinimumSize( width, height ); } } void ConfigureDialog::hideEvent( QHideEvent *ev ) { KConfigGroup geometry( KMKernel::config(), "Geometry" ); geometry.writeEntry( "ConfigureDialogWidth", width() ); geometry.writeEntry( "ConfigureDialogHeight",height() ); KDialogBase::hideEvent( ev ); } ConfigureDialog::~ConfigureDialog() { } void ConfigureDialog::slotApply() { GlobalSettings::self()->writeConfig(); KCMultiDialog::slotApply(); } void ConfigureDialog::slotOk() { GlobalSettings::self()->writeConfig(); KCMultiDialog::slotOk(); } void ConfigureDialog::slotUser2() { if ( mProfileDialog ) { mProfileDialog->raise(); return; } mProfileDialog = new ProfileDialog( this, "mProfileDialog" ); connect( mProfileDialog, SIGNAL(profileSelected(KConfig*)), this, SIGNAL(installProfile(KConfig*)) ); mProfileDialog->show(); } // ************************************************************* // * * // * IdentityPage * // * * // ************************************************************* QString IdentityPage::helpAnchor() const { return QString::fromLatin1("configure-identity"); } IdentityPage::IdentityPage( QWidget * parent, const char * name ) : ConfigModule( parent, name ), mIdentityDialog( 0 ) { QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() ); mIdentityList = new IdentityListView( this ); connect( mIdentityList, SIGNAL(selectionChanged()), SLOT(slotIdentitySelectionChanged()) ); connect( mIdentityList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)), SLOT(slotRenameIdentity(QListViewItem*,const QString&,int)) ); connect( mIdentityList, SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)), SLOT(slotModifyIdentity()) ); connect( mIdentityList, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)), SLOT(slotContextMenu(KListView*,QListViewItem*,const QPoint&)) ); // ### connect dragged(...), ... hlay->addWidget( mIdentityList, 1 ); QVBoxLayout * vlay = new QVBoxLayout( hlay ); // inherits spacing QPushButton * button = new QPushButton( i18n("&Add..."), this ); mModifyButton = new QPushButton( i18n("&Modify..."), this ); mRenameButton = new QPushButton( i18n("&Rename"), this ); mRemoveButton = new QPushButton( i18n("Remo&ve"), this ); mSetAsDefaultButton = new QPushButton( i18n("Set as &Default"), this ); button->setAutoDefault( false ); mModifyButton->setAutoDefault( false ); mModifyButton->setEnabled( false ); mRenameButton->setAutoDefault( false ); mRenameButton->setEnabled( false ); mRemoveButton->setAutoDefault( false ); mRemoveButton->setEnabled( false ); mSetAsDefaultButton->setAutoDefault( false ); mSetAsDefaultButton->setEnabled( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewIdentity()) ); connect( mModifyButton, SIGNAL(clicked()), this, SLOT(slotModifyIdentity()) ); connect( mRenameButton, SIGNAL(clicked()), this, SLOT(slotRenameIdentity()) ); connect( mRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveIdentity()) ); connect( mSetAsDefaultButton, SIGNAL(clicked()), this, SLOT(slotSetAsDefault()) ); vlay->addWidget( button ); vlay->addWidget( mModifyButton ); vlay->addWidget( mRenameButton ); vlay->addWidget( mRemoveButton ); vlay->addWidget( mSetAsDefaultButton ); vlay->addStretch( 1 ); load(); } void IdentityPage::load() { KPIM::IdentityManager * im = kmkernel->identityManager(); mOldNumberOfIdentities = im->shadowIdentities().count(); // Fill the list: mIdentityList->clear(); QListViewItem * item = 0; for ( KPIM::IdentityManager::Iterator it = im->modifyBegin() ; it != im->modifyEnd() ; ++it ) item = new IdentityListViewItem( mIdentityList, item, *it ); mIdentityList->setSelected( mIdentityList->currentItem(), true ); } void IdentityPage::save() { assert( !mIdentityDialog ); kmkernel->identityManager()->sort(); kmkernel->identityManager()->commit(); if( mOldNumberOfIdentities < 2 && mIdentityList->childCount() > 1 ) { // have more than one identity, so better show the combo in the // composer now: KConfigGroup composer( KMKernel::config(), "Composer" ); int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD ); showHeaders |= HDR_IDENTITY; composer.writeEntry( "headers", showHeaders ); } // and now the reverse if( mOldNumberOfIdentities > 1 && mIdentityList->childCount() < 2 ) { // have only one identity, so remove the combo in the composer: KConfigGroup composer( KMKernel::config(), "Composer" ); int showHeaders = composer.readNumEntry( "headers", HDR_STANDARD ); showHeaders &= ~HDR_IDENTITY; composer.writeEntry( "headers", showHeaders ); } } void IdentityPage::slotNewIdentity() { assert( !mIdentityDialog ); KPIM::IdentityManager * im = kmkernel->identityManager(); NewIdentityDialog dialog( im->shadowIdentities(), this, "new", true ); if( dialog.exec() == QDialog::Accepted ) { QString identityName = dialog.identityName().stripWhiteSpace(); assert( !identityName.isEmpty() ); // // Construct a new Identity: // switch ( dialog.duplicateMode() ) { case NewIdentityDialog::ExistingEntry: { KPIM::Identity & dupThis = im->modifyIdentityForName( dialog.duplicateIdentity() ); im->newFromExisting( dupThis, identityName ); break; } case NewIdentityDialog::ControlCenter: im->newFromControlCenter( identityName ); break; case NewIdentityDialog::Empty: im->newFromScratch( identityName ); default: ; } // // Insert into listview: // KPIM::Identity & newIdent = im->modifyIdentityForName( identityName ); QListViewItem * item = mIdentityList->selectedItem(); if ( item ) item = item->itemAbove(); mIdentityList->setSelected( new IdentityListViewItem( mIdentityList, /*after*/ item, newIdent ), true ); slotModifyIdentity(); } } void IdentityPage::slotModifyIdentity() { assert( !mIdentityDialog ); IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; mIdentityDialog = new IdentityDialog( this ); mIdentityDialog->setIdentity( item->identity() ); // Hmm, an unmodal dialog would be nicer, but a modal one is easier ;-) if ( mIdentityDialog->exec() == QDialog::Accepted ) { mIdentityDialog->updateIdentity( item->identity() ); item->redisplay(); emit changed(true); } delete mIdentityDialog; mIdentityDialog = 0; } void IdentityPage::slotRemoveIdentity() { assert( !mIdentityDialog ); KPIM::IdentityManager * im = kmkernel->identityManager(); kdFatal( im->shadowIdentities().count() < 2 ) << "Attempted to remove the last identity!" << endl; IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; QString msg = i18n("Do you really want to remove the identity named " "%1?").arg( item->identity().identityName() ); if( KMessageBox::warningContinueCancel( this, msg, i18n("Remove Identity"), KGuiItem(i18n("&Remove"),"editdelete") ) == KMessageBox::Continue ) if ( im->removeIdentity( item->identity().identityName() ) ) { delete item; mIdentityList->setSelected( mIdentityList->currentItem(), true ); refreshList(); } } void IdentityPage::slotRenameIdentity() { assert( !mIdentityDialog ); QListViewItem * item = mIdentityList->selectedItem(); if ( !item ) return; mIdentityList->rename( item, 0 ); } void IdentityPage::slotRenameIdentity( QListViewItem * i, const QString & s, int col ) { assert( col == 0 ); Q_UNUSED( col ); IdentityListViewItem * item = dynamic_cast( i ); if ( !item ) return; QString newName = s.stripWhiteSpace(); if ( !newName.isEmpty() && !kmkernel->identityManager()->shadowIdentities().contains( newName ) ) { KPIM::Identity & ident = item->identity(); ident.setIdentityName( newName ); emit changed(true); } item->redisplay(); } void IdentityPage::slotContextMenu( KListView *, QListViewItem * i, const QPoint & pos ) { IdentityListViewItem * item = dynamic_cast( i ); QPopupMenu * menu = new QPopupMenu( this ); menu->insertItem( i18n("Add..."), this, SLOT(slotNewIdentity()) ); if ( item ) { menu->insertItem( i18n("Modify..."), this, SLOT(slotModifyIdentity()) ); if ( mIdentityList->childCount() > 1 ) menu->insertItem( i18n("Remove"), this, SLOT(slotRemoveIdentity()) ); if ( !item->identity().isDefault() ) menu->insertItem( i18n("Set as Default"), this, SLOT(slotSetAsDefault()) ); } menu->exec( pos ); delete menu; } void IdentityPage::slotSetAsDefault() { assert( !mIdentityDialog ); IdentityListViewItem * item = dynamic_cast( mIdentityList->selectedItem() ); if ( !item ) return; KPIM::IdentityManager * im = kmkernel->identityManager(); im->setAsDefault( item->identity().identityName() ); refreshList(); } void IdentityPage::refreshList() { for ( QListViewItemIterator it( mIdentityList ) ; it.current() ; ++it ) { IdentityListViewItem * item = dynamic_cast(it.current()); if ( item ) item->redisplay(); } emit changed(true); } void IdentityPage::slotIdentitySelectionChanged() { IdentityListViewItem *item = dynamic_cast( mIdentityList->selectedItem() ); mRemoveButton->setEnabled( item && mIdentityList->childCount() > 1 ); mModifyButton->setEnabled( item ); mRenameButton->setEnabled( item ); mSetAsDefaultButton->setEnabled( item && !item->identity().isDefault() ); } void IdentityPage::slotUpdateTransportCombo( const QStringList & sl ) { if ( mIdentityDialog ) mIdentityDialog->slotUpdateTransportCombo( sl ); } // ************************************************************* // * * // * AccountsPage * // * * // ************************************************************* QString AccountsPage::helpAnchor() const { return QString::fromLatin1("configure-accounts"); } AccountsPage::AccountsPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Receiving" tab: // mReceivingTab = new ReceivingTab(); addTab( mReceivingTab, i18n( "&Receiving" ) ); connect( mReceivingTab, SIGNAL(accountListChanged(const QStringList &)), this, SIGNAL(accountListChanged(const QStringList &)) ); // // "Sending" tab: // mSendingTab = new SendingTab(); addTab( mSendingTab, i18n( "&Sending" ) ); connect( mSendingTab, SIGNAL(transportListChanged(const QStringList&)), this, SIGNAL(transportListChanged(const QStringList&)) ); load(); } QString AccountsPage::SendingTab::helpAnchor() const { return QString::fromLatin1("configure-accounts-sending"); } AccountsPageSendingTab::AccountsPageSendingTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { mTransportInfoList.setAutoDelete( true ); // temp. vars: QVBoxLayout *vlay; QVBoxLayout *btn_vlay; QHBoxLayout *hlay; QGridLayout *glay; QPushButton *button; QGroupBox *group; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // label: zero stretch ### FIXME more vlay->addWidget( new QLabel( i18n("Outgoing accounts (add at least one):"), this ) ); // hbox layout: stretch 10, spacing inherited from vlay hlay = new QHBoxLayout(); vlay->addLayout( hlay, 10 ); // high stretch b/c of the groupbox's sizeHint // transport list: left widget in hlay; stretch 1 // ### FIXME: allow inline renaming of the account: mTransportList = new ListView( this, "transportList", 5 ); mTransportList->addColumn( i18n("Name") ); mTransportList->addColumn( i18n("Type") ); mTransportList->setAllColumnsShowFocus( true ); mTransportList->setSorting( -1 ); connect( mTransportList, SIGNAL(selectionChanged()), this, SLOT(slotTransportSelected()) ); connect( mTransportList, SIGNAL(doubleClicked( QListViewItem *)), this, SLOT(slotModifySelectedTransport()) ); hlay->addWidget( mTransportList, 1 ); // a vbox layout for the buttons: zero stretch, spacing inherited from hlay btn_vlay = new QVBoxLayout( hlay ); // "add..." button: stretch 0 button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotAddTransport()) ); btn_vlay->addWidget( button ); // "modify..." button: stretch 0 mModifyTransportButton = new QPushButton( i18n("&Modify..."), this ); mModifyTransportButton->setAutoDefault( false ); mModifyTransportButton->setEnabled( false ); // b/c no item is selected yet connect( mModifyTransportButton, SIGNAL(clicked()), this, SLOT(slotModifySelectedTransport()) ); btn_vlay->addWidget( mModifyTransportButton ); // "remove" button: stretch 0 mRemoveTransportButton = new QPushButton( i18n("R&emove"), this ); mRemoveTransportButton->setAutoDefault( false ); mRemoveTransportButton->setEnabled( false ); // b/c no item is selected yet connect( mRemoveTransportButton, SIGNAL(clicked()), this, SLOT(slotRemoveSelectedTransport()) ); btn_vlay->addWidget( mRemoveTransportButton ); mSetDefaultTransportButton = new QPushButton( i18n("Set Default"), this ); mSetDefaultTransportButton->setAutoDefault( false ); mSetDefaultTransportButton->setEnabled( false ); connect ( mSetDefaultTransportButton, SIGNAL(clicked()), this, SLOT(slotSetDefaultTransport()) ); btn_vlay->addWidget( mSetDefaultTransportButton ); btn_vlay->addStretch( 1 ); // spacer // "Common options" groupbox: group = new QGroupBox( 0, Qt::Vertical, i18n("Common Options"), this ); vlay->addWidget(group); // a grid layout for the contents of the "common options" group box glay = new QGridLayout( group->layout(), 5, 3, KDialog::spacingHint() ); glay->setColStretch( 2, 10 ); // "confirm before send" check box: mConfirmSendCheck = new QCheckBox( i18n("Confirm &before send"), group ); glay->addMultiCellWidget( mConfirmSendCheck, 0, 0, 0, 1 ); connect( mConfirmSendCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "send on check" combo: mSendOnCheckCombo = new QComboBox( false, group ); mSendOnCheckCombo->insertStringList( QStringList() << i18n("Never Automatically") << i18n("On Manual Mail Checks") << i18n("On All Mail Checks") ); glay->addWidget( mSendOnCheckCombo, 1, 1 ); connect( mSendOnCheckCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default send method" combo: mSendMethodCombo = new QComboBox( false, group ); mSendMethodCombo->insertStringList( QStringList() << i18n("Send Now") << i18n("Send Later") ); glay->addWidget( mSendMethodCombo, 2, 1 ); connect( mSendMethodCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "message property" combo: // ### FIXME: remove completely? mMessagePropertyCombo = new QComboBox( false, group ); mMessagePropertyCombo->insertStringList( QStringList() << i18n("Allow 8-bit") << i18n("MIME Compliant (Quoted Printable)") ); glay->addWidget( mMessagePropertyCombo, 3, 1 ); connect( mMessagePropertyCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default domain" input field: mDefaultDomainEdit = new KLineEdit( group ); glay->addMultiCellWidget( mDefaultDomainEdit, 4, 4, 1, 2 ); connect( mDefaultDomainEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); // labels: QLabel *l = new QLabel( mSendOnCheckCombo, /*buddy*/ i18n("Send &messages in outbox folder:"), group ); glay->addWidget( l, 1, 0 ); QString msg = i18n( GlobalSettings::self()->sendOnCheckItem()->whatsThis().utf8() ); QWhatsThis::add( l, msg ); QWhatsThis::add( mSendOnCheckCombo, msg ); glay->addWidget( new QLabel( mSendMethodCombo, /*buddy*/ i18n("Defa&ult send method:"), group ), 2, 0 ); glay->addWidget( new QLabel( mMessagePropertyCombo, /*buddy*/ i18n("Message &property:"), group ), 3, 0 ); l = new QLabel( mDefaultDomainEdit, /*buddy*/ i18n("Defaul&t domain:"), group ); glay->addWidget( l, 4, 0 ); // and now: add QWhatsThis: msg = i18n( "

The default domain is used to complete email " "addresses that only consist of the user's name." "

" ); QWhatsThis::add( l, msg ); QWhatsThis::add( mDefaultDomainEdit, msg ); } void AccountsPage::SendingTab::slotTransportSelected() { QListViewItem *cur = mTransportList->selectedItem(); mModifyTransportButton->setEnabled( cur ); mRemoveTransportButton->setEnabled( cur ); mSetDefaultTransportButton->setEnabled( cur ); } // adds a number to @p name to make the name unique static inline QString uniqueName( const QStringList & list, const QString & name ) { int suffix = 1; QString result = name; while ( list.find( result ) != list.end() ) { result = i18n("%1: name; %2: number appended to it to make it unique " "among a list of names", "%1 %2") .arg( name ).arg( suffix ); suffix++; } return result; } void AccountsPage::SendingTab::slotSetDefaultTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; KMTransportInfo ti; QListViewItemIterator it( mTransportList ); for ( ; it.current(); ++it ) { ti.readConfig( KMTransportInfo::findTransport( it.current()->text(0) )); if ( ti.type != "sendmail" ) { it.current()->setText( 1, "smtp" ); } else { it.current()->setText( 1, "sendmail" ); } } if ( item->text(1) != "sendmail" ) { item->setText( 1, i18n( "smtp (Default)" )); } else { item->setText( 1, i18n( "sendmail (Default)" )); } GlobalSettings::self()->setDefaultTransport( item->text(0) ); } void AccountsPage::SendingTab::slotAddTransport() { int transportType; { // limit scope of selDialog KMTransportSelDlg selDialog( this ); if ( selDialog.exec() != QDialog::Accepted ) return; transportType = selDialog.selected(); } KMTransportInfo *transportInfo = new KMTransportInfo(); switch ( transportType ) { case 0: // smtp transportInfo->type = QString::fromLatin1("smtp"); break; case 1: // sendmail transportInfo->type = QString::fromLatin1("sendmail"); transportInfo->name = i18n("Sendmail"); transportInfo->host = _PATH_SENDMAIL; // ### FIXME: use const, not #define break; default: assert( 0 ); } KMTransportDialog dialog( i18n("Add Transport"), transportInfo, this ); // create list of names: // ### move behind dialog.exec()? QStringList transportNames; QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) transportNames << (*it)->name; if( dialog.exec() != QDialog::Accepted ) { delete transportInfo; return; } // disambiguate the name by appending a number: // ### FIXME: don't allow this error to happen in the first place! transportInfo->name = uniqueName( transportNames, transportInfo->name ); // append to names and transportinfo lists: transportNames << transportInfo->name; mTransportInfoList.append( transportInfo ); // append to listview: // ### FIXME: insert before the selected item, append on empty selection QListViewItem *lastItem = mTransportList->firstChild(); QString typeDisplayName; if ( lastItem ) { typeDisplayName = transportInfo->type; } else { typeDisplayName = i18n("%1: type of transport. Result used in " "Configure->Accounts->Sending listview, \"type\" " "column, first row, to indicate that this is the " "default transport", "%1 (Default)") .arg( transportInfo->type ); GlobalSettings::self()->setDefaultTransport( transportInfo->name ); } (void) new QListViewItem( mTransportList, lastItem, transportInfo->name, typeDisplayName ); // notify anyone who cares: emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::slotModifySelectedTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) if ( (*it)->name == item->text(0) ) break; if ( !it.current() ) return; KMTransportDialog dialog( i18n("Modify Transport"), (*it), this ); if ( dialog.exec() != QDialog::Accepted ) return; // create the list of names of transports, but leave out the current // item: QStringList transportNames; QPtrListIterator jt( mTransportInfoList ); int entryLocation = -1; for ( jt.toFirst() ; jt.current() ; ++jt ) if ( jt != it ) transportNames << (*jt)->name; else entryLocation = transportNames.count(); assert( entryLocation >= 0 ); // make the new name unique by appending a high enough number: (*it)->name = uniqueName( transportNames, (*it)->name ); // change the list item to the new name item->setText( 0, (*it)->name ); // and insert the new name at the position of the old in the list of // strings; then broadcast the new list: transportNames.insert( transportNames.at( entryLocation ), (*it)->name ); emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::slotRemoveSelectedTransport() { QListViewItem *item = mTransportList->selectedItem(); if ( !item ) return; QStringList changedIdents; KPIM::IdentityManager * im = kmkernel->identityManager(); for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) { if ( item->text( 0 ) == (*it).transport() ) { (*it).setTransport( QString::null ); changedIdents += (*it).identityName(); } } // if the deleted transport is the currently used transport reset it to default const QString& currentTransport = GlobalSettings::self()->currentTransport(); if ( item->text( 0 ) == currentTransport ) { GlobalSettings::self()->setCurrentTransport( QString::null ); } if ( !changedIdents.isEmpty() ) { QString information = i18n( "This identity has been changed to use the default transport:", "These %n identities have been changed to use the default transport:", changedIdents.count() ); KMessageBox::informationList( this, information, changedIdents ); } QPtrListIterator it( mTransportInfoList ); for ( it.toFirst() ; it.current() ; ++it ) if ( (*it)->name == item->text(0) ) break; if ( !it.current() ) return; KMTransportInfo ti; QListViewItem *newCurrent = item->itemBelow(); if ( !newCurrent ) newCurrent = item->itemAbove(); //mTransportList->removeItem( item ); if ( newCurrent ) { mTransportList->setCurrentItem( newCurrent ); mTransportList->setSelected( newCurrent, true ); GlobalSettings::self()->setDefaultTransport( newCurrent->text(0) ); ti.readConfig( KMTransportInfo::findTransport( newCurrent->text(0) )); if ( item->text( 0 ) == GlobalSettings::self()->defaultTransport() ) { if ( ti.type != "sendmail" ) { newCurrent->setText( 1, i18n("smtp (Default)") ); } else { newCurrent->setText( 1, i18n("sendmail (Default)" )); } } } else { GlobalSettings::self()->setDefaultTransport( QString::null ); } delete item; mTransportInfoList.remove( it ); QStringList transportNames; for ( it.toFirst() ; it.current() ; ++it ) transportNames << (*it)->name; emit transportListChanged( transportNames ); emit changed( true ); } void AccountsPage::SendingTab::doLoadFromGlobalSettings() { mSendOnCheckCombo->setCurrentItem( GlobalSettings::self()->sendOnCheck() ); } void AccountsPage::SendingTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General"); KConfigGroup composer( KMKernel::config(), "Composer"); int numTransports = general.readNumEntry("transports", 0); QListViewItem *top = 0; mTransportInfoList.clear(); mTransportList->clear(); QStringList transportNames; for ( int i = 1 ; i <= numTransports ; i++ ) { KMTransportInfo *ti = new KMTransportInfo(); ti->readConfig(i); mTransportInfoList.append( ti ); transportNames << ti->name; top = new QListViewItem( mTransportList, top, ti->name, ti->type ); } emit transportListChanged( transportNames ); const QString &defaultTransport = GlobalSettings::self()->defaultTransport(); QListViewItemIterator it( mTransportList ); for ( ; it.current(); ++it ) { if ( it.current()->text(0) == defaultTransport ) { if ( it.current()->text(1) != "sendmail" ) { it.current()->setText( 1, i18n( "smtp (Default)" )); } else { it.current()->setText( 1, i18n( "sendmail (Default)" )); } } else { if ( it.current()->text(1) != "sendmail" ) { it.current()->setText( 1, "smtp" ); } else { it.current()->setText( 1, "sendmail" ); } } } mSendMethodCombo->setCurrentItem( kmkernel->msgSender()->sendImmediate() ? 0 : 1 ); mMessagePropertyCombo->setCurrentItem( kmkernel->msgSender()->sendQuotedPrintable() ? 1 : 0 ); mConfirmSendCheck->setChecked( composer.readBoolEntry( "confirm-before-send", false ) ); QString str = general.readEntry( "Default domain" ); if( str.isEmpty() ) { //### FIXME: Use the global convenience function instead of the homebrewed // solution once we can rely on HEAD kdelibs. //str = KGlobal::hostname(); ??????? char buffer[256]; if ( !gethostname( buffer, 255 ) ) // buffer need not be NUL-terminated if it has full length buffer[255] = 0; else buffer[0] = 0; str = QString::fromLatin1( *buffer ? buffer : "localhost" ); } mDefaultDomainEdit->setText( str ); } void AccountsPage::SendingTab::save() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup composer( KMKernel::config(), "Composer" ); // Save transports: general.writeEntry( "transports", mTransportInfoList.count() ); QPtrListIterator it( mTransportInfoList ); for ( int i = 1 ; it.current() ; ++it, ++i ) (*it)->writeConfig(i); // Save common options: GlobalSettings::self()->setSendOnCheck( mSendOnCheckCombo->currentItem() ); kmkernel->msgSender()->setSendImmediate( mSendMethodCombo->currentItem() == 0 ); kmkernel->msgSender()->setSendQuotedPrintable( mMessagePropertyCombo->currentItem() == 1 ); kmkernel->msgSender()->writeConfig( false ); // don't sync composer.writeEntry("confirm-before-send", mConfirmSendCheck->isChecked() ); general.writeEntry( "Default domain", mDefaultDomainEdit->text() ); } QString AccountsPage::ReceivingTab::helpAnchor() const { return QString::fromLatin1("configure-accounts-receiving"); } AccountsPageReceivingTab::AccountsPageReceivingTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // temp. vars: QVBoxLayout *vlay; QVBoxLayout *btn_vlay; QHBoxLayout *hlay; QPushButton *button; QGroupBox *group; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // label: zero stretch vlay->addWidget( new QLabel( i18n("Incoming accounts (add at least one):"), this ) ); // hbox layout: stretch 10, spacing inherited from vlay hlay = new QHBoxLayout(); vlay->addLayout( hlay, 10 ); // high stretch to suppress groupbox's growing // account list: left widget in hlay; stretch 1 mAccountList = new ListView( this, "accountList", 5 ); mAccountList->addColumn( i18n("Name") ); mAccountList->addColumn( i18n("Type") ); mAccountList->addColumn( i18n("Folder") ); mAccountList->setAllColumnsShowFocus( true ); mAccountList->setSorting( -1 ); connect( mAccountList, SIGNAL(selectionChanged()), this, SLOT(slotAccountSelected()) ); connect( mAccountList, SIGNAL(doubleClicked( QListViewItem *)), this, SLOT(slotModifySelectedAccount()) ); hlay->addWidget( mAccountList, 1 ); // a vbox layout for the buttons: zero stretch, spacing inherited from hlay btn_vlay = new QVBoxLayout( hlay ); // "add..." button: stretch 0 button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); connect( button, SIGNAL(clicked()), this, SLOT(slotAddAccount()) ); btn_vlay->addWidget( button ); // "modify..." button: stretch 0 mModifyAccountButton = new QPushButton( i18n("&Modify..."), this ); mModifyAccountButton->setAutoDefault( false ); mModifyAccountButton->setEnabled( false ); // b/c no item is selected yet connect( mModifyAccountButton, SIGNAL(clicked()), this, SLOT(slotModifySelectedAccount()) ); btn_vlay->addWidget( mModifyAccountButton ); // "remove..." button: stretch 0 mRemoveAccountButton = new QPushButton( i18n("R&emove"), this ); mRemoveAccountButton->setAutoDefault( false ); mRemoveAccountButton->setEnabled( false ); // b/c no item is selected yet connect( mRemoveAccountButton, SIGNAL(clicked()), this, SLOT(slotRemoveSelectedAccount()) ); btn_vlay->addWidget( mRemoveAccountButton ); btn_vlay->addStretch( 1 ); // spacer mCheckmailStartupCheck = new QCheckBox( i18n("Chec&k mail on startup"), this ); vlay->addWidget( mCheckmailStartupCheck ); connect( mCheckmailStartupCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "New Mail Notification" group box: stretch 0 group = new QVGroupBox( i18n("New Mail Notification"), this ); vlay->addWidget( group ); group->layout()->setSpacing( KDialog::spacingHint() ); // "beep on new mail" check box: mBeepNewMailCheck = new QCheckBox(i18n("&Beep"), group ); mBeepNewMailCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) ); connect( mBeepNewMailCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Detailed new mail notification" check box mVerboseNotificationCheck = new QCheckBox( i18n( "Deta&iled new mail notification" ), group ); mVerboseNotificationCheck->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) ); QToolTip::add( mVerboseNotificationCheck, i18n( "Show for each folder the number of newly arrived " "messages" ) ); QWhatsThis::add( mVerboseNotificationCheck, GlobalSettings::self()->verboseNewMailNotificationItem()->whatsThis() ); connect( mVerboseNotificationCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Other Actions" button: mOtherNewMailActionsButton = new QPushButton( i18n("Other Actio&ns"), group ); mOtherNewMailActionsButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); connect( mOtherNewMailActionsButton, SIGNAL(clicked()), this, SLOT(slotEditNotifications()) ); } void AccountsPage::ReceivingTab::slotAccountSelected() { QListViewItem * item = mAccountList->selectedItem(); mModifyAccountButton->setEnabled( item ); mRemoveAccountButton->setEnabled( item ); } QStringList AccountsPage::ReceivingTab::occupiedNames() { QStringList accountNames = kmkernel->acctMgr()->getAccounts(); QValueList::Iterator k; for (k = mModifiedAccounts.begin(); k != mModifiedAccounts.end(); ++k ) if ((*k)->oldAccount) accountNames.remove( (*k)->oldAccount->name() ); QValueList< QGuardedPtr >::Iterator l; for (l = mAccountsToDelete.begin(); l != mAccountsToDelete.end(); ++l ) if (*l) accountNames.remove( (*l)->name() ); QValueList< QGuardedPtr >::Iterator it; for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) if (*it) accountNames += (*it)->name(); QValueList::Iterator j; for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j ) accountNames += (*j)->newAccount->name(); return accountNames; } void AccountsPage::ReceivingTab::slotAddAccount() { KMAcctSelDlg accountSelectorDialog( this ); if( accountSelectorDialog.exec() != QDialog::Accepted ) return; const char *accountType = 0; switch ( accountSelectorDialog.selected() ) { case 0: accountType = "local"; break; case 1: accountType = "pop"; break; case 2: accountType = "imap"; break; case 3: accountType = "cachedimap"; break; case 4: accountType = "maildir"; break; default: // ### FIXME: How should this happen??? // replace with assert. KMessageBox::sorry( this, i18n("Unknown account type selected") ); return; } KMAccount *account = kmkernel->acctMgr()->create( QString::fromLatin1( accountType ) ); if ( !account ) { // ### FIXME: Give the user more information. Is this error // recoverable? KMessageBox::sorry( this, i18n("Unable to create account") ); return; } account->init(); // fill the account fields with good default values AccountDialog dialog( i18n("Add Account"), account, this ); QStringList accountNames = occupiedNames(); if( dialog.exec() != QDialog::Accepted ) { delete account; return; } account->deinstallTimer(); account->setName( uniqueName( accountNames, account->name() ) ); QListViewItem *after = mAccountList->firstChild(); while ( after && after->nextSibling() ) after = after->nextSibling(); QListViewItem *listItem = new QListViewItem( mAccountList, after, account->name(), account->type() ); if( account->folder() ) listItem->setText( 2, account->folder()->label() ); mNewAccounts.append( account ); emit changed( true ); } void AccountsPage::ReceivingTab::slotModifySelectedAccount() { QListViewItem *listItem = mAccountList->selectedItem(); if( !listItem ) return; KMAccount *account = 0; QValueList::Iterator j; for (j = mModifiedAccounts.begin(); j != mModifiedAccounts.end(); ++j ) if ( (*j)->newAccount->name() == listItem->text(0) ) { account = (*j)->newAccount; break; } if ( !account ) { QValueList< QGuardedPtr >::Iterator it; for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it ) if ( (*it)->name() == listItem->text(0) ) { account = *it; break; } if ( !account ) { account = kmkernel->acctMgr()->findByName( listItem->text(0) ); if( !account ) { // ### FIXME: How should this happen? See above. KMessageBox::sorry( this, i18n("Unable to locate account") ); return; } if ( account->type() == "imap" || account->type() == "cachedimap" ) { ImapAccountBase* ai = static_cast( account ); if ( ai->namespaces().isEmpty() || ai->namespaceToDelimiter().isEmpty() ) { // connect to server - the namespaces are fetched automatically kdDebug(5006) << "slotModifySelectedAccount - connect" << endl; ai->makeConnection(); } } ModifiedAccountsType *mod = new ModifiedAccountsType; mod->oldAccount = account; mod->newAccount = kmkernel->acctMgr()->create( account->type(), account->name() ); mod->newAccount->pseudoAssign( account ); mModifiedAccounts.append( mod ); account = mod->newAccount; } } QStringList accountNames = occupiedNames(); accountNames.remove( account->name() ); AccountDialog dialog( i18n("Modify Account"), account, this ); if( dialog.exec() != QDialog::Accepted ) return; account->setName( uniqueName( accountNames, account->name() ) ); listItem->setText( 0, account->name() ); listItem->setText( 1, account->type() ); if( account->folder() ) listItem->setText( 2, account->folder()->label() ); emit changed( true ); } void AccountsPage::ReceivingTab::slotRemoveSelectedAccount() { QListViewItem *listItem = mAccountList->selectedItem(); if( !listItem ) return; KMAccount *acct = 0; QValueList::Iterator j; for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) if ( (*j)->newAccount->name() == listItem->text(0) ) { acct = (*j)->oldAccount; mAccountsToDelete.append( acct ); mModifiedAccounts.remove( j ); break; } if ( !acct ) { QValueList< QGuardedPtr >::Iterator it; for ( it = mNewAccounts.begin() ; it != mNewAccounts.end() ; ++it ) if ( (*it)->name() == listItem->text(0) ) { acct = *it; mNewAccounts.remove( it ); break; } } if ( !acct ) { acct = kmkernel->acctMgr()->findByName( listItem->text(0) ); if ( acct ) mAccountsToDelete.append( acct ); } if ( !acct ) { // ### FIXME: see above KMessageBox::sorry( this, i18n("Unable to locate account %1.") .arg(listItem->text(0)) ); return; } QListViewItem * item = listItem->itemBelow(); if ( !item ) item = listItem->itemAbove(); delete listItem; if ( item ) mAccountList->setSelected( item, true ); emit changed( true ); } void AccountsPage::ReceivingTab::slotEditNotifications() { if(kmkernel->xmlGuiInstance()) KNotifyDialog::configure(this, 0, kmkernel->xmlGuiInstance()->aboutData()); else KNotifyDialog::configure(this); } void AccountsPage::ReceivingTab::doLoadFromGlobalSettings() { mVerboseNotificationCheck->setChecked( GlobalSettings::self()->verboseNewMailNotification() ); } void AccountsPage::ReceivingTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); mAccountList->clear(); QListViewItem *top = 0; for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0; a = kmkernel->acctMgr()->next() ) { QListViewItem *listItem = new QListViewItem( mAccountList, top, a->name(), a->type() ); if( a->folder() ) listItem->setText( 2, a->folder()->label() ); top = listItem; } QListViewItem *listItem = mAccountList->firstChild(); if ( listItem ) { mAccountList->setCurrentItem( listItem ); mAccountList->setSelected( listItem, true ); } mBeepNewMailCheck->setChecked( general.readBoolEntry("beep-on-mail", false ) ); mCheckmailStartupCheck->setChecked( general.readBoolEntry("checkmail-startup", false) ); QTimer::singleShot( 0, this, SLOT( slotTweakAccountList() ) ); } void AccountsPage::ReceivingTab::slotTweakAccountList() { // Force the contentsWidth of mAccountList to be recalculated so that items can be // selected in the normal way. It would be best if this were not necessary. mAccountList->resizeContents( mAccountList->visibleWidth(), mAccountList->contentsHeight() ); } void AccountsPage::ReceivingTab::save() { // Add accounts marked as new QValueList< QGuardedPtr >::Iterator it; for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) { kmkernel->acctMgr()->add( *it ); (*it)->installTimer(); } // Update accounts that have been modified QValueList::Iterator j; for ( j = mModifiedAccounts.begin() ; j != mModifiedAccounts.end() ; ++j ) { (*j)->oldAccount->pseudoAssign( (*j)->newAccount ); delete (*j)->newAccount; delete (*j); } mModifiedAccounts.clear(); // Delete accounts marked for deletion for ( it = mAccountsToDelete.begin() ; it != mAccountsToDelete.end() ; ++it ) { kmkernel->acctMgr()->writeConfig( true ); if ( (*it) && !kmkernel->acctMgr()->remove(*it) ) KMessageBox::sorry( this, i18n("Unable to locate account %1.") .arg( (*it)->name() ) ); } mAccountsToDelete.clear(); // Incoming mail kmkernel->acctMgr()->writeConfig( false ); kmkernel->cleanupImapFolders(); // Save Mail notification settings KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "beep-on-mail", mBeepNewMailCheck->isChecked() ); GlobalSettings::self()->setVerboseNewMailNotification( mVerboseNotificationCheck->isChecked() ); general.writeEntry( "checkmail-startup", mCheckmailStartupCheck->isChecked() ); // Sync new IMAP accounts ASAP: for (it = mNewAccounts.begin(); it != mNewAccounts.end(); ++it ) { KMAccount *macc = (*it); ImapAccountBase *acc = dynamic_cast (macc); if ( acc ) { AccountUpdater *au = new AccountUpdater( acc ); au->update(); } } mNewAccounts.clear(); } // ************************************************************* // * * // * AppearancePage * // * * // ************************************************************* QString AppearancePage::helpAnchor() const { return QString::fromLatin1("configure-appearance"); } AppearancePage::AppearancePage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Fonts" tab: // mFontsTab = new FontsTab(); addTab( mFontsTab, i18n("&Fonts") ); // // "Colors" tab: // mColorsTab = new ColorsTab(); addTab( mColorsTab, i18n("Color&s") ); // // "Layout" tab: // mLayoutTab = new LayoutTab(); addTab( mLayoutTab, i18n("La&yout") ); // // "Headers" tab: // mHeadersTab = new HeadersTab(); addTab( mHeadersTab, i18n("M&essage List") ); // // "Reader window" tab: // mReaderTab = new ReaderTab(); addTab( mReaderTab, i18n("Message W&indow") ); // // "System Tray" tab: // mSystemTrayTab = new SystemTrayTab(); addTab( mSystemTrayTab, i18n("System &Tray") ); load(); } QString AppearancePage::FontsTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-fonts"); } static const struct { const char * configName; const char * displayName; bool enableFamilyAndSize; bool onlyFixed; } fontNames[] = { { "body-font", I18N_NOOP("Message Body"), true, false }, { "list-font", I18N_NOOP("Message List"), true, false }, { "list-new-font", I18N_NOOP("Message List - New Messages"), true, false }, { "list-unread-font", I18N_NOOP("Message List - Unread Messages"), true, false }, { "list-important-font", I18N_NOOP("Message List - Important Messages"), true, false }, { "list-todo-font", I18N_NOOP("Message List - Todo Messages"), true, false }, { "list-date-font", I18N_NOOP("Message List - Date Field"), true, false }, { "folder-font", I18N_NOOP("Folder List"), true, false }, { "quote1-font", I18N_NOOP("Quoted Text - First Level"), false, false }, { "quote2-font", I18N_NOOP("Quoted Text - Second Level"), false, false }, { "quote3-font", I18N_NOOP("Quoted Text - Third Level"), false, false }, { "fixed-font", I18N_NOOP("Fixed Width Font"), true, true }, { "composer-font", I18N_NOOP("Composer"), true, false }, { "print-font", I18N_NOOP("Printing Output"), true, false }, }; static const int numFontNames = sizeof fontNames / sizeof *fontNames; AppearancePageFontsTab::AppearancePageFontsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ), mActiveFontIndex( -1 ) { assert( numFontNames == sizeof mFont / sizeof *mFont ); // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QLabel *label; // "Use custom fonts" checkbox, followed by
vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mCustomFontCheck = new QCheckBox( i18n("&Use custom fonts"), this ); vlay->addWidget( mCustomFontCheck ); vlay->addWidget( new KSeparator( KSeparator::HLine, this ) ); connect ( mCustomFontCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "font location" combo box and label: hlay = new QHBoxLayout( vlay ); // inherites spacing mFontLocationCombo = new QComboBox( false, this ); mFontLocationCombo->setEnabled( false ); // !mCustomFontCheck->isChecked() QStringList fontDescriptions; for ( int i = 0 ; i < numFontNames ; i++ ) fontDescriptions << i18n( fontNames[i].displayName ); mFontLocationCombo->insertStringList( fontDescriptions ); label = new QLabel( mFontLocationCombo, i18n("Apply &to:"), this ); label->setEnabled( false ); // since !mCustomFontCheck->isChecked() hlay->addWidget( label ); hlay->addWidget( mFontLocationCombo ); hlay->addStretch( 10 ); vlay->addSpacing( KDialog::spacingHint() ); mFontChooser = new KFontChooser( this, "font", false, QStringList(), false, 4 ); mFontChooser->setEnabled( false ); // since !mCustomFontCheck->isChecked() vlay->addWidget( mFontChooser ); connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // {en,dis}able widgets depending on the state of mCustomFontCheck: connect( mCustomFontCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); connect( mCustomFontCheck, SIGNAL(toggled(bool)), mFontLocationCombo, SLOT(setEnabled(bool)) ); connect( mCustomFontCheck, SIGNAL(toggled(bool)), mFontChooser, SLOT(setEnabled(bool)) ); // load the right font settings into mFontChooser: connect( mFontLocationCombo, SIGNAL(activated(int) ), this, SLOT(slotFontSelectorChanged(int)) ); } void AppearancePage::FontsTab::slotFontSelectorChanged( int index ) { kdDebug(5006) << "slotFontSelectorChanged() called" << endl; if( index < 0 || index >= mFontLocationCombo->count() ) return; // Should never happen, but it is better to check. // Save current fontselector setting before we install the new: if( mActiveFontIndex == 0 ) { mFont[0] = mFontChooser->font(); // hardcode the family and size of "message body" dependant fonts: for ( int i = 0 ; i < numFontNames ; i++ ) if ( !fontNames[i].enableFamilyAndSize ) { // ### shall we copy the font and set the save and re-set // {regular,italic,bold,bold italic} property or should we // copy only family and pointSize? mFont[i].setFamily( mFont[0].family() ); mFont[i].setPointSize/*Float?*/( mFont[0].pointSize/*Float?*/() ); } } else if ( mActiveFontIndex > 0 ) mFont[ mActiveFontIndex ] = mFontChooser->font(); mActiveFontIndex = index; // Disonnect so the "Apply" button is not activated by the change disconnect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // Display the new setting: mFontChooser->setFont( mFont[index], fontNames[index].onlyFixed ); connect ( mFontChooser, SIGNAL( fontSelected( const QFont& ) ), this, SLOT( slotEmitChanged( void ) ) ); // Disable Family and Size list if we have selected a quote font: mFontChooser->enableColumn( KFontChooser::FamilyList|KFontChooser::SizeList, fontNames[ index ].enableFamilyAndSize ); } void AppearancePage::FontsTab::doLoadOther() { KConfigGroup fonts( KMKernel::config(), "Fonts" ); mFont[0] = KGlobalSettings::generalFont(); QFont fixedFont = KGlobalSettings::fixedFont(); for ( int i = 0 ; i < numFontNames ; i++ ) mFont[i] = fonts.readFontEntry( fontNames[i].configName, (fontNames[i].onlyFixed) ? &fixedFont : &mFont[0] ); mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts", true ) ); mFontLocationCombo->setCurrentItem( 0 ); slotFontSelectorChanged( 0 ); } void AppearancePage::FontsTab::installProfile( KConfig * profile ) { KConfigGroup fonts( profile, "Fonts" ); // read fonts that are defined in the profile: bool needChange = false; for ( int i = 0 ; i < numFontNames ; i++ ) if ( fonts.hasKey( fontNames[i].configName ) ) { needChange = true; mFont[i] = fonts.readFontEntry( fontNames[i].configName ); kdDebug(5006) << "got font \"" << fontNames[i].configName << "\" thusly: \"" << mFont[i].toString() << "\"" << endl; } if ( needChange && mFontLocationCombo->currentItem() > 0 ) mFontChooser->setFont( mFont[ mFontLocationCombo->currentItem() ], fontNames[ mFontLocationCombo->currentItem() ].onlyFixed ); if ( fonts.hasKey( "defaultFonts" ) ) mCustomFontCheck->setChecked( !fonts.readBoolEntry( "defaultFonts" ) ); } void AppearancePage::FontsTab::save() { KConfigGroup fonts( KMKernel::config(), "Fonts" ); // read the current font (might have been modified) if ( mActiveFontIndex >= 0 ) mFont[ mActiveFontIndex ] = mFontChooser->font(); bool customFonts = mCustomFontCheck->isChecked(); fonts.writeEntry( "defaultFonts", !customFonts ); for ( int i = 0 ; i < numFontNames ; i++ ) if ( customFonts || fonts.hasKey( fontNames[i].configName ) ) // Don't write font info when we use default fonts, but write // if it's already there: fonts.writeEntry( fontNames[i].configName, mFont[i] ); } QString AppearancePage::ColorsTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-colors"); } static const struct { const char * configName; const char * displayName; } colorNames[] = { // adjust setup() if you change this: { "BackgroundColor", I18N_NOOP("Composer Background") }, { "AltBackgroundColor", I18N_NOOP("Alternative Background Color") }, { "ForegroundColor", I18N_NOOP("Normal Text") }, { "QuotedText1", I18N_NOOP("Quoted Text - First Level") }, { "QuotedText2", I18N_NOOP("Quoted Text - Second Level") }, { "QuotedText3", I18N_NOOP("Quoted Text - Third Level") }, { "LinkColor", I18N_NOOP("Link") }, { "FollowedColor", I18N_NOOP("Followed Link") }, { "MisspelledColor", I18N_NOOP("Misspelled Words") }, { "NewMessage", I18N_NOOP("New Message") }, { "UnreadMessage", I18N_NOOP("Unread Message") }, { "FlagMessage", I18N_NOOP("Important Message") }, { "TodoMessage", I18N_NOOP("Todo Message") }, { "PGPMessageEncr", I18N_NOOP("OpenPGP Message - Encrypted") }, { "PGPMessageOkKeyOk", I18N_NOOP("OpenPGP Message - Valid Signature with Trusted Key") }, { "PGPMessageOkKeyBad", I18N_NOOP("OpenPGP Message - Valid Signature with Untrusted Key") }, { "PGPMessageWarn", I18N_NOOP("OpenPGP Message - Unchecked Signature") }, { "PGPMessageErr", I18N_NOOP("OpenPGP Message - Bad Signature") }, { "HTMLWarningColor", I18N_NOOP("Border Around Warning Prepending HTML Messages") }, { "ColorbarBackgroundPlain", I18N_NOOP("HTML Status Bar Background - No HTML Message") }, { "ColorbarForegroundPlain", I18N_NOOP("HTML Status Bar Foreground - No HTML Message") }, { "ColorbarBackgroundHTML", I18N_NOOP("HTML Status Bar Background - HTML Message") }, { "ColorbarForegroundHTML", I18N_NOOP("HTML Status Bar Foreground - HTML Message") }, }; static const int numColorNames = sizeof colorNames / sizeof *colorNames; AppearancePageColorsTab::AppearancePageColorsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; // "use custom colors" check box vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mCustomColorCheck = new QCheckBox( i18n("&Use custom colors"), this ); vlay->addWidget( mCustomColorCheck ); connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // color list box: mColorList = new ColorListBox( this ); mColorList->setEnabled( false ); // since !mCustomColorCheck->isChecked() QStringList modeList; for ( int i = 0 ; i < numColorNames ; i++ ) mColorList->insertItem( new ColorListItem( i18n( colorNames[i].displayName ) ) ); vlay->addWidget( mColorList, 1 ); // "recycle colors" check box: mRecycleColorCheck = new QCheckBox( i18n("Recycle colors on deep "ing"), this ); mRecycleColorCheck->setEnabled( false ); vlay->addWidget( mRecycleColorCheck ); connect( mRecycleColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // {en,dir}able widgets depending on the state of mCustomColorCheck: connect( mCustomColorCheck, SIGNAL(toggled(bool)), mColorList, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL(toggled(bool)), mRecycleColorCheck, SLOT(setEnabled(bool)) ); connect( mCustomColorCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); } void AppearancePage::ColorsTab::doLoadOther() { KConfigGroup reader( KMKernel::config(), "Reader" ); mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors", true ) ); mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors", false ) ); static const QColor defaultColor[ numColorNames ] = { kapp->palette().active().base(), // bg KGlobalSettings::alternateBackgroundColor(), // alt bg kapp->palette().active().text(), // fg QColor( 0x00, 0x80, 0x00 ), // quoted l1 QColor( 0x00, 0x70, 0x00 ), // quoted l2 QColor( 0x00, 0x60, 0x00 ), // quoted l3 KGlobalSettings::linkColor(), // link KGlobalSettings::visitedLinkColor(), // visited link Qt::red, // misspelled words Qt::red, // new msg Qt::blue, // unread mgs QColor( 0x00, 0x7F, 0x00 ), // important msg QColor( 0x00, 0x80, 0xFF ), // light blue // pgp encrypted QColor( 0x40, 0xFF, 0x40 ), // light green // pgp ok, trusted key QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp ok, untrusted key QColor( 0xFF, 0xFF, 0x40 ), // light yellow // pgp unchk Qt::red, // pgp bad QColor( 0xFF, 0x40, 0x40 ), // warning text color: light red Qt::lightGray, // colorbar plain bg Qt::black, // colorbar plain fg Qt::black, // colorbar html bg Qt::white, // colorbar html fg }; for ( int i = 0 ; i < numColorNames ; i++ ) mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName, &defaultColor[i] ) ); connect( mColorList, SIGNAL( changed( ) ), this, SLOT( slotEmitChanged( void ) ) ); } void AppearancePage::ColorsTab::installProfile( KConfig * profile ) { KConfigGroup reader( profile, "Reader" ); if ( reader.hasKey( "defaultColors" ) ) mCustomColorCheck->setChecked( !reader.readBoolEntry( "defaultColors" ) ); if ( reader.hasKey( "RecycleQuoteColors" ) ) mRecycleColorCheck->setChecked( reader.readBoolEntry( "RecycleQuoteColors" ) ); for ( int i = 0 ; i < numColorNames ; i++ ) if ( reader.hasKey( colorNames[i].configName ) ) mColorList->setColor( i, reader.readColorEntry( colorNames[i].configName ) ); } void AppearancePage::ColorsTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); bool customColors = mCustomColorCheck->isChecked(); reader.writeEntry( "defaultColors", !customColors ); for ( int i = 0 ; i < numColorNames ; i++ ) // Don't write color info when we use default colors, but write // if it's already there: if ( customColors || reader.hasKey( colorNames[i].configName ) ) reader.writeEntry( colorNames[i].configName, mColorList->color(i) ); reader.writeEntry( "RecycleQuoteColors", mRecycleColorCheck->isChecked() ); } QString AppearancePage::LayoutTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-layout"); } static const EnumConfigEntryItem folderListModes[] = { { "long", I18N_NOOP("Lon&g folder list") }, { "short", I18N_NOOP("Shor&t folder list" ) } }; static const EnumConfigEntry folderListMode = { "Geometry", "FolderList", I18N_NOOP("Folder List"), folderListModes, DIM(folderListModes), 0 }; static const EnumConfigEntryItem mimeTreeLocations[] = { { "top", I18N_NOOP("Abo&ve the message pane") }, { "bottom", I18N_NOOP("&Below the message pane") } }; static const EnumConfigEntry mimeTreeLocation = { "Reader", "MimeTreeLocation", I18N_NOOP("Message Structure Viewer Placement"), mimeTreeLocations, DIM(mimeTreeLocations), 1 }; static const EnumConfigEntryItem mimeTreeModes[] = { { "never", I18N_NOOP("Show &never") }, { "smart", I18N_NOOP("Show only for non-plaintext &messages") }, { "always", I18N_NOOP("Show alway&s") } }; static const EnumConfigEntry mimeTreeMode = { "Reader", "MimeTreeMode", I18N_NOOP("Message Structure Viewer"), mimeTreeModes, DIM(mimeTreeModes), 1 }; static const EnumConfigEntryItem readerWindowModes[] = { { "hide", I18N_NOOP("&Do not show a message preview pane") }, { "below", I18N_NOOP("Show the message preview pane belo&w the message list") }, { "right", I18N_NOOP("Show the message preview pane ne&xt to the message list") } }; static const EnumConfigEntry readerWindowMode = { "Geometry", "readerWindowMode", I18N_NOOP("Message Preview Pane"), readerWindowModes, DIM(readerWindowModes), 1 }; AppearancePageLayoutTab::AppearancePageLayoutTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout * vlay; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "folder list" radio buttons: populateButtonGroup( mFolderListGroup = new QHButtonGroup( this ), folderListMode ); vlay->addWidget( mFolderListGroup ); connect( mFolderListGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); // "show reader window" radio buttons: populateButtonGroup( mReaderWindowModeGroup = new QVButtonGroup( this ), readerWindowMode ); vlay->addWidget( mReaderWindowModeGroup ); connect( mReaderWindowModeGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); // "Show MIME Tree" radio buttons: populateButtonGroup( mMIMETreeModeGroup = new QVButtonGroup( this ), mimeTreeMode ); vlay->addWidget( mMIMETreeModeGroup ); connect( mMIMETreeModeGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); // "MIME Tree Location" radio buttons: populateButtonGroup( mMIMETreeLocationGroup = new QHButtonGroup( this ), mimeTreeLocation ); vlay->addWidget( mMIMETreeLocationGroup ); connect( mMIMETreeLocationGroup, SIGNAL ( clicked( int ) ), this, SLOT( slotEmitChanged() ) ); vlay->addStretch( 10 ); // spacer } void AppearancePage::LayoutTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); const KConfigGroup geometry( KMKernel::config(), "Geometry" ); loadWidget( mFolderListGroup, geometry, folderListMode ); loadWidget( mMIMETreeLocationGroup, reader, mimeTreeLocation ); loadWidget( mMIMETreeModeGroup, reader, mimeTreeMode ); loadWidget( mReaderWindowModeGroup, geometry, readerWindowMode ); } void AppearancePage::LayoutTab::installProfile( KConfig * profile ) { const KConfigGroup reader( profile, "Reader" ); const KConfigGroup geometry( profile, "Geometry" ); loadProfile( mFolderListGroup, geometry, folderListMode ); loadProfile( mMIMETreeLocationGroup, reader, mimeTreeLocation ); loadProfile( mMIMETreeModeGroup, reader, mimeTreeMode ); loadProfile( mReaderWindowModeGroup, geometry, readerWindowMode ); } void AppearancePage::LayoutTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); saveButtonGroup( mFolderListGroup, geometry, folderListMode ); saveButtonGroup( mMIMETreeLocationGroup, reader, mimeTreeLocation ); saveButtonGroup( mMIMETreeModeGroup, reader, mimeTreeMode ); saveButtonGroup( mReaderWindowModeGroup, geometry, readerWindowMode ); } // // Appearance Message List // QString AppearancePage::HeadersTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-headers"); } static const struct { const char * displayName; DateFormatter::FormatType dateDisplay; } dateDisplayConfig[] = { { I18N_NOOP("Sta&ndard format (%1)"), KMime::DateFormatter::CTime }, { I18N_NOOP("Locali&zed format (%1)"), KMime::DateFormatter::Localized }, { I18N_NOOP("Fancy for&mat (%1)"), KMime::DateFormatter::Fancy }, { I18N_NOOP("C&ustom format (Shift+F1 for help):"), KMime::DateFormatter::Custom } }; static const int numDateDisplayConfig = sizeof dateDisplayConfig / sizeof *dateDisplayConfig; AppearancePageHeadersTab::AppearancePageHeadersTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ), mCustomDateFormatEdit( 0 ) { // tmp. vars: QButtonGroup * group; QRadioButton * radio; QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "General Options" group: group = new QVButtonGroup( i18n( "General Options" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mMessageSizeCheck = new QCheckBox( i18n("Display messa&ge sizes"), group ); mCryptoIconsCheck = new QCheckBox( i18n( "Show crypto &icons" ), group ); mAttachmentCheck = new QCheckBox( i18n("Show attachment icon"), group ); mNestedMessagesCheck = new QCheckBox( i18n("&Threaded message list"), group ); connect( mMessageSizeCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mAttachmentCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mCryptoIconsCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mNestedMessagesCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); // "Message Header Threading Options" group: mNestingPolicy = new QVButtonGroup( i18n("Threaded Message List Options"), this ); mNestingPolicy->layout()->setSpacing( KDialog::spacingHint() ); mNestingPolicy->insert( new QRadioButton( i18n("Always &keep threads open"), mNestingPolicy ), 0 ); mNestingPolicy->insert( new QRadioButton( i18n("Threads default to o&pen"), mNestingPolicy ), 1 ); mNestingPolicy->insert( new QRadioButton( i18n("Threads default to closed"), mNestingPolicy ), 2 ); mNestingPolicy->insert( new QRadioButton( i18n("Open threads that contain ne&w, unread " "or important messages and open watched threads."), mNestingPolicy ), 3 ); vlay->addWidget( mNestingPolicy ); connect( mNestingPolicy, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Date Display" group: mDateDisplay = new QVButtonGroup( i18n("Date Display"), this ); mDateDisplay->layout()->setSpacing( KDialog::spacingHint() ); for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) { QString buttonLabel = i18n(dateDisplayConfig[i].displayName); if ( buttonLabel.contains("%1") ) buttonLabel = buttonLabel.arg( DateFormatter::formatCurrentDate( dateDisplayConfig[i].dateDisplay ) ); radio = new QRadioButton( buttonLabel, mDateDisplay ); mDateDisplay->insert( radio, i ); if ( dateDisplayConfig[i].dateDisplay == DateFormatter::Custom ) { mCustomDateFormatEdit = new KLineEdit( mDateDisplay ); mCustomDateFormatEdit->setEnabled( false ); connect( radio, SIGNAL(toggled(bool)), mCustomDateFormatEdit, SLOT(setEnabled(bool)) ); connect( mCustomDateFormatEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotEmitChanged(void)) ); QString customDateWhatsThis = i18n("

These expressions may be used for the date:" "

" "
    " "
  • d - the day as a number without a leading zero (1-31)
  • " "
  • dd - the day as a number with a leading zero (01-31)
  • " "
  • ddd - the abbreviated day name (Mon - Sun)
  • " "
  • dddd - the long day name (Monday - Sunday)
  • " "
  • M - the month as a number without a leading zero (1-12)
  • " "
  • MM - the month as a number with a leading zero (01-12)
  • " "
  • MMM - the abbreviated month name (Jan - Dec)
  • " "
  • MMMM - the long month name (January - December)
  • " "
  • yy - the year as a two digit number (00-99)
  • " "
  • yyyy - the year as a four digit number (0000-9999)
  • " "
" "

These expressions may be used for the time:" "

" "
    " "
  • h - the hour without a leading zero (0-23 or 1-12 if AM/PM display)
  • " "
  • hh - the hour with a leading zero (00-23 or 01-12 if AM/PM display)
  • " "
  • m - the minutes without a leading zero (0-59)
  • " "
  • mm - the minutes with a leading zero (00-59)
  • " "
  • s - the seconds without a leading zero (0-59)
  • " "
  • ss - the seconds with a leading zero (00-59)
  • " "
  • z - the milliseconds without leading zeroes (0-999)
  • " "
  • zzz - the milliseconds with leading zeroes (000-999)
  • " "
  • AP - switch to AM/PM display. AP will be replaced by either \"AM\" or \"PM\".
  • " "
  • ap - switch to AM/PM display. ap will be replaced by either \"am\" or \"pm\".
  • " "
  • Z - time zone in numeric form (-0500)
  • " "
" "

All other input characters will be ignored." "

"); QWhatsThis::add( mCustomDateFormatEdit, customDateWhatsThis ); QWhatsThis::add( radio, customDateWhatsThis ); } } // end for loop populating mDateDisplay vlay->addWidget( mDateDisplay ); connect( mDateDisplay, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addStretch( 10 ); // spacer } void AppearancePage::HeadersTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); // "General Options": mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages", false ) ); mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize", false ) ); mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons", false ) ); mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon", true ) ); // "Message Header Threading Options": int num = geometry.readNumEntry( "nestingPolicy", 3 ); if ( num < 0 || num > 3 ) num = 3; mNestingPolicy->setButton( num ); // "Date Display": setDateDisplay( general.readNumEntry( "dateFormat", DateFormatter::Fancy ), general.readEntry( "customDateFormat" ) ); } void AppearancePage::HeadersTab::setDateDisplay( int num, const QString & format ) { DateFormatter::FormatType dateDisplay = static_cast( num ); // special case: needs text for the line edit: if ( dateDisplay == DateFormatter::Custom ) mCustomDateFormatEdit->setText( format ); for ( int i = 0 ; i < numDateDisplayConfig ; i++ ) if ( dateDisplay == dateDisplayConfig[i].dateDisplay ) { mDateDisplay->setButton( i ); return; } // fell through since none found: mDateDisplay->setButton( numDateDisplayConfig - 2 ); // default } void AppearancePage::HeadersTab::installProfile( KConfig * profile ) { KConfigGroup general( profile, "General" ); KConfigGroup geometry( profile, "Geometry" ); if ( geometry.hasKey( "nestedMessages" ) ) mNestedMessagesCheck->setChecked( geometry.readBoolEntry( "nestedMessages" ) ); if ( general.hasKey( "showMessageSize" ) ) mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize" ) ); if( general.hasKey( "showCryptoIcons" ) ) mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons" ) ); if ( general.hasKey( "showAttachmentIcon" ) ) mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon" ) ); if ( geometry.hasKey( "nestingPolicy" ) ) { int num = geometry.readNumEntry( "nestingPolicy" ); if ( num < 0 || num > 3 ) num = 3; mNestingPolicy->setButton( num ); } if ( general.hasKey( "dateFormat" ) ) setDateDisplay( general.readNumEntry( "dateFormat" ), general.readEntry( "customDateFormat" ) ); } void AppearancePage::HeadersTab::save() { KConfigGroup general( KMKernel::config(), "General" ); KConfigGroup geometry( KMKernel::config(), "Geometry" ); if ( geometry.readBoolEntry( "nestedMessages", false ) != mNestedMessagesCheck->isChecked() ) { int result = KMessageBox::warningContinueCancel( this, i18n("Changing the global threading setting will override " "all folder specific values."), QString::null, QString::null, "threadOverride" ); if ( result == KMessageBox::Continue ) { geometry.writeEntry( "nestedMessages", mNestedMessagesCheck->isChecked() ); // remove all threadMessagesOverride keys from all [Folder-*] groups: QStringList groups = KMKernel::config()->groupList().grep( QRegExp("^Folder-") ); kdDebug(5006) << "groups.count() == " << groups.count() << endl; for ( QStringList::const_iterator it = groups.begin() ; it != groups.end() ; ++it ) { KConfigGroup group( KMKernel::config(), *it ); group.deleteEntry( "threadMessagesOverride" ); } } } geometry.writeEntry( "nestingPolicy", mNestingPolicy->id( mNestingPolicy->selected() ) ); general.writeEntry( "showMessageSize", mMessageSizeCheck->isChecked() ); general.writeEntry( "showCryptoIcons", mCryptoIconsCheck->isChecked() ); general.writeEntry( "showAttachmentIcon", mAttachmentCheck->isChecked() ); int dateDisplayID = mDateDisplay->id( mDateDisplay->selected() ); // check bounds: assert( dateDisplayID >= 0 ); assert( dateDisplayID < numDateDisplayConfig ); general.writeEntry( "dateFormat", dateDisplayConfig[ dateDisplayID ].dateDisplay ); general.writeEntry( "customDateFormat", mCustomDateFormatEdit->text() ); } // // Message Window // static const BoolConfigEntry showColorbarMode = { "Reader", "showColorbar", I18N_NOOP("Show HTML stat&us bar"), false }; static const BoolConfigEntry showSpamStatusMode = { "Reader", "showSpamStatus", I18N_NOOP("Show s&pam status in fancy headers"), true }; static const BoolConfigEntry showEmoticons = { "Reader", "ShowEmoticons", I18N_NOOP("Replace smileys by emoticons"), true }; static const BoolConfigEntry shrinkQuotes = { "Reader", "ShrinkQuotes", I18N_NOOP("Use smaller font for quoted text"), false }; static const BoolConfigEntry showExpandQuotesMark= { "Reader", "ShowExpandQuotesMark", I18N_NOOP("Show expand/collapse quote marks"), false }; QString AppearancePage::ReaderTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-reader"); } AppearancePageReaderTab::AppearancePageReaderTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout *vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "show colorbar" check box: populateCheckBox( mShowColorbarCheck = new QCheckBox( this ), showColorbarMode ); vlay->addWidget( mShowColorbarCheck ); connect( mShowColorbarCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "show spam status" check box; populateCheckBox( mShowSpamStatusCheck = new QCheckBox( this ), showSpamStatusMode ); vlay->addWidget( mShowSpamStatusCheck ); connect( mShowSpamStatusCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "replace smileys by emoticons" check box; populateCheckBox( mShowEmoticonsCheck = new QCheckBox( this ), showEmoticons ); vlay->addWidget( mShowEmoticonsCheck ); connect( mShowEmoticonsCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Use smaller font for quoted text" check box mShrinkQuotesCheck = new QCheckBox( i18n( shrinkQuotes.desc ), this, "kcfg_ShrinkQuotes" ); vlay->addWidget( mShrinkQuotesCheck ); connect( mShrinkQuotesCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); // "Show expand/collaps quote marks" check box; QHBoxLayout *hlay= new QHBoxLayout( vlay ); // inherits spacing populateCheckBox( mShowExpandQuotesMark= new QCheckBox( this ), showExpandQuotesMark); hlay->addWidget( mShowExpandQuotesMark); connect( mShowExpandQuotesMark, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged() ) ); hlay->addStretch( 1 ); mCollapseQuoteLevelSpin = new KIntSpinBox( 0/*min*/,10/*max*/,1/*step*/, 3/*init*/,10/*base*/,this ); QLabel *label = new QLabel( mCollapseQuoteLevelSpin, GlobalSettings::self()->collapseQuoteLevelSpinItem()->label(), this ); hlay->addWidget( label ); mCollapseQuoteLevelSpin->setEnabled( false ); //since !mShowExpandQuotesMark->isCheckec() connect( mCollapseQuoteLevelSpin, SIGNAL( valueChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hlay->addWidget( mCollapseQuoteLevelSpin); connect( mShowExpandQuotesMark, SIGNAL( toggled( bool ) ), mCollapseQuoteLevelSpin, SLOT( setEnabled( bool ) ) ); // Fallback Character Encoding hlay = new QHBoxLayout( vlay ); // inherits spacing mCharsetCombo = new QComboBox( this ); mCharsetCombo->insertStringList( KMMsgBase::supportedEncodings( false ) ); connect( mCharsetCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); QString fallbackCharsetWhatsThis = i18n( GlobalSettings::self()->fallbackCharacterEncodingItem()->whatsThis().utf8() ); QWhatsThis::add( mCharsetCombo, fallbackCharsetWhatsThis ); label = new QLabel( i18n("Fallback ch&aracter encoding:"), this ); label->setBuddy( mCharsetCombo ); hlay->addWidget( label ); hlay->addWidget( mCharsetCombo ); // Override Character Encoding QHBoxLayout *hlay2 = new QHBoxLayout( vlay ); // inherits spacing mOverrideCharsetCombo = new QComboBox( this ); QStringList encodings = KMMsgBase::supportedEncodings( false ); encodings.prepend( i18n( "Auto" ) ); mOverrideCharsetCombo->insertStringList( encodings ); mOverrideCharsetCombo->setCurrentItem(0); connect( mOverrideCharsetCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); QString overrideCharsetWhatsThis = i18n( GlobalSettings::self()->overrideCharacterEncodingItem()->whatsThis().utf8() ); QWhatsThis::add( mOverrideCharsetCombo, overrideCharsetWhatsThis ); label = new QLabel( i18n("&Override character encoding:"), this ); label->setBuddy( mOverrideCharsetCombo ); hlay2->addWidget( label ); hlay2->addWidget( mOverrideCharsetCombo ); vlay->addStretch( 100 ); // spacer } void AppearancePage::ReaderTab::readCurrentFallbackCodec() { QStringList encodings = KMMsgBase::supportedEncodings( false ); QStringList::ConstIterator it( encodings.begin() ); QStringList::ConstIterator end( encodings.end() ); const QString ¤tEncoding = GlobalSettings::self()->fallbackCharacterEncoding(); int i = 0; for( ; it != end; ++it) { if( KGlobal::charsets()->encodingForName(*it) == currentEncoding ) { mCharsetCombo->setCurrentItem( i ); break; } i++; } } void AppearancePage::ReaderTab::readCurrentOverrideCodec() { const QString ¤tOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding(); if ( currentOverrideEncoding.isEmpty() ) { mOverrideCharsetCombo->setCurrentItem( 0 ); return; } QStringList encodings = KMMsgBase::supportedEncodings( false ); encodings.prepend( i18n( "Auto" ) ); QStringList::Iterator it( encodings.begin() ); QStringList::Iterator end( encodings.end() ); int i = 0; for( ; it != end; ++it) { if( KGlobal::charsets()->encodingForName(*it) == currentOverrideEncoding ) { mOverrideCharsetCombo->setCurrentItem( i ); break; } i++; } } void AppearancePage::ReaderTab::doLoadFromGlobalSettings() { mShowEmoticonsCheck->setChecked( GlobalSettings::self()->showEmoticons() ); mShrinkQuotesCheck->setChecked( GlobalSettings::self()->shrinkQuotes() ); mShowExpandQuotesMark->setChecked( GlobalSettings::self()->showExpandQuotesMark() ); mCollapseQuoteLevelSpin->setValue( GlobalSettings::self()->collapseQuoteLevelSpin() ); readCurrentFallbackCodec(); readCurrentOverrideCodec(); } void AppearancePage::ReaderTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); loadWidget( mShowColorbarCheck, reader, showColorbarMode ); loadWidget( mShowSpamStatusCheck, reader, showSpamStatusMode ); } void AppearancePage::ReaderTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); saveCheckBox( mShowColorbarCheck, reader, showColorbarMode ); saveCheckBox( mShowSpamStatusCheck, reader, showSpamStatusMode ); GlobalSettings::self()->setShowEmoticons( mShowEmoticonsCheck->isChecked() ); GlobalSettings::self()->setShrinkQuotes( mShrinkQuotesCheck->isChecked() ); GlobalSettings::self()->setShowExpandQuotesMark( mShowExpandQuotesMark->isChecked() ); GlobalSettings::self()->setCollapseQuoteLevelSpin( mCollapseQuoteLevelSpin->value() ); GlobalSettings::self()->setFallbackCharacterEncoding( KGlobal::charsets()->encodingForName( mCharsetCombo->currentText() ) ); GlobalSettings::self()->setOverrideCharacterEncoding( mOverrideCharsetCombo->currentItem() == 0 ? QString() : KGlobal::charsets()->encodingForName( mOverrideCharsetCombo->currentText() ) ); } void AppearancePage::ReaderTab::installProfile( KConfig * /* profile */ ) { const KConfigGroup reader( KMKernel::config(), "Reader" ); loadProfile( mShowColorbarCheck, reader, showColorbarMode ); loadProfile( mShowSpamStatusCheck, reader, showSpamStatusMode ); loadProfile( mShowEmoticonsCheck, reader, showEmoticons ); loadProfile( mShrinkQuotesCheck, reader, shrinkQuotes ); loadProfile( mShowExpandQuotesMark, reader, showExpandQuotesMark); } QString AppearancePage::SystemTrayTab::helpAnchor() const { return QString::fromLatin1("configure-appearance-systemtray"); } AppearancePageSystemTrayTab::AppearancePageSystemTrayTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Enable system tray applet" check box mSystemTrayCheck = new QCheckBox( i18n("Enable system tray icon"), this ); vlay->addWidget( mSystemTrayCheck ); connect( mSystemTrayCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // System tray modes mSystemTrayGroup = new QVButtonGroup( i18n("System Tray Mode"), this ); mSystemTrayGroup->layout()->setSpacing( KDialog::spacingHint() ); vlay->addWidget( mSystemTrayGroup ); connect( mSystemTrayGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mSystemTrayCheck, SIGNAL( toggled( bool ) ), mSystemTrayGroup, SLOT( setEnabled( bool ) ) ); mSystemTrayGroup->insert( new QRadioButton( i18n("Always show KMail in system tray"), mSystemTrayGroup ), GlobalSettings::EnumSystemTrayPolicy::ShowAlways ); mSystemTrayGroup->insert( new QRadioButton( i18n("Only show KMail in system tray if there are unread messages"), mSystemTrayGroup ), GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ); vlay->addStretch( 10 ); // spacer } void AppearancePage::SystemTrayTab::doLoadFromGlobalSettings() { mSystemTrayCheck->setChecked( GlobalSettings::self()->systemTrayEnabled() ); mSystemTrayGroup->setButton( GlobalSettings::self()->systemTrayPolicy() ); mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() ); } void AppearancePage::SystemTrayTab::installProfile( KConfig * profile ) { KConfigGroup general( profile, "General" ); if ( general.hasKey( "SystemTrayEnabled" ) ) { mSystemTrayCheck->setChecked( general.readBoolEntry( "SystemTrayEnabled" ) ); } if ( general.hasKey( "SystemTrayPolicy" ) ) { mSystemTrayGroup->setButton( general.readNumEntry( "SystemTrayPolicy" ) ); } mSystemTrayGroup->setEnabled( mSystemTrayCheck->isChecked() ); } void AppearancePage::SystemTrayTab::save() { GlobalSettings::self()->setSystemTrayEnabled( mSystemTrayCheck->isChecked() ); GlobalSettings::self()->setSystemTrayPolicy( mSystemTrayGroup->id( mSystemTrayGroup->selected() ) ); } // ************************************************************* // * * // * ComposerPage * // * * // ************************************************************* QString ComposerPage::helpAnchor() const { return QString::fromLatin1("configure-composer"); } ComposerPage::ComposerPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "General" tab: // mGeneralTab = new GeneralTab(); addTab( mGeneralTab, i18n("&General") ); addConfig( GlobalSettings::self(), mGeneralTab ); // // "Phrases" tab: // mPhrasesTab = new PhrasesTab(); addTab( mPhrasesTab, i18n("&Phrases") ); // // "Subject" tab: // mSubjectTab = new SubjectTab(); addTab( mSubjectTab, i18n("&Subject") ); addConfig( GlobalSettings::self(), mSubjectTab ); // // "Charset" tab: // mCharsetTab = new CharsetTab(); addTab( mCharsetTab, i18n("Cha&rset") ); // // "Headers" tab: // mHeadersTab = new HeadersTab(); addTab( mHeadersTab, i18n("M&essage List") ); // // "Attachments" tab: // mAttachmentsTab = new AttachmentsTab(); addTab( mAttachmentsTab, i18n("Config->Composer->Attachments", "A&ttachments") ); load(); } QString ComposerPage::GeneralTab::helpAnchor() const { return QString::fromLatin1("configure-composer-general"); } ComposerPageGeneralTab::ComposerPageGeneralTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QGroupBox *group; QLabel *label; QHBox *hbox; QString msg; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // some check buttons... mAutoAppSignFileCheck = new QCheckBox( GlobalSettings::self()->autoTextSignatureItem()->label(), this ); vlay->addWidget( mAutoAppSignFileCheck ); connect( mAutoAppSignFileCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mSmartQuoteCheck = new QCheckBox( GlobalSettings::self()->smartQuoteItem()->label(), this, "kcfg_SmartQuote" ); vlay->addWidget( mSmartQuoteCheck ); connect( mSmartQuoteCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mAutoRequestMDNCheck = new QCheckBox( GlobalSettings::self()->requestMDNItem()->label(), this, "kcfg_RequestMDN" ); vlay->addWidget( mAutoRequestMDNCheck ); connect( mAutoRequestMDNCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mShowRecentAddressesInComposer = new QCheckBox( GlobalSettings::self()->showRecentAddressesInComposerItem()->label(), this, "kcfg_ShowRecentAddressesInComposer" ); vlay->addWidget( mShowRecentAddressesInComposer ); connect( mShowRecentAddressesInComposer, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); // a checkbox for "word wrap" and a spinbox for the column in // which to wrap: hlay = new QHBoxLayout( vlay ); // inherits spacing mWordWrapCheck = new QCheckBox( GlobalSettings::self()->wordWrapItem()->label(), this, "kcfg_WordWrap" ); hlay->addWidget( mWordWrapCheck ); connect( mWordWrapCheck, SIGNAL( stateChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); mWrapColumnSpin = new KIntSpinBox( 30/*min*/, 78/*max*/, 1/*step*/, 78/*init*/, 10 /*base*/, this, "kcfg_LineWrapWidth" ); mWrapColumnSpin->setEnabled( false ); // since !mWordWrapCheck->isChecked() connect( mWrapColumnSpin, SIGNAL( valueChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); hlay->addWidget( mWrapColumnSpin ); hlay->addStretch( 1 ); // only enable the spinbox if the checkbox is checked: connect( mWordWrapCheck, SIGNAL(toggled(bool)), mWrapColumnSpin, SLOT(setEnabled(bool)) ); hlay = new QHBoxLayout( vlay ); // inherits spacing mAutoSave = new KIntSpinBox( 0, 60, 1, 1, 10, this, "kcfg_AutosaveInterval" ); label = new QLabel( mAutoSave, GlobalSettings::self()->autosaveIntervalItem()->label(), this ); hlay->addWidget( label ); hlay->addWidget( mAutoSave ); mAutoSave->setSpecialValueText( i18n("No autosave") ); mAutoSave->setSuffix( i18n(" min") ); hlay->addStretch( 1 ); connect( mAutoSave, SIGNAL( valueChanged(int) ), this, SLOT( slotEmitChanged( void ) ) ); hlay = new QHBoxLayout( vlay ); // inherits spacing - QPushButton *completionOrderBtn = new QPushButton( i18n( "Configure completion order" ), this ); + QPushButton *completionOrderBtn = new QPushButton( i18n( "Configure Completion Order" ), this ); connect( completionOrderBtn, SIGNAL( clicked() ), this, SLOT( slotConfigureCompletionOrder() ) ); hlay->addWidget( completionOrderBtn ); hlay->addItem( new QSpacerItem(0, 0) ); // recent addresses hlay = new QHBoxLayout( vlay ); // inherits spacing - QPushButton *recentAddressesBtn = new QPushButton( i18n( "Edit recent addresses" ), this ); + QPushButton *recentAddressesBtn = new QPushButton( i18n( "Edit Recent Addresses" ), this ); connect( recentAddressesBtn, SIGNAL( clicked() ), this, SLOT( slotConfigureRecentAddresses() ) ); hlay->addWidget( recentAddressesBtn ); hlay->addItem( new QSpacerItem(0, 0) ); // The "external editor" group: group = new QVGroupBox( i18n("External Editor"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mExternalEditorCheck = new QCheckBox( GlobalSettings::self()->useExternalEditorItem()->label(), group, "kcfg_UseExternalEditor" ); connect( mExternalEditorCheck, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); label = new QLabel( GlobalSettings::self()->externalEditorItem()->label(), hbox ); mEditorRequester = new KURLRequester( hbox, "kcfg_ExternalEditor" ); connect( mEditorRequester, SIGNAL( urlSelected(const QString&) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mEditorRequester, SIGNAL( textChanged(const QString&) ), this, SLOT( slotEmitChanged( void ) ) ); hbox->setStretchFactor( mEditorRequester, 1 ); label->setBuddy( mEditorRequester ); label->setEnabled( false ); // since !mExternalEditorCheck->isChecked() // ### FIXME: allow only executables (x-bit when available..) mEditorRequester->setFilter( "application/x-executable " "application/x-shellscript " "application/x-desktop" ); mEditorRequester->setEnabled( false ); // !mExternalEditorCheck->isChecked() connect( mExternalEditorCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); connect( mExternalEditorCheck, SIGNAL(toggled(bool)), mEditorRequester, SLOT(setEnabled(bool)) ); label = new QLabel( i18n("%f will be replaced with the " "filename to edit."), group ); label->setEnabled( false ); // see above connect( mExternalEditorCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); vlay->addWidget( group ); vlay->addStretch( 100 ); } void ComposerPage::GeneralTab::doLoadFromGlobalSettings() { // various check boxes: mAutoAppSignFileCheck->setChecked( GlobalSettings::self()->autoTextSignature()=="auto" ); mSmartQuoteCheck->setChecked( GlobalSettings::self()->smartQuote() ); mAutoRequestMDNCheck->setChecked( GlobalSettings::self()->requestMDN() ); mWordWrapCheck->setChecked( GlobalSettings::self()->wordWrap() ); mWrapColumnSpin->setValue( GlobalSettings::self()->lineWrapWidth() ); mAutoSave->setValue( GlobalSettings::self()->autosaveInterval() ); // editor group: mExternalEditorCheck->setChecked( GlobalSettings::self()->useExternalEditor() ); mEditorRequester->setURL( GlobalSettings::self()->externalEditor() ); } void ComposerPage::GeneralTab::installProfile( KConfig * profile ) { KConfigGroup composer( profile, "Composer" ); KConfigGroup general( profile, "General" ); if ( composer.hasKey( "signature" ) ) { bool state = composer.readBoolEntry("signature"); mAutoAppSignFileCheck->setChecked( state ); } if ( composer.hasKey( "smart-quote" ) ) mSmartQuoteCheck->setChecked( composer.readBoolEntry( "smart-quote" ) ); if ( composer.hasKey( "request-mdn" ) ) mAutoRequestMDNCheck->setChecked( composer.readBoolEntry( "request-mdn" ) ); if ( composer.hasKey( "word-wrap" ) ) mWordWrapCheck->setChecked( composer.readBoolEntry( "word-wrap" ) ); if ( composer.hasKey( "break-at" ) ) mWrapColumnSpin->setValue( composer.readNumEntry( "break-at" ) ); if ( composer.hasKey( "autosave" ) ) mAutoSave->setValue( composer.readNumEntry( "autosave" ) ); if ( general.hasKey( "use-external-editor" ) && general.hasKey( "external-editor" ) ) { mExternalEditorCheck->setChecked( general.readBoolEntry( "use-external-editor" ) ); mEditorRequester->setURL( general.readPathEntry( "external-editor" ) ); } } void ComposerPage::GeneralTab::save() { GlobalSettings::self()->setAutoTextSignature( mAutoAppSignFileCheck->isChecked() ? "auto" : "manual" ); GlobalSettings::self()->setSmartQuote( mSmartQuoteCheck->isChecked() ); GlobalSettings::self()->setRequestMDN( mAutoRequestMDNCheck->isChecked() ); GlobalSettings::self()->setWordWrap( mWordWrapCheck->isChecked() ); GlobalSettings::self()->setLineWrapWidth( mWrapColumnSpin->value() ); GlobalSettings::self()->setAutosaveInterval( mAutoSave->value() ); // editor group: GlobalSettings::self()->setUseExternalEditor( mExternalEditorCheck->isChecked() ); GlobalSettings::self()->setExternalEditor( mEditorRequester->url() ); } void ComposerPage::GeneralTab::slotConfigureRecentAddresses( ) { KRecentAddress::RecentAddressDialog dlg( this ); dlg.setAddresses( RecentAddresses::self( KMKernel::config() )->addresses() ); if ( dlg.exec() ) { RecentAddresses::self( KMKernel::config() )->clear(); const QStringList &addrList = dlg.addresses(); QStringList::ConstIterator it; for ( it = addrList.constBegin(); it != addrList.constEnd(); ++it ) RecentAddresses::self( KMKernel::config() )->add( *it ); } } void ComposerPage::GeneralTab::slotConfigureCompletionOrder( ) { KPIM::LdapSearch search; KPIM::CompletionOrderEditor editor( &search, this ); editor.exec(); } QString ComposerPage::PhrasesTab::helpAnchor() const { return QString::fromLatin1("configure-composer-phrases"); } ComposerPagePhrasesTab::ComposerPagePhrasesTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QGridLayout *glay; QPushButton *button; glay = new QGridLayout( this, 7, 3, KDialog::spacingHint() ); glay->setMargin( KDialog::marginHint() ); glay->setColStretch( 1, 1 ); glay->setColStretch( 2, 1 ); glay->setRowStretch( 7, 1 ); // row 0: help text glay->addMultiCellWidget( new QLabel( i18n("The following placeholders are " "supported in the reply phrases:
" "%D: date, %S: subject,
" "%e: sender's address, %F: sender's name, %f: sender's initials,
" "%T: recipient's name, %t: recipient's name and address,
" "%C: carbon copy names, %c: carbon copy names and addresses,
" "%%: percent sign, %_: space, " "%L: linebreak
"), this ), 0, 0, 0, 2 ); // row 0; cols 0..2 // row 1: label and language combo box: mPhraseLanguageCombo = new LanguageComboBox( false, this ); glay->addWidget( new QLabel( mPhraseLanguageCombo, i18n("Lang&uage:"), this ), 1, 0 ); glay->addMultiCellWidget( mPhraseLanguageCombo, 1, 1, 1, 2 ); connect( mPhraseLanguageCombo, SIGNAL(activated(const QString&)), this, SLOT(slotLanguageChanged(const QString&)) ); // row 2: "add..." and "remove" push buttons: button = new QPushButton( i18n("A&dd..."), this ); button->setAutoDefault( false ); glay->addWidget( button, 2, 1 ); mRemoveButton = new QPushButton( i18n("Re&move"), this ); mRemoveButton->setAutoDefault( false ); mRemoveButton->setEnabled( false ); // combo doesn't contain anything... glay->addWidget( mRemoveButton, 2, 2 ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewLanguage()) ); connect( mRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveLanguage()) ); // row 3: "reply to sender" line edit and label: mPhraseReplyEdit = new KLineEdit( this ); connect( mPhraseReplyEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseReplyEdit, i18n("Reply to se&nder:"), this ), 3, 0 ); glay->addMultiCellWidget( mPhraseReplyEdit, 3, 3, 1, 2 ); // cols 1..2 // row 4: "reply to all" line edit and label: mPhraseReplyAllEdit = new KLineEdit( this ); connect( mPhraseReplyAllEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseReplyAllEdit, i18n("Repl&y to all:"), this ), 4, 0 ); glay->addMultiCellWidget( mPhraseReplyAllEdit, 4, 4, 1, 2 ); // cols 1..2 // row 5: "forward" line edit and label: mPhraseForwardEdit = new KLineEdit( this ); connect( mPhraseForwardEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseForwardEdit, i18n("&Forward:"), this ), 5, 0 ); glay->addMultiCellWidget( mPhraseForwardEdit, 5, 5, 1, 2 ); // cols 1..2 // row 6: "quote indicator" line edit and label: mPhraseIndentPrefixEdit = new KLineEdit( this ); connect( mPhraseIndentPrefixEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); glay->addWidget( new QLabel( mPhraseIndentPrefixEdit, i18n("&Quote indicator:"), this ), 6, 0 ); glay->addMultiCellWidget( mPhraseIndentPrefixEdit, 6, 6, 1, 2 ); // row 7: spacer } void ComposerPage::PhrasesTab::setLanguageItemInformation( int index ) { assert( 0 <= index && index < (int)mLanguageList.count() ); LanguageItem &l = *mLanguageList.at( index ); mPhraseReplyEdit->setText( l.mReply ); mPhraseReplyAllEdit->setText( l.mReplyAll ); mPhraseForwardEdit->setText( l.mForward ); mPhraseIndentPrefixEdit->setText( l.mIndentPrefix ); } void ComposerPage::PhrasesTab::saveActiveLanguageItem() { int index = mActiveLanguageItem; if (index == -1) return; assert( 0 <= index && index < (int)mLanguageList.count() ); LanguageItem &l = *mLanguageList.at( index ); l.mReply = mPhraseReplyEdit->text(); l.mReplyAll = mPhraseReplyAllEdit->text(); l.mForward = mPhraseForwardEdit->text(); l.mIndentPrefix = mPhraseIndentPrefixEdit->text(); } void ComposerPage::PhrasesTab::slotNewLanguage() { NewLanguageDialog dialog( mLanguageList, parentWidget(), "New", true ); if ( dialog.exec() == QDialog::Accepted ) slotAddNewLanguage( dialog.language() ); } void ComposerPage::PhrasesTab::slotAddNewLanguage( const QString& lang ) { mPhraseLanguageCombo->setCurrentItem( mPhraseLanguageCombo->insertLanguage( lang ) ); KLocale locale("kmail"); locale.setLanguage( lang ); mLanguageList.append( LanguageItem( lang, locale.translate("On %D, you wrote:"), locale.translate("On %D, %F wrote:"), locale.translate("Forwarded Message"), locale.translate(">%_") ) ); mRemoveButton->setEnabled( true ); slotLanguageChanged( QString::null ); } void ComposerPage::PhrasesTab::slotRemoveLanguage() { assert( mPhraseLanguageCombo->count() > 1 ); int index = mPhraseLanguageCombo->currentItem(); assert( 0 <= index && index < (int)mLanguageList.count() ); // remove current item from internal list and combobox: mLanguageList.remove( mLanguageList.at( index ) ); mPhraseLanguageCombo->removeItem( index ); if ( index >= (int)mLanguageList.count() ) index--; mActiveLanguageItem = index; setLanguageItemInformation( index ); mRemoveButton->setEnabled( mLanguageList.count() > 1 ); emit changed( true ); } void ComposerPage::PhrasesTab::slotLanguageChanged( const QString& ) { int index = mPhraseLanguageCombo->currentItem(); assert( index < (int)mLanguageList.count() ); saveActiveLanguageItem(); mActiveLanguageItem = index; setLanguageItemInformation( index ); emit changed( true ); } void ComposerPage::PhrasesTab::doLoadFromGlobalSettings() { mLanguageList.clear(); mPhraseLanguageCombo->clear(); mActiveLanguageItem = -1; int numLang = GlobalSettings::self()->replyLanguagesCount(); int currentNr = GlobalSettings::self()->replyCurrentLanguage(); // build mLanguageList and mPhraseLanguageCombo: for ( int i = 0 ; i < numLang ; i++ ) { ReplyPhrases replyPhrases( QString::number(i) ); replyPhrases.readConfig(); QString lang = replyPhrases.language(); mLanguageList.append( LanguageItem( lang, replyPhrases.phraseReplySender(), replyPhrases.phraseReplyAll(), replyPhrases.phraseForward(), replyPhrases.indentPrefix() ) ); mPhraseLanguageCombo->insertLanguage( lang ); } if ( currentNr >= numLang || currentNr < 0 ) currentNr = 0; if ( numLang == 0 ) { slotAddNewLanguage( KGlobal::locale()->language() ); } mPhraseLanguageCombo->setCurrentItem( currentNr ); mActiveLanguageItem = currentNr; setLanguageItemInformation( currentNr ); mRemoveButton->setEnabled( mLanguageList.count() > 1 ); } void ComposerPage::PhrasesTab::save() { GlobalSettings::self()->setReplyLanguagesCount( mLanguageList.count() ); GlobalSettings::self()->setReplyCurrentLanguage( mPhraseLanguageCombo->currentItem() ); saveActiveLanguageItem(); LanguageItemList::Iterator it = mLanguageList.begin(); for ( int i = 0 ; it != mLanguageList.end() ; ++it, ++i ) { ReplyPhrases replyPhrases( QString::number(i) ); replyPhrases.setLanguage( (*it).mLanguage ); replyPhrases.setPhraseReplySender( (*it).mReply ); replyPhrases.setPhraseReplyAll( (*it).mReplyAll ); replyPhrases.setPhraseForward( (*it).mForward ); replyPhrases.setIndentPrefix( (*it).mIndentPrefix ); replyPhrases.writeConfig(); } } QString ComposerPage::SubjectTab::helpAnchor() const { return QString::fromLatin1("configure-composer-subject"); } ComposerPageSubjectTab::ComposerPageSubjectTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QGroupBox *group; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); group = new QVGroupBox( i18n("Repl&y Subject Prefixes"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); // row 0: help text: label = new QLabel( i18n("Recognize any sequence of the following prefixes\n" "(entries are case-insensitive regular expressions):"), group ); label->setAlignment( AlignLeft|WordBreak ); // row 1, string list editor: SimpleStringListEditor::ButtonCode buttonCode = static_cast( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify ); mReplyListEditor = new SimpleStringListEditor( group, 0, buttonCode, i18n("A&dd..."), i18n("Re&move"), i18n("Mod&ify..."), i18n("Enter new reply prefix:") ); connect( mReplyListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); // row 2: "replace [...]" check box: mReplaceReplyPrefixCheck = new QCheckBox( GlobalSettings::self()->replaceReplyPrefixItem()->label(), group, "kcfg_ReplaceReplyPrefix" ); connect( mReplaceReplyPrefixCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); group = new QVGroupBox( i18n("For&ward Subject Prefixes"), this ); group->layout()->setSpacing( KDialog::marginHint() ); // row 0: help text: label= new QLabel( i18n("Recognize any sequence of the following prefixes\n" "(entries are case-insensitive regular expressions):"), group ); label->setAlignment( AlignLeft|WordBreak ); // row 1: string list editor mForwardListEditor = new SimpleStringListEditor( group, 0, buttonCode, i18n("Add..."), i18n("Remo&ve"), i18n("Modify..."), i18n("Enter new forward prefix:") ); connect( mForwardListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); // row 3: "replace [...]" check box: mReplaceForwardPrefixCheck = new QCheckBox( GlobalSettings::self()->replaceForwardPrefixItem()->label(), group, "kcfg_ReplaceForwardPrefix" ); connect( mReplaceForwardPrefixCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( group ); } void ComposerPage::SubjectTab::doLoadFromGlobalSettings() { mReplyListEditor->setStringList( GlobalSettings::self()->replyPrefixes() ); mReplaceReplyPrefixCheck->setChecked( GlobalSettings::self()->replaceReplyPrefix() ); mForwardListEditor->setStringList( GlobalSettings::self()->forwardPrefixes() ); mReplaceForwardPrefixCheck->setChecked( GlobalSettings::self()->replaceForwardPrefix() ); } void ComposerPage::SubjectTab::save() { GlobalSettings::self()->setReplyPrefixes( mReplyListEditor->stringList() ); GlobalSettings::self()->setForwardPrefixes( mForwardListEditor->stringList() ); } QString ComposerPage::CharsetTab::helpAnchor() const { return QString::fromLatin1("configure-composer-charset"); } ComposerPageCharsetTab::ComposerPageCharsetTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); label = new QLabel( i18n("This list is checked for every outgoing message " "from the top to the bottom for a charset that " "contains all required characters."), this ); label->setAlignment( WordBreak); vlay->addWidget( label ); mCharsetListEditor = new SimpleStringListEditor( this, 0, SimpleStringListEditor::All, i18n("A&dd..."), i18n("Remo&ve"), i18n("&Modify..."), i18n("Enter charset:") ); connect( mCharsetListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mCharsetListEditor, 1 ); mKeepReplyCharsetCheck = new QCheckBox( i18n("&Keep original charset when " "replying or forwarding (if " "possible)"), this ); connect( mKeepReplyCharsetCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mKeepReplyCharsetCheck ); connect( mCharsetListEditor, SIGNAL(aboutToAdd(QString&)), this, SLOT(slotVerifyCharset(QString&)) ); } void ComposerPage::CharsetTab::slotVerifyCharset( QString & charset ) { if ( charset.isEmpty() ) return; // KCharsets::codecForName("us-ascii") returns "iso-8859-1" (cf. Bug #49812) // therefore we have to treat this case specially if ( charset.lower() == QString::fromLatin1("us-ascii") ) { charset = QString::fromLatin1("us-ascii"); return; } if ( charset.lower() == QString::fromLatin1("locale") ) { charset = QString::fromLatin1("%1 (locale)") .arg( QCString( kmkernel->networkCodec()->mimeName() ).lower() ); return; } bool ok = false; QTextCodec *codec = KGlobal::charsets()->codecForName( charset, ok ); if ( ok && codec ) { charset = QString::fromLatin1( codec->mimeName() ).lower(); return; } KMessageBox::sorry( this, i18n("This charset is not supported.") ); charset = QString::null; } void ComposerPage::CharsetTab::doLoadOther() { KConfigGroup composer( KMKernel::config(), "Composer" ); QStringList charsets = composer.readListEntry( "pref-charsets" ); for ( QStringList::Iterator it = charsets.begin() ; it != charsets.end() ; ++it ) if ( (*it) == QString::fromLatin1("locale") ) { QCString cset = kmkernel->networkCodec()->mimeName(); KPIM::kAsciiToLower( cset.data() ); (*it) = QString("%1 (locale)").arg( cset ); } mCharsetListEditor->setStringList( charsets ); mKeepReplyCharsetCheck->setChecked( !composer.readBoolEntry( "force-reply-charset", false ) ); } void ComposerPage::CharsetTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); QStringList charsetList = mCharsetListEditor->stringList(); QStringList::Iterator it = charsetList.begin(); for ( ; it != charsetList.end() ; ++it ) if ( (*it).endsWith("(locale)") ) (*it) = "locale"; composer.writeEntry( "pref-charsets", charsetList ); composer.writeEntry( "force-reply-charset", !mKeepReplyCharsetCheck->isChecked() ); } QString ComposerPage::HeadersTab::helpAnchor() const { return QString::fromLatin1("configure-composer-headers"); } ComposerPageHeadersTab::ComposerPageHeadersTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QGridLayout *glay; QLabel *label; QPushButton *button; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Use custom Message-Id suffix" checkbox: mCreateOwnMessageIdCheck = new QCheckBox( i18n("&Use custom message-id suffix"), this ); connect( mCreateOwnMessageIdCheck, SIGNAL ( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mCreateOwnMessageIdCheck ); // "Message-Id suffix" line edit and label: hlay = new QHBoxLayout( vlay ); // inherits spacing mMessageIdSuffixEdit = new KLineEdit( this ); // only ASCII letters, digits, plus, minus and dots are allowed mMessageIdSuffixValidator = new QRegExpValidator( QRegExp( "[a-zA-Z0-9+-]+(?:\\.[a-zA-Z0-9+-]+)*" ), this ); mMessageIdSuffixEdit->setValidator( mMessageIdSuffixValidator ); label = new QLabel( mMessageIdSuffixEdit, i18n("Custom message-&id suffix:"), this ); label->setEnabled( false ); // since !mCreateOwnMessageIdCheck->isChecked() mMessageIdSuffixEdit->setEnabled( false ); hlay->addWidget( label ); hlay->addWidget( mMessageIdSuffixEdit, 1 ); connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ), label, SLOT(setEnabled(bool)) ); connect( mCreateOwnMessageIdCheck, SIGNAL(toggled(bool) ), mMessageIdSuffixEdit, SLOT(setEnabled(bool)) ); connect( mMessageIdSuffixEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged( void ) ) ); // horizontal rule and "custom header fields" label: vlay->addWidget( new KSeparator( KSeparator::HLine, this ) ); vlay->addWidget( new QLabel( i18n("Define custom mime header fields:"), this) ); // "custom header fields" listbox: glay = new QGridLayout( vlay, 5, 3 ); // inherits spacing glay->setRowStretch( 2, 1 ); glay->setColStretch( 1, 1 ); mTagList = new ListView( this, "tagList" ); mTagList->addColumn( i18n("Name") ); mTagList->addColumn( i18n("Value") ); mTagList->setAllColumnsShowFocus( true ); mTagList->setSorting( -1 ); connect( mTagList, SIGNAL(selectionChanged()), this, SLOT(slotMimeHeaderSelectionChanged()) ); glay->addMultiCellWidget( mTagList, 0, 2, 0, 1 ); // "new" and "remove" buttons: button = new QPushButton( i18n("Ne&w"), this ); connect( button, SIGNAL(clicked()), this, SLOT(slotNewMimeHeader()) ); button->setAutoDefault( false ); glay->addWidget( button, 0, 2 ); mRemoveHeaderButton = new QPushButton( i18n("Re&move"), this ); connect( mRemoveHeaderButton, SIGNAL(clicked()), this, SLOT(slotRemoveMimeHeader()) ); button->setAutoDefault( false ); glay->addWidget( mRemoveHeaderButton, 1, 2 ); // "name" and "value" line edits and labels: mTagNameEdit = new KLineEdit( this ); mTagNameEdit->setEnabled( false ); mTagNameLabel = new QLabel( mTagNameEdit, i18n("&Name:"), this ); mTagNameLabel->setEnabled( false ); glay->addWidget( mTagNameLabel, 3, 0 ); glay->addWidget( mTagNameEdit, 3, 1 ); connect( mTagNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotMimeHeaderNameChanged(const QString&)) ); mTagValueEdit = new KLineEdit( this ); mTagValueEdit->setEnabled( false ); mTagValueLabel = new QLabel( mTagValueEdit, i18n("&Value:"), this ); mTagValueLabel->setEnabled( false ); glay->addWidget( mTagValueLabel, 4, 0 ); glay->addWidget( mTagValueEdit, 4, 1 ); connect( mTagValueEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotMimeHeaderValueChanged(const QString&)) ); } void ComposerPage::HeadersTab::slotMimeHeaderSelectionChanged() { QListViewItem * item = mTagList->selectedItem(); if ( item ) { mTagNameEdit->setText( item->text( 0 ) ); mTagValueEdit->setText( item->text( 1 ) ); } else { mTagNameEdit->clear(); mTagValueEdit->clear(); } mRemoveHeaderButton->setEnabled( item ); mTagNameEdit->setEnabled( item ); mTagValueEdit->setEnabled( item ); mTagNameLabel->setEnabled( item ); mTagValueLabel->setEnabled( item ); } void ComposerPage::HeadersTab::slotMimeHeaderNameChanged( const QString & text ) { // is called on ::setup(), when clearing the line edits. So be // prepared to not find a selection: QListViewItem * item = mTagList->selectedItem(); if ( item ) item->setText( 0, text ); emit changed( true ); } void ComposerPage::HeadersTab::slotMimeHeaderValueChanged( const QString & text ) { // is called on ::setup(), when clearing the line edits. So be // prepared to not find a selection: QListViewItem * item = mTagList->selectedItem(); if ( item ) item->setText( 1, text ); emit changed( true ); } void ComposerPage::HeadersTab::slotNewMimeHeader() { QListViewItem *listItem = new QListViewItem( mTagList ); mTagList->setCurrentItem( listItem ); mTagList->setSelected( listItem, true ); emit changed( true ); } void ComposerPage::HeadersTab::slotRemoveMimeHeader() { // calling this w/o selection is a programming error: QListViewItem * item = mTagList->selectedItem(); if ( !item ) { kdDebug(5006) << "==================================================\n" << "Error: Remove button was pressed although no custom header was selected\n" << "==================================================\n"; return; } QListViewItem * below = item->nextSibling(); delete item; if ( below ) mTagList->setSelected( below, true ); else if ( mTagList->lastItem() ) mTagList->setSelected( mTagList->lastItem(), true ); emit changed( true ); } void ComposerPage::HeadersTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); QString suffix = general.readEntry( "myMessageIdSuffix" ); mMessageIdSuffixEdit->setText( suffix ); bool state = ( !suffix.isEmpty() && general.readBoolEntry( "useCustomMessageIdSuffix", false ) ); mCreateOwnMessageIdCheck->setChecked( state ); mTagList->clear(); mTagNameEdit->clear(); mTagValueEdit->clear(); QListViewItem * item = 0; int count = general.readNumEntry( "mime-header-count", 0 ); for( int i = 0 ; i < count ; i++ ) { KConfigGroup config( KMKernel::config(), QCString("Mime #") + QCString().setNum(i) ); QString name = config.readEntry( "name" ); QString value = config.readEntry( "value" ); if( !name.isEmpty() ) item = new QListViewItem( mTagList, item, name, value ); } if ( mTagList->childCount() ) { mTagList->setCurrentItem( mTagList->firstChild() ); mTagList->setSelected( mTagList->firstChild(), true ); } else { // disable the "Remove" button mRemoveHeaderButton->setEnabled( false ); } } void ComposerPage::HeadersTab::save() { KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "useCustomMessageIdSuffix", mCreateOwnMessageIdCheck->isChecked() ); general.writeEntry( "myMessageIdSuffix", mMessageIdSuffixEdit->text() ); int numValidEntries = 0; QListViewItem * item = mTagList->firstChild(); for ( ; item ; item = item->itemBelow() ) if( !item->text(0).isEmpty() ) { KConfigGroup config( KMKernel::config(), QCString("Mime #") + QCString().setNum( numValidEntries ) ); config.writeEntry( "name", item->text( 0 ) ); config.writeEntry( "value", item->text( 1 ) ); numValidEntries++; } general.writeEntry( "mime-header-count", numValidEntries ); } QString ComposerPage::AttachmentsTab::helpAnchor() const { return QString::fromLatin1("configure-composer-attachments"); } ComposerPageAttachmentsTab::ComposerPageAttachmentsTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "Outlook compatible attachment naming" check box mOutlookCompatibleCheck = new QCheckBox( i18n( "Outlook-compatible attachment naming" ), this ); mOutlookCompatibleCheck->setChecked( false ); QToolTip::add( mOutlookCompatibleCheck, i18n( "Turn this option on to make Outlook(tm) understand attachment names " "containing non-English characters" ) ); connect( mOutlookCompatibleCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mOutlookCompatibleCheck, SIGNAL( clicked() ), this, SLOT( slotOutlookCompatibleClicked() ) ); vlay->addWidget( mOutlookCompatibleCheck ); vlay->addSpacing( 5 ); // "Enable detection of missing attachments" check box mMissingAttachmentDetectionCheck = new QCheckBox( i18n("E&nable detection of missing attachments"), this ); mMissingAttachmentDetectionCheck->setChecked( true ); connect( mMissingAttachmentDetectionCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mMissingAttachmentDetectionCheck ); // "Attachment key words" label and string list editor label = new QLabel( i18n("Recognize any of the following key words as " "intention to attach a file:"), this ); label->setAlignment( AlignLeft|WordBreak ); vlay->addWidget( label ); SimpleStringListEditor::ButtonCode buttonCode = static_cast( SimpleStringListEditor::Add | SimpleStringListEditor::Remove | SimpleStringListEditor::Modify ); mAttachWordsListEditor = new SimpleStringListEditor( this, 0, buttonCode, i18n("A&dd..."), i18n("Re&move"), i18n("Mod&ify..."), i18n("Enter new key word:") ); connect( mAttachWordsListEditor, SIGNAL( changed( void ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addWidget( mAttachWordsListEditor ); connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ), label, SLOT(setEnabled(bool)) ); connect( mMissingAttachmentDetectionCheck, SIGNAL(toggled(bool) ), mAttachWordsListEditor, SLOT(setEnabled(bool)) ); } void ComposerPage::AttachmentsTab::doLoadOther() { KConfigGroup composer( KMKernel::config(), "Composer" ); mOutlookCompatibleCheck->setChecked( composer.readBoolEntry( "outlook-compatible-attachments", false ) ); mMissingAttachmentDetectionCheck->setChecked( composer.readBoolEntry( "showForgottenAttachmentWarning", true ) ); QStringList attachWordsList = composer.readListEntry( "attachment-keywords" ); if ( attachWordsList.isEmpty() ) { // default value attachWordsList << QString::fromLatin1("attachment") << QString::fromLatin1("attached"); if ( QString::fromLatin1("attachment") != i18n("attachment") ) attachWordsList << i18n("attachment"); if ( QString::fromLatin1("attached") != i18n("attached") ) attachWordsList << i18n("attached"); } mAttachWordsListEditor->setStringList( attachWordsList ); } void ComposerPage::AttachmentsTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); composer.writeEntry( "outlook-compatible-attachments", mOutlookCompatibleCheck->isChecked() ); composer.writeEntry( "showForgottenAttachmentWarning", mMissingAttachmentDetectionCheck->isChecked() ); composer.writeEntry( "attachment-keywords", mAttachWordsListEditor->stringList() ); } void ComposerPageAttachmentsTab::slotOutlookCompatibleClicked() { if (mOutlookCompatibleCheck->isChecked()) { KMessageBox::information(0,i18n("You have chosen to " "encode attachment names containing non-English characters in a way that " "is understood by Outlook(tm) and other mail clients that do not " "support standard-compliant encoded attachment names.\n" "Note that KMail may create non-standard compliant messages, " "and consequently it is possible that your messages will not be " "understood by standard-compliant mail clients; so, unless you have no " "other choice, you should not enable this option." ) ); } } // ************************************************************* // * * // * SecurityPage * // * * // ************************************************************* QString SecurityPage::helpAnchor() const { return QString::fromLatin1("configure-security"); } SecurityPage::SecurityPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { // // "Reading" tab: // mGeneralTab = new GeneralTab(); // @TODO: rename addTab( mGeneralTab, i18n("&Reading") ); // // "Composing" tab: // mComposerCryptoTab = new ComposerCryptoTab(); addTab( mComposerCryptoTab, i18n("Composing") ); // // "Warnings" tab: // mWarningTab = new WarningTab(); addTab( mWarningTab, i18n("Warnings") ); // // "S/MIME Validation" tab: // mSMimeTab = new SMimeTab(); addTab( mSMimeTab, i18n("S/MIME &Validation") ); // // "Crypto Backends" tab: // mCryptPlugTab = new CryptPlugTab(); addTab( mCryptPlugTab, i18n("Crypto Backe&nds") ); load(); } void SecurityPage::installProfile( KConfig * profile ) { mGeneralTab->installProfile( profile ); mComposerCryptoTab->installProfile( profile ); mWarningTab->installProfile( profile ); mSMimeTab->installProfile( profile ); } QString SecurityPage::GeneralTab::helpAnchor() const { return QString::fromLatin1("configure-security-reading"); } SecurityPageGeneralTab::SecurityPageGeneralTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // tmp. vars: QVBoxLayout *vlay; QHBox *hbox; QGroupBox *group; QRadioButton *radio; KActiveLabel *label; QWidget *w; QString msg; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // QWhat'sThis texts QString htmlWhatsThis = i18n( "

Messages sometimes come in both formats. " "This option controls whether you want the HTML part or the plain " "text part to be displayed.

" "

Displaying the HTML part makes the message look better, " "but at the same time increases the risk of security holes " "being exploited.

" "

Displaying the plain text part loses much of the message's " "formatting, but makes it almost impossible " "to exploit security holes in the HTML renderer (Konqueror).

" "

The option below guards against one common misuse of HTML " "messages, but it cannot guard against security issues that were " "not known at the time this version of KMail was written.

" "

It is therefore advisable to not prefer HTML to " "plain text.

" "

Note: You can set this option on a per-folder basis " "from the Folder menu of KMail's main window.

" ); QString externalWhatsThis = i18n( "

Some mail advertisements are in HTML " "and contain references to, for example, images that the advertisers" " employ to find out that you have read their message " "("web bugs").

" "

There is no valid reason to load images off the Internet like " "this, since the sender can always attach the required images " "directly to the message.

" "

To guard from such a misuse of the HTML displaying feature " "of KMail, this option is disabled by default.

" "

However, if you wish to, for example, view images in HTML " "messages that were not attached to it, you can enable this " "option, but you should be aware of the possible problem.

" ); QString receiptWhatsThis = i18n( "

Message Disposition " "Notification Policy

" "

MDNs are a generalization of what is commonly called read " "receipt. The message author requests a disposition " "notification to be sent and the receiver's mail program " "generates a reply from which the author can learn what " "happened to his message. Common disposition types include " "displayed (i.e. read), deleted and dispatched " "(e.g. forwarded).

" "

The following options are available to control KMail's " "sending of MDNs:

" "
    " "
  • Ignore: Ignores any request for disposition " "notifications. No MDN will ever be sent automatically " "(recommended).
  • " "
  • Ask: Answers requests only after asking the user " "for permission. This way, you can send MDNs for selected " "messages while denying or ignoring them for others.
  • " "
  • Deny: Always sends a denied notification. This " "is only slightly better than always sending MDNs. " "The author will still know that the messages has been acted " "upon, he just cannot tell whether it was deleted or read etc.
  • " "
  • Always send: Always sends the requested " "disposition notification. That means that the author of the " "message gets to know when the message was acted upon and, " "in addition, what happened to it (displayed, deleted, " "etc.). This option is strongly discouraged, but since it " "makes much sense e.g. for customer relationship management, " "it has been made available.
  • " "
" ); // "HTML Messages" group box: group = new QVGroupBox( i18n( "HTML Messages" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mHtmlMailCheck = new QCheckBox( i18n("Prefer H&TML to plain text"), group ); QWhatsThis::add( mHtmlMailCheck, htmlWhatsThis ); connect( mHtmlMailCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mExternalReferences = new QCheckBox( i18n("Allow messages to load e&xternal " "references from the Internet" ), group ); QWhatsThis::add( mExternalReferences, externalWhatsThis ); connect( mExternalReferences, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); label = new KActiveLabel( i18n("WARNING: Allowing HTML in email may " "increase the risk that your system will be " "compromised by present and anticipated security " "exploits. More about " "HTML mails... More " "about external references...") .arg(htmlWhatsThis).arg(externalWhatsThis), group ); vlay->addWidget( group ); // "Message Disposition Notification" groupbox: group = new QVGroupBox( i18n("Message Disposition Notifications"), this ); group->layout()->setSpacing( KDialog::spacingHint() ); // "ignore", "ask", "deny", "always send" radiobutton line: mMDNGroup = new QButtonGroup( group ); mMDNGroup->hide(); connect( mMDNGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); hbox->setSpacing( KDialog::spacingHint() ); (void)new QLabel( i18n("Send policy:"), hbox ); radio = new QRadioButton( i18n("&Ignore"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("As&k"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("&Deny"), hbox ); mMDNGroup->insert( radio ); radio = new QRadioButton( i18n("Al&ways send"), hbox ); mMDNGroup->insert( radio ); for ( int i = 0 ; i < mMDNGroup->count() ; ++i ) QWhatsThis::add( mMDNGroup->find( i ), receiptWhatsThis ); w = new QWidget( hbox ); // spacer hbox->setStretchFactor( w, 1 ); // "Original Message quote" radiobutton line: mOrigQuoteGroup = new QButtonGroup( group ); mOrigQuoteGroup->hide(); connect( mOrigQuoteGroup, SIGNAL( clicked( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hbox = new QHBox( group ); hbox->setSpacing( KDialog::spacingHint() ); (void)new QLabel( i18n("Quote original message:"), hbox ); radio = new QRadioButton( i18n("Nothin&g"), hbox ); mOrigQuoteGroup->insert( radio ); radio = new QRadioButton( i18n("&Full message"), hbox ); mOrigQuoteGroup->insert( radio ); radio = new QRadioButton( i18n("Onl&y headers"), hbox ); mOrigQuoteGroup->insert( radio ); w = new QWidget( hbox ); hbox->setStretchFactor( w, 1 ); mNoMDNsWhenEncryptedCheck = new QCheckBox( i18n("Do not send MDNs in response to encrypted messages"), group ); connect( mNoMDNsWhenEncryptedCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); // Warning label: label = new KActiveLabel( i18n("WARNING: Unconditionally returning " "confirmations undermines your privacy. " "More...") .arg(receiptWhatsThis), group ); vlay->addWidget( group ); // "Attached keys" group box: group = new QVGroupBox( i18n( "Certificate && Key Bundle Attachments" ), this ); group->layout()->setSpacing( KDialog::spacingHint() ); mAutomaticallyImportAttachedKeysCheck = new QCheckBox( i18n("Automatically import keys and certificates"), group ); connect( mAutomaticallyImportAttachedKeysCheck, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); vlay->addWidget( group ); vlay->addStretch( 10 ); // spacer } void SecurityPage::GeneralTab::doLoadOther() { const KConfigGroup reader( KMKernel::config(), "Reader" ); mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail", false ) ); mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal", false ) ); mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys", false ) ); const KConfigGroup mdn( KMKernel::config(), "MDN" ); int num = mdn.readNumEntry( "default-policy", 0 ); if ( num < 0 || num >= mMDNGroup->count() ) num = 0; mMDNGroup->setButton( num ); num = mdn.readNumEntry( "quote-message", 0 ); if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0; mOrigQuoteGroup->setButton( num ); mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted", true )); } void SecurityPage::GeneralTab::installProfile( KConfig * profile ) { const KConfigGroup reader( profile, "Reader" ); const KConfigGroup mdn( profile, "MDN" ); if ( reader.hasKey( "htmlMail" ) ) mHtmlMailCheck->setChecked( reader.readBoolEntry( "htmlMail" ) ); if ( reader.hasKey( "htmlLoadExternal" ) ) mExternalReferences->setChecked( reader.readBoolEntry( "htmlLoadExternal" ) ); if ( reader.hasKey( "AutoImportKeys" ) ) mAutomaticallyImportAttachedKeysCheck->setChecked( reader.readBoolEntry( "AutoImportKeys" ) ); if ( mdn.hasKey( "default-policy" ) ) { int num = mdn.readNumEntry( "default-policy" ); if ( num < 0 || num >= mMDNGroup->count() ) num = 0; mMDNGroup->setButton( num ); } if ( mdn.hasKey( "quote-message" ) ) { int num = mdn.readNumEntry( "quote-message" ); if ( num < 0 || num >= mOrigQuoteGroup->count() ) num = 0; mOrigQuoteGroup->setButton( num ); } if ( mdn.hasKey( "not-send-when-encrypted" ) ) mNoMDNsWhenEncryptedCheck->setChecked(mdn.readBoolEntry( "not-send-when-encrypted" )); } void SecurityPage::GeneralTab::save() { KConfigGroup reader( KMKernel::config(), "Reader" ); KConfigGroup mdn( KMKernel::config(), "MDN" ); if (reader.readBoolEntry( "htmlMail", false ) != mHtmlMailCheck->isChecked()) { if (KMessageBox::warningContinueCancel(this, i18n("Changing the global " "HTML setting will override all folder specific values."), QString::null, QString::null, "htmlMailOverride") == KMessageBox::Continue) { reader.writeEntry( "htmlMail", mHtmlMailCheck->isChecked() ); QStringList names; QValueList > folders; kmkernel->folderMgr()->createFolderList(&names, &folders); kmkernel->imapFolderMgr()->createFolderList(&names, &folders); kmkernel->dimapFolderMgr()->createFolderList(&names, &folders); kmkernel->searchFolderMgr()->createFolderList(&names, &folders); for (QValueList >::iterator it = folders.begin(); it != folders.end(); ++it) { if (*it) { KConfigGroupSaver saver(KMKernel::config(), "Folder-" + (*it)->idString()); KMKernel::config()->writeEntry("htmlMailOverride", false); } } } } reader.writeEntry( "htmlLoadExternal", mExternalReferences->isChecked() ); reader.writeEntry( "AutoImportKeys", mAutomaticallyImportAttachedKeysCheck->isChecked() ); mdn.writeEntry( "default-policy", mMDNGroup->id( mMDNGroup->selected() ) ); mdn.writeEntry( "quote-message", mOrigQuoteGroup->id( mOrigQuoteGroup->selected() ) ); mdn.writeEntry( "not-send-when-encrypted", mNoMDNsWhenEncryptedCheck->isChecked() ); } QString SecurityPage::ComposerCryptoTab::helpAnchor() const { return QString::fromLatin1("configure-security-composing"); } SecurityPageComposerCryptoTab::SecurityPageComposerCryptoTab( QWidget * parent, const char * name ) : ConfigModuleTab ( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new ComposerCryptoConfiguration( this ); connect( mWidget->mAutoSignature, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mEncToSelf, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mShowEncryptionResult, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mShowKeyApprovalDlg, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mAutoEncrypt, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mNeverEncryptWhenSavingInDrafts, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->mStoreEncrypted, SIGNAL( toggled(bool) ), this, SLOT( slotEmitChanged() ) ); vlay->addWidget( mWidget ); } void SecurityPage::ComposerCryptoTab::doLoadOther() { const KConfigGroup composer( KMKernel::config(), "Composer" ); // If you change default values, sync messagecomposer.cpp too mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign", false ) ); mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self", true ) ); mWidget->mShowEncryptionResult->setChecked( false ); //composer.readBoolEntry( "crypto-show-encryption-result", true ) ); mWidget->mShowEncryptionResult->hide(); mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval", true ) ); mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt", false ) ); mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts", true ) ); mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted", true ) ); } void SecurityPage::ComposerCryptoTab::installProfile( KConfig * profile ) { const KConfigGroup composer( profile, "Composer" ); if ( composer.hasKey( "pgp-auto-sign" ) ) mWidget->mAutoSignature->setChecked( composer.readBoolEntry( "pgp-auto-sign" ) ); if ( composer.hasKey( "crypto-encrypt-to-self" ) ) mWidget->mEncToSelf->setChecked( composer.readBoolEntry( "crypto-encrypt-to-self" ) ); if ( composer.hasKey( "crypto-show-encryption-result" ) ) mWidget->mShowEncryptionResult->setChecked( composer.readBoolEntry( "crypto-show-encryption-result" ) ); if ( composer.hasKey( "crypto-show-keys-for-approval" ) ) mWidget->mShowKeyApprovalDlg->setChecked( composer.readBoolEntry( "crypto-show-keys-for-approval" ) ); if ( composer.hasKey( "pgp-auto-encrypt" ) ) mWidget->mAutoEncrypt->setChecked( composer.readBoolEntry( "pgp-auto-encrypt" ) ); if ( composer.hasKey( "never-encrypt-drafts" ) ) mWidget->mNeverEncryptWhenSavingInDrafts->setChecked( composer.readBoolEntry( "never-encrypt-drafts" ) ); if ( composer.hasKey( "crypto-store-encrypted" ) ) mWidget->mStoreEncrypted->setChecked( composer.readBoolEntry( "crypto-store-encrypted" ) ); } void SecurityPage::ComposerCryptoTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); composer.writeEntry( "pgp-auto-sign", mWidget->mAutoSignature->isChecked() ); composer.writeEntry( "crypto-encrypt-to-self", mWidget->mEncToSelf->isChecked() ); composer.writeEntry( "crypto-show-encryption-result", mWidget->mShowEncryptionResult->isChecked() ); composer.writeEntry( "crypto-show-keys-for-approval", mWidget->mShowKeyApprovalDlg->isChecked() ); composer.writeEntry( "pgp-auto-encrypt", mWidget->mAutoEncrypt->isChecked() ); composer.writeEntry( "never-encrypt-drafts", mWidget->mNeverEncryptWhenSavingInDrafts->isChecked() ); composer.writeEntry( "crypto-store-encrypted", mWidget->mStoreEncrypted->isChecked() ); } QString SecurityPage::WarningTab::helpAnchor() const { return QString::fromLatin1("configure-security-warnings"); } SecurityPageWarningTab::SecurityPageWarningTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new WarningConfiguration( this ); vlay->addWidget( mWidget ); connect( mWidget->warnGroupBox, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->mWarnUnsigned, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->warnUnencryptedCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->warnReceiverNotInCertificateCB, SIGNAL(toggled(bool)), SLOT(slotEmitChanged()) ); connect( mWidget->mWarnSignKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnSignChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnSignRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrKeyExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrChainCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->mWarnEncrRootCertExpiresSB, SIGNAL( valueChanged( int ) ), SLOT( slotEmitChanged() ) ); connect( mWidget->enableAllWarningsPB, SIGNAL(clicked()), SLOT(slotReenableAllWarningsClicked()) ); } void SecurityPage::WarningTab::doLoadOther() { const KConfigGroup composer( KMKernel::config(), "Composer" ); mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted", false ) ); mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned", false ) ); mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert", true ) ); // The "-int" part of the key name is because there used to be a separate boolean // config entry for enabling/disabling. This is done with the single bool value now. mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire", true ) ); mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int", 14 ) ); mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int", 14 ) ); mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int", 14 ) ); mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int", 14 ) ); mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int", 14 ) ); mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int", 14 ) ); mWidget->enableAllWarningsPB->setEnabled( true ); } void SecurityPage::WarningTab::installProfile( KConfig * profile ) { const KConfigGroup composer( profile, "Composer" ); if ( composer.hasKey( "crypto-warning-unencrypted" ) ) mWidget->warnUnencryptedCB->setChecked( composer.readBoolEntry( "crypto-warning-unencrypted" ) ); if ( composer.hasKey( "crypto-warning-unsigned" ) ) mWidget->mWarnUnsigned->setChecked( composer.readBoolEntry( "crypto-warning-unsigned" ) ); if ( composer.hasKey( "crypto-warn-recv-not-in-cert" ) ) mWidget->warnReceiverNotInCertificateCB->setChecked( composer.readBoolEntry( "crypto-warn-recv-not-in-cert" ) ); if ( composer.hasKey( "crypto-warn-when-near-expire" ) ) mWidget->warnGroupBox->setChecked( composer.readBoolEntry( "crypto-warn-when-near-expire" ) ); if ( composer.hasKey( "crypto-warn-sign-key-near-expire-int" ) ) mWidget->mWarnSignKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-key-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-sign-chaincert-near-expire-int" ) ) mWidget->mWarnSignChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-chaincert-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-sign-root-near-expire-int" ) ) mWidget->mWarnSignRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-sign-root-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-key-near-expire-int" ) ) mWidget->mWarnEncrKeyExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-key-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-chaincert-near-expire-int" ) ) mWidget->mWarnEncrChainCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-chaincert-near-expire-int" ) ); if ( composer.hasKey( "crypto-warn-encr-root-near-expire-int" ) ) mWidget->mWarnEncrRootCertExpiresSB->setValue( composer.readNumEntry( "crypto-warn-encr-root-near-expire-int" ) ); } void SecurityPage::WarningTab::save() { KConfigGroup composer( KMKernel::config(), "Composer" ); composer.writeEntry( "crypto-warn-recv-not-in-cert", mWidget->warnReceiverNotInCertificateCB->isChecked() ); composer.writeEntry( "crypto-warning-unencrypted", mWidget->warnUnencryptedCB->isChecked() ); composer.writeEntry( "crypto-warning-unsigned", mWidget->mWarnUnsigned->isChecked() ); composer.writeEntry( "crypto-warn-when-near-expire", mWidget->warnGroupBox->isChecked() ); composer.writeEntry( "crypto-warn-sign-key-near-expire-int", mWidget->mWarnSignKeyExpiresSB->value() ); composer.writeEntry( "crypto-warn-sign-chaincert-near-expire-int", mWidget->mWarnSignChainCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-sign-root-near-expire-int", mWidget->mWarnSignRootCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-key-near-expire-int", mWidget->mWarnEncrKeyExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-chaincert-near-expire-int", mWidget->mWarnEncrChainCertExpiresSB->value() ); composer.writeEntry( "crypto-warn-encr-root-near-expire-int", mWidget->mWarnEncrRootCertExpiresSB->value() ); } void SecurityPage::WarningTab::slotReenableAllWarningsClicked() { KMessageBox::enableAllMessages(); mWidget->enableAllWarningsPB->setEnabled( false ); } //// QString SecurityPage::SMimeTab::helpAnchor() const { return QString::fromLatin1("configure-security-smime-validation"); } SecurityPageSMimeTab::SecurityPageSMimeTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // the margins are inside mWidget itself QVBoxLayout* vlay = new QVBoxLayout( this, 0, 0 ); mWidget = new SMimeConfiguration( this ); vlay->addWidget( mWidget ); // Button-group for exclusive radiobuttons QButtonGroup* bg = new QButtonGroup( mWidget ); bg->hide(); bg->insert( mWidget->CRLRB ); bg->insert( mWidget->OCSPRB ); // Settings for the keyrequester custom widget mWidget->OCSPResponderSignature->setAllowedKeys( Kleo::KeySelectionDialog::SMIMEKeys | Kleo::KeySelectionDialog::TrustedKeys | Kleo::KeySelectionDialog::ValidKeys | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::PublicKeys ); mWidget->OCSPResponderSignature->setMultipleKeysEnabled( false ); mConfig = Kleo::CryptoBackendFactory::instance()->config(); connect( mWidget->CRLRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPResponderURL, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->OCSPResponderSignature, SIGNAL( changed() ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->doNotCheckCertPolicyCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->neverConsultCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->fetchMissingCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreServiceURLCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->honorHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->useCustomHTTPProxyRB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->customHTTPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->ignoreLDAPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableLDAPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->customLDAPProxy, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotEmitChanged() ) ); connect( mWidget->disableHTTPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotUpdateHTTPActions() ) ); connect( mWidget->ignoreHTTPDPCB, SIGNAL( toggled( bool ) ), this, SLOT( slotUpdateHTTPActions() ) ); // Button-group for exclusive radiobuttons QButtonGroup* bgHTTPProxy = new QButtonGroup( mWidget ); bgHTTPProxy->hide(); bgHTTPProxy->insert( mWidget->honorHTTPProxyRB ); bgHTTPProxy->insert( mWidget->useCustomHTTPProxyRB ); if ( !connectDCOPSignal( 0, "KPIM::CryptoConfig", "changed()", "load()", false ) ) kdError(5650) << "SecurityPageSMimeTab: connection to CryptoConfig's changed() failed" << endl; } SecurityPageSMimeTab::~SecurityPageSMimeTab() { } static void disableDirmngrWidget( QWidget* w ) { w->setEnabled( false ); QWhatsThis::remove( w ); QWhatsThis::add( w, i18n( "This option requires dirmngr >= 0.9.0" ) ); } static void initializeDirmngrCheckbox( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) { if ( entry ) cb->setChecked( entry->boolValue() ); else disableDirmngrWidget( cb ); } struct SMIMECryptoConfigEntries { SMIMECryptoConfigEntries( Kleo::CryptoConfig* config ) : mConfig( config ) { // Checkboxes mCheckUsingOCSPConfigEntry = configEntry( "gpgsm", "Security", "enable-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false ); mEnableOCSPsendingConfigEntry = configEntry( "dirmngr", "OCSP", "allow-ocsp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDoNotCheckCertPolicyConfigEntry = configEntry( "gpgsm", "Security", "disable-policy-checks", Kleo::CryptoConfigEntry::ArgType_None, false ); mNeverConsultConfigEntry = configEntry( "gpgsm", "Security", "disable-crl-checks", Kleo::CryptoConfigEntry::ArgType_None, false ); mFetchMissingConfigEntry = configEntry( "gpgsm", "Security", "auto-issuer-key-retrieve", Kleo::CryptoConfigEntry::ArgType_None, false ); // dirmngr-0.9.0 options mIgnoreServiceURLEntry = configEntry( "dirmngr", "OCSP", "ignore-ocsp-service-url", Kleo::CryptoConfigEntry::ArgType_None, false ); mIgnoreHTTPDPEntry = configEntry( "dirmngr", "HTTP", "ignore-http-dp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDisableHTTPEntry = configEntry( "dirmngr", "HTTP", "disable-http", Kleo::CryptoConfigEntry::ArgType_None, false ); mHonorHTTPProxy = configEntry( "dirmngr", "HTTP", "honor-http-proxy", Kleo::CryptoConfigEntry::ArgType_None, false ); mIgnoreLDAPDPEntry = configEntry( "dirmngr", "LDAP", "ignore-ldap-dp", Kleo::CryptoConfigEntry::ArgType_None, false ); mDisableLDAPEntry = configEntry( "dirmngr", "LDAP", "disable-ldap", Kleo::CryptoConfigEntry::ArgType_None, false ); // Other widgets mOCSPResponderURLConfigEntry = configEntry( "dirmngr", "OCSP", "ocsp-responder", Kleo::CryptoConfigEntry::ArgType_String, false ); mOCSPResponderSignature = configEntry( "dirmngr", "OCSP", "ocsp-signer", Kleo::CryptoConfigEntry::ArgType_String, false ); mCustomHTTPProxy = configEntry( "dirmngr", "HTTP", "http-proxy", Kleo::CryptoConfigEntry::ArgType_String, false ); mCustomLDAPProxy = configEntry( "dirmngr", "LDAP", "ldap-proxy", Kleo::CryptoConfigEntry::ArgType_String, false ); } Kleo::CryptoConfigEntry* configEntry( const char* componentName, const char* groupName, const char* entryName, int argType, bool isList ); // Checkboxes Kleo::CryptoConfigEntry* mCheckUsingOCSPConfigEntry; Kleo::CryptoConfigEntry* mEnableOCSPsendingConfigEntry; Kleo::CryptoConfigEntry* mDoNotCheckCertPolicyConfigEntry; Kleo::CryptoConfigEntry* mNeverConsultConfigEntry; Kleo::CryptoConfigEntry* mFetchMissingConfigEntry; Kleo::CryptoConfigEntry* mIgnoreServiceURLEntry; Kleo::CryptoConfigEntry* mIgnoreHTTPDPEntry; Kleo::CryptoConfigEntry* mDisableHTTPEntry; Kleo::CryptoConfigEntry* mHonorHTTPProxy; Kleo::CryptoConfigEntry* mIgnoreLDAPDPEntry; Kleo::CryptoConfigEntry* mDisableLDAPEntry; // Other widgets Kleo::CryptoConfigEntry* mOCSPResponderURLConfigEntry; Kleo::CryptoConfigEntry* mOCSPResponderSignature; Kleo::CryptoConfigEntry* mCustomHTTPProxy; Kleo::CryptoConfigEntry* mCustomLDAPProxy; Kleo::CryptoConfig* mConfig; }; void SecurityPage::SMimeTab::doLoadOther() { if ( !mConfig ) { setEnabled( false ); return; } // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used // (which ends up calling us via dcop) mConfig->clear(); // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be // done by the "configure backend" button even before we save(). SMIMECryptoConfigEntries e( mConfig ); // Initialize GUI items from the config entries if ( e.mCheckUsingOCSPConfigEntry ) { bool b = e.mCheckUsingOCSPConfigEntry->boolValue(); mWidget->OCSPRB->setChecked( b ); mWidget->CRLRB->setChecked( !b ); mWidget->OCSPGroupBox->setEnabled( b ); } else { mWidget->OCSPGroupBox->setEnabled( false ); } if ( e.mDoNotCheckCertPolicyConfigEntry ) mWidget->doNotCheckCertPolicyCB->setChecked( e.mDoNotCheckCertPolicyConfigEntry->boolValue() ); if ( e.mNeverConsultConfigEntry ) mWidget->neverConsultCB->setChecked( e.mNeverConsultConfigEntry->boolValue() ); if ( e.mFetchMissingConfigEntry ) mWidget->fetchMissingCB->setChecked( e.mFetchMissingConfigEntry->boolValue() ); if ( e.mOCSPResponderURLConfigEntry ) mWidget->OCSPResponderURL->setText( e.mOCSPResponderURLConfigEntry->stringValue() ); if ( e.mOCSPResponderSignature ) { mWidget->OCSPResponderSignature->setFingerprint( e.mOCSPResponderSignature->stringValue() ); } // dirmngr-0.9.0 options initializeDirmngrCheckbox( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry ); initializeDirmngrCheckbox( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry ); initializeDirmngrCheckbox( mWidget->disableHTTPCB, e.mDisableHTTPEntry ); initializeDirmngrCheckbox( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry ); initializeDirmngrCheckbox( mWidget->disableLDAPCB, e.mDisableLDAPEntry ); if ( e.mCustomHTTPProxy ) { QString systemProxy = QString::fromLocal8Bit( getenv( "http_proxy" ) ); if ( systemProxy.isEmpty() ) systemProxy = i18n( "no proxy" ); mWidget->systemHTTPProxy->setText( i18n( "(Current system setting: %1)" ).arg( systemProxy ) ); bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue(); mWidget->honorHTTPProxyRB->setChecked( honor ); mWidget->useCustomHTTPProxyRB->setChecked( !honor ); mWidget->customHTTPProxy->setText( e.mCustomHTTPProxy->stringValue() ); } else { disableDirmngrWidget( mWidget->honorHTTPProxyRB ); disableDirmngrWidget( mWidget->useCustomHTTPProxyRB ); disableDirmngrWidget( mWidget->systemHTTPProxy ); disableDirmngrWidget( mWidget->customHTTPProxy ); } if ( e.mCustomLDAPProxy ) mWidget->customLDAPProxy->setText( e.mCustomLDAPProxy->stringValue() ); else { disableDirmngrWidget( mWidget->customLDAPProxy ); disableDirmngrWidget( mWidget->customLDAPLabel ); } slotUpdateHTTPActions(); } void SecurityPage::SMimeTab::slotUpdateHTTPActions() { mWidget->ignoreHTTPDPCB->setEnabled( !mWidget->disableHTTPCB->isChecked() ); // The proxy settings only make sense when "Ignore HTTP CRL DPs of certificate" is checked. bool enableProxySettings = !mWidget->disableHTTPCB->isChecked() && mWidget->ignoreHTTPDPCB->isChecked(); mWidget->systemHTTPProxy->setEnabled( enableProxySettings ); mWidget->useCustomHTTPProxyRB->setEnabled( enableProxySettings ); mWidget->honorHTTPProxyRB->setEnabled( enableProxySettings ); mWidget->customHTTPProxy->setEnabled( enableProxySettings ); } void SecurityPage::SMimeTab::installProfile( KConfig * ) { } static void saveCheckBoxToKleoEntry( QCheckBox* cb, Kleo::CryptoConfigEntry* entry ) { const bool b = cb->isChecked(); if ( entry && entry->boolValue() != b ) entry->setBoolValue( b ); } void SecurityPage::SMimeTab::save() { if ( !mConfig ) { return; } // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be done by the // "configure backend" button. SMIMECryptoConfigEntries e( mConfig ); bool b = mWidget->OCSPRB->isChecked(); if ( e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b ) e.mCheckUsingOCSPConfigEntry->setBoolValue( b ); // Set allow-ocsp together with enable-ocsp if ( e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b ) e.mEnableOCSPsendingConfigEntry->setBoolValue( b ); saveCheckBoxToKleoEntry( mWidget->doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry ); saveCheckBoxToKleoEntry( mWidget->neverConsultCB, e.mNeverConsultConfigEntry ); saveCheckBoxToKleoEntry( mWidget->fetchMissingCB, e.mFetchMissingConfigEntry ); QString txt = mWidget->OCSPResponderURL->text(); if ( e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt ) e.mOCSPResponderURLConfigEntry->setStringValue( txt ); txt = mWidget->OCSPResponderSignature->fingerprint(); if ( e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt ) { e.mOCSPResponderSignature->setStringValue( txt ); } //dirmngr-0.9.0 options saveCheckBoxToKleoEntry( mWidget->ignoreServiceURLCB, e.mIgnoreServiceURLEntry ); saveCheckBoxToKleoEntry( mWidget->ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry ); saveCheckBoxToKleoEntry( mWidget->disableHTTPCB, e.mDisableHTTPEntry ); saveCheckBoxToKleoEntry( mWidget->ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry ); saveCheckBoxToKleoEntry( mWidget->disableLDAPCB, e.mDisableLDAPEntry ); if ( e.mCustomHTTPProxy ) { const bool honor = mWidget->honorHTTPProxyRB->isChecked(); if ( e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor ) e.mHonorHTTPProxy->setBoolValue( honor ); QString chosenProxy = mWidget->customHTTPProxy->text(); if ( chosenProxy != e.mCustomHTTPProxy->stringValue() ) e.mCustomHTTPProxy->setStringValue( chosenProxy ); } txt = mWidget->customLDAPProxy->text(); if ( e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt ) e.mCustomLDAPProxy->setStringValue( mWidget->customLDAPProxy->text() ); mConfig->sync( true ); } bool SecurityPageSMimeTab::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData) { if ( fun == "load()" ) { replyType = "void"; load(); } else { return DCOPObject::process( fun, data, replyType, replyData ); } return true; } QCStringList SecurityPageSMimeTab::interfaces() { QCStringList ifaces = DCOPObject::interfaces(); ifaces += "SecurityPageSMimeTab"; return ifaces; } QCStringList SecurityPageSMimeTab::functions() { // Hide our slot, just because it's simpler to do so. return DCOPObject::functions(); } Kleo::CryptoConfigEntry* SMIMECryptoConfigEntries::configEntry( const char* componentName, const char* groupName, const char* entryName, int /*Kleo::CryptoConfigEntry::ArgType*/ argType, bool isList ) { Kleo::CryptoConfigEntry* entry = mConfig->entry( componentName, groupName, entryName ); if ( !entry ) { kdWarning(5006) << QString( "Backend error: gpgconf doesn't seem to know the entry for %1/%2/%3" ).arg( componentName, groupName, entryName ) << endl; return 0; } if( entry->argType() != argType || entry->isList() != isList ) { kdWarning(5006) << QString( "Backend error: gpgconf has wrong type for %1/%2/%3: %4 %5" ).arg( componentName, groupName, entryName ).arg( entry->argType() ).arg( entry->isList() ) << endl; return 0; } return entry; } //// QString SecurityPage::CryptPlugTab::helpAnchor() const { return QString::fromLatin1("configure-security-crypto-backends"); } SecurityPageCryptPlugTab::SecurityPageCryptPlugTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { QVBoxLayout * vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); mBackendConfig = Kleo::CryptoBackendFactory::instance()->configWidget( this, "mBackendConfig" ); connect( mBackendConfig, SIGNAL( changed( bool ) ), this, SIGNAL( changed( bool ) ) ); vlay->addWidget( mBackendConfig ); } SecurityPageCryptPlugTab::~SecurityPageCryptPlugTab() { } void SecurityPage::CryptPlugTab::doLoadOther() { mBackendConfig->load(); } void SecurityPage::CryptPlugTab::save() { mBackendConfig->save(); } // ************************************************************* // * * // * MiscPage * // * * // ************************************************************* QString MiscPage::helpAnchor() const { return QString::fromLatin1("configure-misc"); } MiscPage::MiscPage( QWidget * parent, const char * name ) : ConfigModuleWithTabs( parent, name ) { mFolderTab = new FolderTab(); addTab( mFolderTab, i18n("&Folders") ); mGroupwareTab = new GroupwareTab(); addTab( mGroupwareTab, i18n("&Groupware") ); load(); } QString MiscPage::FolderTab::helpAnchor() const { return QString::fromLatin1("configure-misc-folders"); } MiscPageFolderTab::MiscPageFolderTab( QWidget * parent, const char * name ) : ConfigModuleTab( parent, name ) { // temp. vars: QVBoxLayout *vlay; QHBoxLayout *hlay; QLabel *label; vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); // "confirm before emptying folder" check box: stretch 0 mEmptyFolderConfirmCheck = new QCheckBox( i18n("Corresponds to Folder->Move All Messages to Trash", "Ask for co&nfirmation before moving all messages to " "trash"), this ); vlay->addWidget( mEmptyFolderConfirmCheck ); connect( mEmptyFolderConfirmCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mExcludeImportantFromExpiry = new QCheckBox( i18n("E&xclude important messages from expiry"), this ); vlay->addWidget( mExcludeImportantFromExpiry ); connect( mExcludeImportantFromExpiry, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "when trying to find unread messages" combo + label: stretch 0 hlay = new QHBoxLayout( vlay ); // inherits spacing mLoopOnGotoUnread = new QComboBox( false, this ); label = new QLabel( mLoopOnGotoUnread, i18n("to be continued with \"do not loop\", \"loop in current folder\", " "and \"loop in all folders\".", "When trying to find unread messages:"), this ); mLoopOnGotoUnread->insertStringList( QStringList() << i18n("continuation of \"When trying to find unread messages:\"", "Do not Loop") << i18n("continuation of \"When trying to find unread messages:\"", "Loop in Current Folder") << i18n("continuation of \"When trying to find unread messages:\"", "Loop in All Folders")); hlay->addWidget( label ); hlay->addWidget( mLoopOnGotoUnread, 1 ); connect( mLoopOnGotoUnread, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // when entering a folder hlay = new QHBoxLayout( vlay ); // inherits spacing mActionEnterFolder = new QComboBox( false, this ); label = new QLabel( mActionEnterFolder, i18n("to be continued with \"jump to first new message\", " "\"jump to first unread or new message\"," "and \"jump to last selected message\".", "When entering a folder:"), this ); mActionEnterFolder->insertStringList( QStringList() << i18n("continuation of \"When entering a folder:\"", "Jump to First New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to First Unread or New Message") << i18n("continuation of \"When entering a folder:\"", "Jump to Last Selected Message")); hlay->addWidget( label ); hlay->addWidget( mActionEnterFolder, 1 ); connect( mActionEnterFolder, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); hlay = new QHBoxLayout( vlay ); // inherits spacing mDelayedMarkAsRead = new QCheckBox( i18n("Mar&k selected message as read after"), this ); hlay->addWidget( mDelayedMarkAsRead ); mDelayedMarkTime = new KIntSpinBox( 0 /*min*/, 60 /*max*/, 1/*step*/, 0 /*init*/, 10 /*base*/, this); mDelayedMarkTime->setSuffix( i18n(" sec") ); mDelayedMarkTime->setEnabled( false ); // since mDelayedMarkAsREad is off hlay->addWidget( mDelayedMarkTime ); hlay->addStretch( 1 ); connect( mDelayedMarkTime, SIGNAL( valueChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)), mDelayedMarkTime, SLOT(setEnabled(bool))); connect( mDelayedMarkAsRead, SIGNAL(toggled(bool)), this , SLOT(slotEmitChanged( void ))); // "show popup after Drag'n'Drop" checkbox: stretch 0 mShowPopupAfterDnD = new QCheckBox( i18n("Ask for action after &dragging messages to another folder"), this ); vlay->addWidget( mShowPopupAfterDnD ); connect( mShowPopupAfterDnD, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "default mailbox format" combo + label: stretch 0 hlay = new QHBoxLayout( vlay ); // inherits spacing mMailboxPrefCombo = new QComboBox( false, this ); label = new QLabel( mMailboxPrefCombo, i18n("to be continued with \"flat files\" and " "\"directories\", resp.", "By default, &message folders on disk are:"), this ); mMailboxPrefCombo->insertStringList( QStringList() << i18n("continuation of \"By default, &message folders on disk are\"", "Flat Files (\"mbox\" format)") << i18n("continuation of \"By default, &message folders on disk are\"", "Directories (\"maildir\" format)") ); hlay->addWidget( label ); hlay->addWidget( mMailboxPrefCombo, 1 ); connect( mMailboxPrefCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // "On startup..." option: hlay = new QHBoxLayout( vlay ); // inherits spacing mOnStartupOpenFolder = new FolderRequester( this, kmkernel->getKMMainWidget()->folderTree() ); label = new QLabel( mOnStartupOpenFolder, i18n("Open this folder on startup:"), this ); hlay->addWidget( label ); hlay->addWidget( mOnStartupOpenFolder, 1 ); connect( mOnStartupOpenFolder, SIGNAL( folderChanged( KMFolder* ) ), this, SLOT( slotEmitChanged( void ) ) ); // "Empty &trash on program exit" option: mEmptyTrashCheck = new QCheckBox( i18n("Empty local &trash folder on program exit"), this ); vlay->addWidget( mEmptyTrashCheck ); connect( mEmptyTrashCheck, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); vlay->addStretch( 1 ); // and now: add QWhatsThis: QString msg = i18n( "what's this help", "

This selects which mailbox format will be " "the default for local folders:

" "

mbox: KMail's mail " "folders are represented by a single file each. " "Individual messages are separated from each other by a " "line starting with \"From \". This saves space on " "disk, but may be less robust, e.g. when moving messages " "between folders.

" "

maildir: KMail's mail folders are " "represented by real folders on disk. Individual messages " "are separate files. This may waste a bit of space on " "disk, but should be more robust, e.g. when moving " "messages between folders.

"); QWhatsThis::add( mMailboxPrefCombo, msg ); QWhatsThis::add( label, msg ); // @TODO: Till, move into .kcgc file msg = i18n( "what's this help", "

When jumping to the next unread message, it may occur " "that no more unread messages are below the current message.

" "

Do not loop: The search will stop at the last message in " "the current folder.

" "

Loop in current folder: The search will continue at the " "top of the message list, but not go to another folder.

" "

Loop in all folders: The search will continue at the top of " "the message list. If no unread messages are found it will then continue " "to the next folder.

" "

Similarly, when searching for the previous unread message, " "the search will start from the bottom of the message list and continue to " "the previous folder depending on which option is selected.

" ); QWhatsThis::add( mLoopOnGotoUnread, msg ); } void MiscPage::FolderTab::doLoadFromGlobalSettings() { mExcludeImportantFromExpiry->setChecked( GlobalSettings::self()->excludeImportantMailFromExpiry() ); // default = "Loop in current folder" mLoopOnGotoUnread->setCurrentItem( GlobalSettings::self()->loopOnGotoUnread() ); mActionEnterFolder->setCurrentItem( GlobalSettings::self()->actionEnterFolder() ); mDelayedMarkAsRead->setChecked( GlobalSettings::self()->delayedMarkAsRead() ); mDelayedMarkTime->setValue( GlobalSettings::self()->delayedMarkTime() ); mShowPopupAfterDnD->setChecked( GlobalSettings::self()->showPopupAfterDnD() ); } void MiscPage::FolderTab::doLoadOther() { KConfigGroup general( KMKernel::config(), "General" ); mEmptyTrashCheck->setChecked( general.readBoolEntry( "empty-trash-on-exit", true ) ); mOnStartupOpenFolder->setFolder( general.readEntry( "startupFolder", kmkernel->inboxFolder()->idString() ) ); mEmptyFolderConfirmCheck->setChecked( general.readBoolEntry( "confirm-before-empty", true ) ); int num = general.readNumEntry("default-mailbox-format", 1 ); if ( num < 0 || num > 1 ) num = 1; mMailboxPrefCombo->setCurrentItem( num ); } void MiscPage::FolderTab::save() { KConfigGroup general( KMKernel::config(), "General" ); general.writeEntry( "empty-trash-on-exit", mEmptyTrashCheck->isChecked() ); general.writeEntry( "confirm-before-empty", mEmptyFolderConfirmCheck->isChecked() ); general.writeEntry( "default-mailbox-format", mMailboxPrefCombo->currentItem() ); general.writeEntry( "startupFolder", mOnStartupOpenFolder->folder() ? mOnStartupOpenFolder->folder()->idString() : QString::null ); GlobalSettings::self()->setDelayedMarkAsRead( mDelayedMarkAsRead->isChecked() ); GlobalSettings::self()->setDelayedMarkTime( mDelayedMarkTime->value() ); GlobalSettings::self()->setActionEnterFolder( mActionEnterFolder->currentItem() ); GlobalSettings::self()->setLoopOnGotoUnread( mLoopOnGotoUnread->currentItem() ); GlobalSettings::self()->setShowPopupAfterDnD( mShowPopupAfterDnD->isChecked() ); GlobalSettings::self()->setExcludeImportantMailFromExpiry( mExcludeImportantFromExpiry->isChecked() ); } QString MiscPage::GroupwareTab::helpAnchor() const { return QString::fromLatin1("configure-misc-groupware"); } MiscPageGroupwareTab::MiscPageGroupwareTab( QWidget* parent, const char* name ) : ConfigModuleTab( parent, name ) { QBoxLayout* vlay = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); vlay->setAutoAdd( true ); // IMAP resource setup QVGroupBox* b1 = new QVGroupBox( i18n("&IMAP Resource Folder Options"), this ); mEnableImapResCB = new QCheckBox( i18n("&Enable IMAP resource functionality"), b1 ); QToolTip::add( mEnableImapResCB, i18n( "This enables the IMAP storage for " "the Kontact applications" ) ); QWhatsThis::add( mEnableImapResCB, i18n( GlobalSettings::self()->theIMAPResourceEnabledItem()->whatsThis().utf8() ) ); connect( mEnableImapResCB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mBox = new QWidget( b1 ); QGridLayout* grid = new QGridLayout( mBox, 4, 2, 0, KDialog::spacingHint() ); grid->setColStretch( 1, 1 ); connect( mEnableImapResCB, SIGNAL( toggled(bool) ), mBox, SLOT( setEnabled(bool) ) ); QLabel* storageFormatLA = new QLabel( i18n("&Format used for the groupware folders:"), mBox ); QString toolTip = i18n( "Choose the format to use to store the contents of the groupware folders." ); QString whatsThis = i18n( GlobalSettings::self() ->theIMAPResourceStorageFormatItem()->whatsThis().utf8() ); grid->addWidget( storageFormatLA, 0, 0 ); QToolTip::add( storageFormatLA, toolTip ); QWhatsThis::add( storageFormatLA, whatsThis ); mStorageFormatCombo = new QComboBox( false, mBox ); storageFormatLA->setBuddy( mStorageFormatCombo ); QStringList formatLst; formatLst << i18n("Standard (Ical / Vcard)") << i18n("Kolab (XML)"); mStorageFormatCombo->insertStringList( formatLst ); grid->addWidget( mStorageFormatCombo, 0, 1 ); QToolTip::add( mStorageFormatCombo, toolTip ); QWhatsThis::add( mStorageFormatCombo, whatsThis ); connect( mStorageFormatCombo, SIGNAL( activated( int ) ), this, SLOT( slotStorageFormatChanged( int ) ) ); QLabel* languageLA = new QLabel( i18n("&Language of the groupware folders:"), mBox ); toolTip = i18n( "Set the language of the folder names" ); whatsThis = i18n( GlobalSettings::self() ->theIMAPResourceFolderLanguageItem()->whatsThis().utf8() ); grid->addWidget( languageLA, 1, 0 ); QToolTip::add( languageLA, toolTip ); QWhatsThis::add( languageLA, whatsThis ); mLanguageCombo = new QComboBox( false, mBox ); languageLA->setBuddy( mLanguageCombo ); QStringList lst; lst << i18n("English") << i18n("German") << i18n("French") << i18n("Dutch"); mLanguageCombo->insertStringList( lst ); grid->addWidget( mLanguageCombo, 1, 1 ); QToolTip::add( mLanguageCombo, toolTip ); QWhatsThis::add( mLanguageCombo, whatsThis ); connect( mLanguageCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mFolderComboLabel = new QLabel( mBox ); // text depends on storage format toolTip = i18n( "Set the parent of the resource folders" ); whatsThis = i18n( GlobalSettings::self()->theIMAPResourceFolderParentItem()->whatsThis().utf8() ); QToolTip::add( mFolderComboLabel, toolTip ); QWhatsThis::add( mFolderComboLabel, whatsThis ); grid->addWidget( mFolderComboLabel, 2, 0 ); mFolderComboStack = new QWidgetStack( mBox ); grid->addWidget( mFolderComboStack, 2, 1 ); // First possibility in the widgetstack: a combo showing the list of all folders // This is used with the ical/vcard storage mFolderCombo = new FolderRequester( mBox, kmkernel->getKMMainWidget()->folderTree() ); mFolderComboStack->addWidget( mFolderCombo, 0 ); QToolTip::add( mFolderCombo, toolTip ); QWhatsThis::add( mFolderCombo, whatsThis ); connect( mFolderCombo, SIGNAL( folderChanged( KMFolder* ) ), this, SLOT( slotEmitChanged() ) ); // Second possibility in the widgetstack: a combo showing the list of accounts // This is used with the kolab xml storage since the groupware folders // are always under the inbox. mAccountCombo = new KMail::AccountComboBox( mBox ); mFolderComboStack->addWidget( mAccountCombo, 1 ); QToolTip::add( mAccountCombo, toolTip ); QWhatsThis::add( mAccountCombo, whatsThis ); connect( mAccountCombo, SIGNAL( activated( int ) ), this, SLOT( slotEmitChanged() ) ); mHideGroupwareFolders = new QCheckBox( i18n( "&Hide groupware folders" ), mBox, "HideGroupwareFoldersBox" ); grid->addMultiCellWidget( mHideGroupwareFolders, 3, 3, 0, 1 ); QToolTip::add( mHideGroupwareFolders, i18n( "When this is checked, you will not see the IMAP " "resource folders in the folder tree." ) ); QWhatsThis::add( mHideGroupwareFolders, i18n( GlobalSettings::self() ->hideGroupwareFoldersItem()->whatsThis().utf8() ) ); connect( mHideGroupwareFolders, SIGNAL( toggled( bool ) ), this, SLOT( slotEmitChanged() ) ); // Groupware functionality compatibility setup b1 = new QVGroupBox( i18n("Groupware Compatibility && Legacy Options"), this ); gBox = new QVBox( b1 ); #if 0 // Currently believed to be disused. mEnableGwCB = new QCheckBox( i18n("&Enable groupware functionality"), b1 ); gBox->setSpacing( KDialog::spacingHint() ); connect( mEnableGwCB, SIGNAL( toggled(bool) ), gBox, SLOT( setEnabled(bool) ) ); connect( mEnableGwCB, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); #endif mEnableGwCB = 0; mLegacyMangleFromTo = new QCheckBox( i18n( "Mangle From:/To: headers in replies to invitations" ), gBox ); QToolTip::add( mLegacyMangleFromTo, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitation replies" ) ); QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()-> legacyMangleFromToHeadersItem()->whatsThis().utf8() ) ); connect( mLegacyMangleFromTo, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mLegacyBodyInvites = new QCheckBox( i18n( "Send invitations in the mail body" ), gBox ); QToolTip::add( mLegacyBodyInvites, i18n( "Turn this option on in order to make Outlook(tm) understand your answers to invitations" ) ); QWhatsThis::add( mLegacyMangleFromTo, i18n( GlobalSettings::self()-> legacyBodyInvitesItem()->whatsThis().utf8() ) ); connect( mLegacyBodyInvites, SIGNAL( toggled( bool ) ), this, SLOT( slotLegacyBodyInvitesToggled( bool ) ) ); connect( mLegacyBodyInvites, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); mAutomaticSending = new QCheckBox( i18n( "Automatic invitation sending" ), gBox ); QToolTip::add( mAutomaticSending, i18n( "When this is on, the user will not see the mail composer window. Invitation mails are sent automatically" ) ); QWhatsThis::add( mAutomaticSending, i18n( GlobalSettings::self()-> automaticSendingItem()->whatsThis().utf8() ) ); connect( mAutomaticSending, SIGNAL( stateChanged( int ) ), this, SLOT( slotEmitChanged( void ) ) ); // Open space padding at the end new QLabel( this ); } void MiscPageGroupwareTab::slotLegacyBodyInvitesToggled( bool on ) { if ( on ) { QString txt = i18n( "Invitations are normally sent as attachments to " "a mail. This switch changes the invitation mails to " "be sent in the text of the mail instead; this is " "necessary to send invitations and replies to " "Microsoft Outlook.
But, when you do this, you no " "longer get descriptive text that mail programs " "can read; so, to people who have email programs " "that do not understand the invitations, the " "resulting messages look very odd.
People that have email " "programs that do understand invitations will still " "be able to work with this.
" ); KMessageBox::information( this, txt, QString::null, "LegacyBodyInvitesWarning" ); } // Invitations in the body are autosent in any case (no point in editing raw ICAL) // So the autosend option is only available if invitations are sent as attachment. mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() ); } void MiscPage::GroupwareTab::doLoadFromGlobalSettings() { // Read the groupware config if ( mEnableGwCB ) { mEnableGwCB->setChecked( GlobalSettings::self()->groupwareEnabled() ); gBox->setEnabled( mEnableGwCB->isChecked() ); } mLegacyMangleFromTo->setChecked( GlobalSettings::self()->legacyMangleFromToHeaders() ); mLegacyBodyInvites->blockSignals( true ); mLegacyBodyInvites->setChecked( GlobalSettings::self()->legacyBodyInvites() ); mLegacyBodyInvites->blockSignals( false ); mAutomaticSending->setChecked( GlobalSettings::self()->automaticSending() ); mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() ); // Read the IMAP resource config mEnableImapResCB->setChecked( GlobalSettings::self()->theIMAPResourceEnabled() ); mBox->setEnabled( mEnableImapResCB->isChecked() ); mHideGroupwareFolders->setChecked( GlobalSettings::self()->hideGroupwareFolders() ); int i = GlobalSettings::self()->theIMAPResourceFolderLanguage(); mLanguageCombo->setCurrentItem(i); i = GlobalSettings::self()->theIMAPResourceStorageFormat(); mStorageFormatCombo->setCurrentItem(i); slotStorageFormatChanged( i ); QString folderId( GlobalSettings::self()->theIMAPResourceFolderParent() ); if( !folderId.isNull() && kmkernel->findFolderById( folderId ) ) { mFolderCombo->setFolder( folderId ); } else { // Folder was deleted, we have to choose a new one mFolderCombo->setFolder( i18n( "" ) ); } KMAccount* selectedAccount = 0; int accountId = GlobalSettings::self()->theIMAPResourceAccount(); if ( accountId ) selectedAccount = kmkernel->acctMgr()->find( accountId ); else { // Fallback: iterate over accounts to select folderId if found (as an inbox folder) for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0; a = kmkernel->acctMgr()->next() ) { if( a->folder() && a->folder()->child() ) { // Look inside that folder for an INBOX KMFolderNode *node; for (node = a->folder()->child()->first(); node; node = a->folder()->child()->next()) if (!node->isDir() && node->name() == "INBOX") break; if ( node && static_cast(node)->idString() == folderId ) { selectedAccount = a; break; } } } } if ( selectedAccount ) mAccountCombo->setCurrentAccount( selectedAccount ); else if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == 1 ) kdDebug(5006) << "Folder " << folderId << " not found as an account's inbox" << endl; } void MiscPage::GroupwareTab::save() { // Write the groupware config if ( mEnableGwCB ) GlobalSettings::self()->setGroupwareEnabled( mEnableGwCB->isChecked() ); GlobalSettings::self()->setLegacyMangleFromToHeaders( mLegacyMangleFromTo->isChecked() ); GlobalSettings::self()->setLegacyBodyInvites( mLegacyBodyInvites->isChecked() ); GlobalSettings::self()->setAutomaticSending( mAutomaticSending->isChecked() ); int format = mStorageFormatCombo->currentItem(); GlobalSettings::self()->setTheIMAPResourceStorageFormat( format ); // Write the IMAP resource config GlobalSettings::self()->setHideGroupwareFolders( mHideGroupwareFolders->isChecked() ); // If there is a leftover folder in the foldercombo, getFolder can // return 0. In that case we really don't have it enabled QString folderId; if ( format == 0 ) { KMFolder* folder = mFolderCombo->folder(); if ( folder ) folderId = folder->idString(); } else { // Inbox folder of the selected account KMAccount* acct = mAccountCombo->currentAccount(); if ( acct ) { folderId = QString( ".%1.directory/INBOX" ).arg( acct->id() ); GlobalSettings::self()->setTheIMAPResourceAccount( acct->id() ); } } bool enabled = mEnableImapResCB->isChecked() && !folderId.isEmpty(); GlobalSettings::self()->setTheIMAPResourceEnabled( enabled ); GlobalSettings::self()->setTheIMAPResourceFolderLanguage( mLanguageCombo->currentItem() ); GlobalSettings::self()->setTheIMAPResourceFolderParent( folderId ); } void MiscPage::GroupwareTab::slotStorageFormatChanged( int format ) { mLanguageCombo->setEnabled( format == 0 ); // only ical/vcard needs the language hack mFolderComboStack->raiseWidget( format ); if ( format == 0 ) { mFolderComboLabel->setText( i18n("&Resource folders are subfolders of:") ); mFolderComboLabel->setBuddy( mFolderCombo ); } else { mFolderComboLabel->setText( i18n("&Resource folders are in account:") ); mFolderComboLabel->setBuddy( mAccountCombo ); } slotEmitChanged(); } // ************************************************************* // * * // * AccountUpdater * // * * // ************************************************************* AccountUpdater::AccountUpdater(ImapAccountBase *account) : QObject() { mAccount = account; } void AccountUpdater::update() { connect( mAccount, SIGNAL( namespacesFetched() ), this, SLOT( namespacesFetched() ) ); mAccount->getNamespaces(); } void AccountUpdater::namespacesFetched() { mAccount->setCheckingMail( true ); mAccount->processNewMail( false ); deleteLater(); } #undef DIM //---------------------------- #include "configuredialog.moc" diff --git a/kmail/kmmainwidget.cpp b/kmail/kmmainwidget.cpp index 8ed4604ead..fdc3943b91 100644 --- a/kmail/kmmainwidget.cpp +++ b/kmail/kmmainwidget.cpp @@ -1,3623 +1,3623 @@ // -*- mode: C++; c-file-style: "gnu" -*- // kmmainwidget.cpp //#define MALLOC_DEBUG 1 #ifdef HAVE_CONFIG_H #include #endif #include #ifdef MALLOC_DEBUG #include #endif #undef Unsorted // X headers... #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "globalsettings.h" #include "kcursorsaver.h" #include "broadcaststatus.h" using KPIM::BroadcastStatus; #include "kmfoldermgr.h" #include "kmfolderdia.h" #include "accountmanager.h" using KMail::AccountManager; #include "kmfilter.h" #include "kmfoldertree.h" #include "kmreadermainwin.h" #include "kmfoldercachedimap.h" #include "kmfolderimap.h" #include "kmacctcachedimap.h" #include "composer.h" #include "kmfolderseldlg.h" #include "kmfiltermgr.h" #include "messagesender.h" #include "kmaddrbook.h" #include "kmversion.h" #include "searchwindow.h" using KMail::SearchWindow; #include "kmacctfolder.h" #include "undostack.h" #include "kmcommands.h" #include "kmmainwin.h" #include "kmsystemtray.h" #include "imapaccountbase.h" #include "transportmanager.h" using KMail::ImapAccountBase; #include "vacation.h" using KMail::Vacation; #include "subscriptiondialog.h" using KMail::SubscriptionDialog; #include "attachmentstrategy.h" using KMail::AttachmentStrategy; #include "headerstrategy.h" using KMail::HeaderStrategy; #include "headerstyle.h" using KMail::HeaderStyle; #include "folderjob.h" using KMail::FolderJob; #include "mailinglist-magic.h" #include "antispamwizard.h" using KMail::AntiSpamWizard; #include "filterlogdlg.h" using KMail::FilterLogDialog; #include using KMail::HeaderListQuickSearch; #include "kmheaders.h" #include "mailinglistpropertiesdialog.h" #if !defined(NDEBUG) #include "sievedebugdialog.h" using KMail::SieveDebugDialog; #endif #include #include #include #include #include #include using namespace KMime; using KMime::Types::AddrSpecList; #include "progressmanager.h" using KPIM::ProgressManager; #include "managesievescriptsdialog.h" #include #include "kmmainwidget.moc" QValueList* KMMainWidget::s_mainWidgetList = 0; static KStaticDeleter > mwlsd; //----------------------------------------------------------------------------- KMMainWidget::KMMainWidget(QWidget *parent, const char *name, KXMLGUIClient *aGUIClient, KActionCollection *actionCollection, KConfig* config ) : QWidget(parent, name), mQuickSearchLine( 0 ), mShowBusySplashTimer( 0 ), mShowingOfflineScreen( false ), mAccel( 0 ) { // must be the first line of the constructor: mStartupDone = FALSE; mSearchWin = 0; mIntegrated = TRUE; mFolder = 0; mFolderThreadPref = false; mFolderThreadSubjPref = true; mReaderWindowActive = true; mReaderWindowBelow = true; mFolderHtmlPref = false; mFolderHtmlLoadExtPref = false; mSystemTray = 0; mDestructed = false; mActionCollection = actionCollection; mTopLayout = new QVBoxLayout(this); mFilterMenuActions.setAutoDelete(true); mFilterTBarActions.setAutoDelete(false); mFilterCommands.setAutoDelete(true); mFolderShortcutCommands.setAutoDelete(true); mJob = 0; mConfig = config; mGUIClient = aGUIClient; // FIXME This should become a line separator as soon as the API // is extended in kdelibs. mToolbarActionSeparator = new KActionSeparator( actionCollection ); if( !s_mainWidgetList ) mwlsd.setObject( s_mainWidgetList, new QValueList() ); s_mainWidgetList->append( this ); mPanner1Sep << 1 << 1; mPanner2Sep << 1 << 1; setMinimumSize(400, 300); readPreConfig(); createWidgets(); setupActions(); readConfig(); activatePanners(); QTimer::singleShot( 0, this, SLOT( slotShowStartupFolder() )); connect( kmkernel->acctMgr(), SIGNAL( checkedMail( bool, bool, const QMap & ) ), this, SLOT( slotMailChecked( bool, bool, const QMap & ) ) ); connect( kmkernel->acctMgr(), SIGNAL( accountAdded( KMAccount* ) ), this, SLOT( initializeIMAPActions() ) ); connect( kmkernel->acctMgr(), SIGNAL( accountRemoved( KMAccount* ) ), this, SLOT( initializeIMAPActions() ) ); connect(kmkernel, SIGNAL( configChanged() ), this, SLOT( slotConfigChanged() )); // display the full path to the folder in the caption connect(mFolderTree, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(slotChangeCaption(QListViewItem*))); connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)), this, SLOT(slotFolderRemoved(KMFolder*))); connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)), this, SLOT(slotFolderRemoved(KMFolder*))); connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)), this, SLOT(slotFolderRemoved(KMFolder*))); connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)), this, SLOT(slotFolderRemoved(KMFolder*))); toggleSystemTray(); // must be the last line of the constructor: mStartupDone = TRUE; } //----------------------------------------------------------------------------- //The kernel may have already been deleted when this method is called, //perform all cleanup that requires the kernel in destruct() KMMainWidget::~KMMainWidget() { s_mainWidgetList->remove( this ); destruct(); } //----------------------------------------------------------------------------- //This method performs all cleanup that requires the kernel to exist. void KMMainWidget::destruct() { if (mDestructed) return; if (mSearchWin) mSearchWin->close(); writeConfig(); writeFolderConfig(); delete mHeaders; delete mFolderTree; delete mSystemTray; delete mMsgView; mDestructed = true; } //----------------------------------------------------------------------------- void KMMainWidget::readPreConfig(void) { const KConfigGroup geometry( KMKernel::config(), "Geometry" ); const KConfigGroup general( KMKernel::config(), "General" ); mLongFolderList = geometry.readEntry( "FolderList", "long" ) != "short"; mReaderWindowActive = geometry.readEntry( "readerWindowMode", "below" ) != "hide"; mReaderWindowBelow = geometry.readEntry( "readerWindowMode", "below" ) == "below"; } //----------------------------------------------------------------------------- void KMMainWidget::readFolderConfig(void) { if (!mFolder) return; KConfig *config = KMKernel::config(); KConfigGroupSaver saver(config, "Folder-" + mFolder->idString()); mFolderThreadPref = config->readBoolEntry( "threadMessagesOverride", false ); mFolderThreadSubjPref = config->readBoolEntry( "threadMessagesBySubject", true ); mFolderHtmlPref = config->readBoolEntry( "htmlMailOverride", false ); mFolderHtmlLoadExtPref = config->readBoolEntry( "htmlLoadExternalOverride", false ); } //----------------------------------------------------------------------------- void KMMainWidget::writeFolderConfig(void) { if (!mFolder) return; KConfig *config = KMKernel::config(); KConfigGroupSaver saver(config, "Folder-" + mFolder->idString()); config->writeEntry( "threadMessagesOverride", mFolderThreadPref ); config->writeEntry( "threadMessagesBySubject", mFolderThreadSubjPref ); config->writeEntry( "htmlMailOverride", mFolderHtmlPref ); config->writeEntry( "htmlLoadExternalOverride", mFolderHtmlLoadExtPref ); } //----------------------------------------------------------------------------- void KMMainWidget::readConfig(void) { KConfig *config = KMKernel::config(); bool oldLongFolderList = mLongFolderList; bool oldReaderWindowActive = mReaderWindowActive; bool oldReaderWindowBelow = mReaderWindowBelow; QString str; QSize siz; if (mStartupDone) { writeConfig(); readPreConfig(); mHeaders->refreshNestedState(); bool layoutChanged = ( oldLongFolderList != mLongFolderList ) || ( oldReaderWindowActive != mReaderWindowActive ) || ( oldReaderWindowBelow != mReaderWindowBelow ); if( layoutChanged ) { hide(); // delete all panners delete mPanner1; // will always delete the others createWidgets(); } } // read "Reader" config options KConfigGroup readerConfig( config, "Reader" ); mHtmlPref = readerConfig.readBoolEntry( "htmlMail", false ); mHtmlLoadExtPref = readerConfig.readBoolEntry( "htmlLoadExternal", false ); { // area for config group "Geometry" KConfigGroupSaver saver(config, "Geometry"); mThreadPref = config->readBoolEntry( "nestedMessages", false ); // size of the mainwin QSize defaultSize(750,560); siz = config->readSizeEntry("MainWin", &defaultSize); if (!siz.isEmpty()) resize(siz); // default width of the foldertree static const int folderpanewidth = 250; const int folderW = config->readNumEntry( "FolderPaneWidth", folderpanewidth ); const int headerW = config->readNumEntry( "HeaderPaneWidth", width()-folderpanewidth ); const int headerH = config->readNumEntry( "HeaderPaneHeight", 180 ); const int readerH = config->readNumEntry( "ReaderPaneHeight", 280 ); mPanner1Sep.clear(); mPanner2Sep.clear(); QValueList & widths = mLongFolderList ? mPanner1Sep : mPanner2Sep ; QValueList & heights = mLongFolderList ? mPanner2Sep : mPanner1Sep ; widths << folderW << headerW; heights << headerH << readerH; bool layoutChanged = ( oldLongFolderList != mLongFolderList ) || ( oldReaderWindowActive != mReaderWindowActive ) || ( oldReaderWindowBelow != mReaderWindowBelow ); if (!mStartupDone || layoutChanged ) { /** unread / total columns * as we have some dependencies in this widget * it's better to manage these here */ // The columns are shown by default. const int unreadColumn = config->readNumEntry("UnreadColumn", 1); const int totalColumn = config->readNumEntry("TotalColumn", 2); /* we need to _activate_ them in the correct order * this is ugly because we can't use header()->moveSection * but otherwise the restoreLayout from KMFolderTree * doesn't know that to do */ if (unreadColumn != -1 && unreadColumn < totalColumn) mFolderTree->addUnreadColumn( i18n("Unread"), 70 ); if (totalColumn != -1) mFolderTree->addTotalColumn( i18n("Total"), 70 ); if (unreadColumn != -1 && unreadColumn > totalColumn) mFolderTree->addUnreadColumn( i18n("Unread"), 70 ); mUnreadColumnToggle->setChecked( mFolderTree->isUnreadActive() ); mUnreadTextToggle->setChecked( !mFolderTree->isUnreadActive() ); mTotalColumnToggle->setChecked( mFolderTree->isTotalActive() ); mFolderTree->updatePopup(); } } if (mMsgView) mMsgView->readConfig(); mHeaders->readConfig(); mHeaders->restoreLayout(KMKernel::config(), "Header-Geometry"); mFolderTree->readConfig(); { // area for config group "General" KConfigGroupSaver saver(config, "General"); mBeepOnNew = config->readBoolEntry("beep-on-mail", false); mConfirmEmpty = config->readBoolEntry("confirm-before-empty", true); // startup-Folder, defaults to system-inbox mStartupFolder = config->readEntry("startupFolder", kmkernel->inboxFolder()->idString()); if (!mStartupDone) { // check mail on startup bool check = config->readBoolEntry("checkmail-startup", false); if (check) // do it after building the kmmainwin, so that the progressdialog is available QTimer::singleShot( 0, this, SLOT( slotCheckMail() ) ); } } // reload foldertree mFolderTree->reload(); // Re-activate panners if (mStartupDone) { // Update systray toggleSystemTray(); bool layoutChanged = ( oldLongFolderList != mLongFolderList ) || ( oldReaderWindowActive != mReaderWindowActive ) || ( oldReaderWindowBelow != mReaderWindowBelow ); if ( layoutChanged ) { activatePanners(); } mFolderTree->showFolder( mFolder ); // sanders - New code mHeaders->setFolder(mFolder); if (mMsgView) { int aIdx = mHeaders->currentItemIndex(); if (aIdx != -1) mMsgView->setMsg( mFolder->getMsg(aIdx), true ); else mMsgView->clear( true ); } updateMessageActions(); show(); // sanders - Maybe this fixes a bug? } updateMessageMenu(); updateFileMenu(); } //----------------------------------------------------------------------------- void KMMainWidget::writeConfig(void) { QString s; KConfig *config = KMKernel::config(); KConfigGroup geometry( config, "Geometry" ); KConfigGroup general( config, "General" ); if (mMsgView) mMsgView->writeConfig(); mFolderTree->writeConfig(); geometry.writeEntry( "MainWin", this->geometry().size() ); const QValueList widths = ( mLongFolderList ? mPanner1 : mPanner2 )->sizes(); const QValueList heights = ( mLongFolderList ? mPanner2 : mPanner1 )->sizes(); geometry.writeEntry( "FolderPaneWidth", widths[0] ); geometry.writeEntry( "HeaderPaneWidth", widths[1] ); // Only save when the widget is shown (to avoid saving a wrong value) if ( mSearchAndHeaders && mSearchAndHeaders->isShown() ) { geometry.writeEntry( "HeaderPaneHeight", heights[0] ); geometry.writeEntry( "ReaderPaneHeight", heights[1] ); } // save the state of the unread/total-columns geometry.writeEntry( "UnreadColumn", mFolderTree->unreadIndex() ); geometry.writeEntry( "TotalColumn", mFolderTree->totalIndex() ); } //----------------------------------------------------------------------------- void KMMainWidget::createWidgets(void) { mAccel = new QAccel(this, "createWidgets()"); // Create the splitters according to the layout settings QWidget *headerParent = 0, *folderParent = 0, *mimeParent = 0, *messageParent = 0; const bool opaqueResize = KGlobalSettings::opaqueResize(); if ( mLongFolderList ) { // superior splitter: folder tree vs. rest // inferior splitter: headers vs. message vs. mime tree mPanner1 = new QSplitter( Qt::Horizontal, this, "panner 1" ); mPanner1->setOpaqueResize( opaqueResize ); Qt::Orientation orientation = mReaderWindowBelow ? Qt::Vertical : Qt::Horizontal; mPanner2 = new QSplitter( orientation, mPanner1, "panner 2" ); mPanner2->setOpaqueResize( opaqueResize ); folderParent = mPanner1; headerParent = mimeParent = messageParent = mPanner2; } else /* !mLongFolderList */ { // superior splitter: ( folder tree + headers ) vs. message vs. mime // inferior splitter: folder tree vs. headers mPanner1 = new QSplitter( Qt::Vertical, this, "panner 1" ); mPanner1->setOpaqueResize( opaqueResize ); mPanner2 = new QSplitter( Qt::Horizontal, mPanner1, "panner 2" ); mPanner2->setOpaqueResize( opaqueResize ); headerParent = folderParent = mPanner2; mimeParent = messageParent = mPanner1; } #ifndef NDEBUG if( mPanner1 ) mPanner1->dumpObjectTree(); if( mPanner2 ) mPanner2->dumpObjectTree(); #endif mTopLayout->add( mPanner1 ); // BUG -sanders these accelerators stop working after switching // between long/short folder layout // Probably need to disconnect them first. // create list of messages #ifndef NDEBUG headerParent->dumpObjectTree(); #endif mSearchAndHeaders = new QVBox( headerParent ); mSearchToolBar = new KToolBar( mSearchAndHeaders, "search toolbar"); mSearchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() ); QLabel *label = new QLabel( i18n("S&earch:"), mSearchToolBar, "kde toolbar widget" ); mHeaders = new KMHeaders(this, mSearchAndHeaders, "headers"); mQuickSearchLine = new HeaderListQuickSearch( mSearchToolBar, mHeaders, actionCollection(), "headers quick search line" ); label->setBuddy( mQuickSearchLine ); mSearchToolBar->setStretchableWidget( mQuickSearchLine ); connect( mHeaders, SIGNAL( messageListUpdated() ), mQuickSearchLine, SLOT( updateSearch() ) ); if ( !GlobalSettings::self()->quickSearchActive() ) mSearchToolBar->hide(); if (mReaderWindowActive) { connect(mHeaders, SIGNAL(selected(KMMessage*)), this, SLOT(slotMsgSelected(KMMessage*))); } connect(mHeaders, SIGNAL(activated(KMMessage*)), this, SLOT(slotMsgActivated(KMMessage*))); connect( mHeaders, SIGNAL( selectionChanged() ), SLOT( startUpdateMessageActionsTimer() ) ); mAccel->connectItem(mAccel->insertItem(SHIFT+Key_Left), mHeaders, SLOT(selectPrevMessage())); mAccel->connectItem(mAccel->insertItem(SHIFT+Key_Right), mHeaders, SLOT(selectNextMessage())); if (mReaderWindowActive) { mMsgView = new KMReaderWin(messageParent, this, actionCollection(), 0 ); connect(mMsgView, SIGNAL(replaceMsgByUnencryptedVersion()), this, SLOT(slotReplaceMsgByUnencryptedVersion())); connect(mMsgView, SIGNAL(popupMenu(KMMessage&,const KURL&,const QPoint&)), this, SLOT(slotMsgPopup(KMMessage&,const KURL&,const QPoint&))); connect(mMsgView, SIGNAL(urlClicked(const KURL&,int)), mMsgView, SLOT(slotUrlClicked())); connect(mHeaders, SIGNAL(maybeDeleting()), mMsgView, SLOT(clearCache())); connect(mMsgView, SIGNAL(noDrag()), mHeaders, SLOT(slotNoDrag())); mAccel->connectItem(mAccel->insertItem(Key_Up), mMsgView, SLOT(slotScrollUp())); mAccel->connectItem(mAccel->insertItem(Key_Down), mMsgView, SLOT(slotScrollDown())); mAccel->connectItem(mAccel->insertItem(Key_Prior), mMsgView, SLOT(slotScrollPrior())); mAccel->connectItem(mAccel->insertItem(Key_Next), mMsgView, SLOT(slotScrollNext())); } else { mMsgView = NULL; } new KAction( i18n("Move Message to Folder"), Key_M, this, SLOT(slotMoveMsg()), actionCollection(), "move_message_to_folder" ); new KAction( i18n("Copy Message to Folder"), Key_C, this, SLOT(slotCopyMsg()), actionCollection(), "copy_message_to_folder" ); mAccel->connectItem(mAccel->insertItem(Key_M), this, SLOT(slotMoveMsg()) ); mAccel->connectItem(mAccel->insertItem(Key_C), this, SLOT(slotCopyMsg()) ); // create list of folders mFolderTree = new KMFolderTree(this, folderParent, "folderTree"); connect(mFolderTree, SIGNAL(folderSelected(KMFolder*)), this, SLOT(folderSelected(KMFolder*))); connect( mFolderTree, SIGNAL( folderSelected( KMFolder* ) ), mQuickSearchLine, SLOT( reset() ) ); connect(mFolderTree, SIGNAL(folderSelectedUnread(KMFolder*)), this, SLOT(folderSelectedUnread(KMFolder*))); connect(mFolderTree, SIGNAL(folderDrop(KMFolder*)), this, SLOT(slotMoveMsgToFolder(KMFolder*))); connect(mFolderTree, SIGNAL(folderDropCopy(KMFolder*)), this, SLOT(slotCopyMsgToFolder(KMFolder*))); connect(mFolderTree, SIGNAL(columnsChanged()), this, SLOT(slotFolderTreeColumnsChanged())); //Commands not worthy of menu items, but that deserve configurable keybindings new KAction( i18n("Remove Duplicate Messages"), CTRL+Key_Asterisk, this, SLOT(removeDuplicates()), actionCollection(), "remove_duplicate_messages"); new KAction( i18n("Abort Current Operation"), Key_Escape, ProgressManager::instance(), SLOT(slotAbortAll()), actionCollection(), "cancel" ); mAccel->connectItem(mAccel->insertItem(Key_Escape), ProgressManager::instance(), SLOT(slotAbortAll())); new KAction( i18n("Focus on Next Folder"), CTRL+Key_Right, mFolderTree, SLOT(incCurrentFolder()), actionCollection(), "inc_current_folder"); mAccel->connectItem(mAccel->insertItem(CTRL+Key_Right), mFolderTree, SLOT(incCurrentFolder())); new KAction( i18n("Focus on Previous Folder"), CTRL+Key_Left, mFolderTree, SLOT(decCurrentFolder()), actionCollection(), "dec_current_folder"); mAccel->connectItem(mAccel->insertItem(CTRL+Key_Left), mFolderTree, SLOT(decCurrentFolder())); new KAction( i18n("Select Folder with Focus"), CTRL+Key_Space, mFolderTree, SLOT(selectCurrentFolder()), actionCollection(), "select_current_folder"); mAccel->connectItem(mAccel->insertItem(CTRL+Key_Space), mFolderTree, SLOT(selectCurrentFolder())); new KAction( i18n("Focus on Next Message"), ALT+Key_Right, mHeaders, SLOT(incCurrentMessage()), actionCollection(), "inc_current_message"); mAccel->connectItem( mAccel->insertItem( ALT+Key_Right ), mHeaders, SLOT( incCurrentMessage() ) ); new KAction( i18n("Focus on Previous Message"), ALT+Key_Left, mHeaders, SLOT(decCurrentMessage()), actionCollection(), "dec_current_message"); mAccel->connectItem( mAccel->insertItem( ALT+Key_Left ), mHeaders, SLOT( decCurrentMessage() ) ); new KAction( i18n("Select Message with Focus"), ALT+Key_Space, mHeaders, SLOT( selectCurrentMessage() ), actionCollection(), "select_current_message"); mAccel->connectItem( mAccel->insertItem( ALT+Key_Space ), mHeaders, SLOT( selectCurrentMessage() ) ); connect( kmkernel->outboxFolder(), SIGNAL( msgRemoved(int, QString) ), SLOT( startUpdateMessageActionsTimer() ) ); connect( kmkernel->outboxFolder(), SIGNAL( msgAdded(int) ), SLOT( startUpdateMessageActionsTimer() ) ); } //----------------------------------------------------------------------------- void KMMainWidget::activatePanners(void) { if (mMsgView) { QObject::disconnect( mMsgView->copyAction(), SIGNAL( activated() ), mMsgView, SLOT( slotCopySelectedText() )); } if ( mLongFolderList ) { mSearchAndHeaders->reparent( mPanner2, 0, QPoint( 0, 0 ) ); if (mMsgView) { mMsgView->reparent( mPanner2, 0, QPoint( 0, 0 ) ); mPanner2->moveToLast( mMsgView ); } mFolderTree->reparent( mPanner1, 0, QPoint( 0, 0 ) ); mPanner1->moveToLast( mPanner2 ); mPanner1->setSizes( mPanner1Sep ); mPanner1->setResizeMode( mFolderTree, QSplitter::KeepSize ); mPanner2->setSizes( mPanner2Sep ); mPanner2->setResizeMode( mSearchAndHeaders, QSplitter::KeepSize ); } else /* !mLongFolderList */ { mFolderTree->reparent( mPanner2, 0, QPoint( 0, 0 ) ); mSearchAndHeaders->reparent( mPanner2, 0, QPoint( 0, 0 ) ); mPanner2->moveToLast( mSearchAndHeaders ); mPanner1->moveToFirst( mPanner2 ); if (mMsgView) { mMsgView->reparent( mPanner1, 0, QPoint( 0, 0 ) ); mPanner1->moveToLast( mMsgView ); } mPanner1->setSizes( mPanner1Sep ); mPanner2->setSizes( mPanner2Sep ); mPanner1->setResizeMode( mPanner2, QSplitter::KeepSize ); mPanner2->setResizeMode( mFolderTree, QSplitter::KeepSize ); } if (mMsgView) { QObject::connect( mMsgView->copyAction(), SIGNAL( activated() ), mMsgView, SLOT( slotCopySelectedText() )); } } //----------------------------------------------------------------------------- void KMMainWidget::hide() { QWidget::hide(); } //----------------------------------------------------------------------------- void KMMainWidget::show() { QWidget::show(); } //------------------------------------------------------------------------- void KMMainWidget::slotSearch() { if(!mSearchWin) { mSearchWin = new SearchWindow(this, "Search", mFolder, false); connect(mSearchWin, SIGNAL(destroyed()), this, SLOT(slotSearchClosed())); } else { mSearchWin->activateFolder(mFolder); } mSearchWin->show(); KWin::activateWindow( mSearchWin->winId() ); } //------------------------------------------------------------------------- void KMMainWidget::slotSearchClosed() { mSearchWin = 0; } //------------------------------------------------------------------------- void KMMainWidget::slotFind() { if( mMsgView ) mMsgView->slotFind(); } //----------------------------------------------------------------------------- void KMMainWidget::slotHelp() { kapp->invokeHelp(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFilter() { kmkernel->filterMgr()->openDialog( this ); } //----------------------------------------------------------------------------- void KMMainWidget::slotPopFilter() { kmkernel->popFilterMgr()->openDialog( this ); } void KMMainWidget::slotManageSieveScripts() { if ( !kmkernel->askToGoOnline() ) { return; } KMail::ManageSieveScriptsDialog * dlg = new KMail::ManageSieveScriptsDialog( this ); dlg->show(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAddrBook() { KAddrBookExternal::openAddressBook(this); } //----------------------------------------------------------------------------- void KMMainWidget::slotImport() { KRun::runCommand("kmailcvt"); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckMail() { if ( !kmkernel->askToGoOnline() ) { return; } kmkernel->acctMgr()->checkMail(true); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckOneAccount(int item) { if ( !kmkernel->askToGoOnline() ) { return; } kmkernel->acctMgr()->intCheckMail(item); } //----------------------------------------------------------------------------- void KMMainWidget::slotMailChecked( bool newMail, bool sendOnCheck, const QMap & newInFolder ) { const bool sendOnAll = GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnAllChecks; const bool sendOnManual = GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnManualChecks; if( sendOnAll || (sendOnManual && sendOnCheck ) ) slotSendQueued(); if ( !newMail || newInFolder.isEmpty() ) return; kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", QByteArray() ); // build summary for new mail message bool showNotification = false; QString summary; QStringList keys( newInFolder.keys() ); keys.sort(); for ( QStringList::const_iterator it = keys.begin(); it != keys.end(); ++it ) { kdDebug(5006) << newInFolder.find( *it ).data() << " new message(s) in " << *it << endl; KMFolder *folder = kmkernel->findFolderById( *it ); if ( !folder->ignoreNewMail() ) { showNotification = true; if ( GlobalSettings::self()->verboseNewMailNotification() ) { summary += "
" + i18n( "1 new message in %1", "%n new messages in %1", newInFolder.find( *it ).data() ) .arg( folder->prettyURL() ); } } } if ( !showNotification ) return; if ( GlobalSettings::self()->verboseNewMailNotification() ) { summary = i18n( "%1 is a list of the number of new messages per folder", "New mail arrived
%1" ) .arg( summary ); } else { summary = i18n( "New mail arrived" ); } if(kmkernel->xmlGuiInstance()) { KNotifyClient::Instance instance(kmkernel->xmlGuiInstance()); KNotifyClient::event( topLevelWidget()->winId(), "new-mail-arrived", summary ); } else KNotifyClient::event( topLevelWidget()->winId(), "new-mail-arrived", summary ); if (mBeepOnNew) { KNotifyClient::beep(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotCompose() { KMail::Composer * win; KMMessage* msg = new KMMessage; if ( mFolder ) { msg->initHeader( mFolder->identity() ); win = KMail::makeComposer( msg, mFolder->identity() ); } else { msg->initHeader(); win = KMail::makeComposer( msg ); } win->show(); } //----------------------------------------------------------------------------- void KMMainWidget::slotPostToML() { if ( mFolder && mFolder->isMailingListEnabled() ) { KMCommand *command = new KMMailingListPostCommand( this, mFolder ); command->start(); } else slotCompose(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFolderMailingListProperties() { if (!mFolderTree) return; KMFolderTreeItem *item = static_cast( mFolderTree->currentItem() ); if ( !item ) return; KMFolder* folder = item->folder(); if ( folder ) { ( new KMail::MailingListFolderPropertiesDialog( this, folder ) )->show(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotFolderShortcutCommand() { if (!mFolderTree) return; KMFolderTreeItem *item = static_cast( mFolderTree->currentItem() ); if ( item ) item->assignShortcut(); } //----------------------------------------------------------------------------- void KMMainWidget::slotModifyFolder() { if (!mFolderTree) return; KMFolderTreeItem *item = static_cast( mFolderTree->currentItem() ); if ( item ) modifyFolder( item ); } //----------------------------------------------------------------------------- void KMMainWidget::modifyFolder( KMFolderTreeItem* folderItem ) { KMFolder* folder = folderItem->folder(); KMFolderTree* folderTree = static_cast( folderItem->listView() ); KMFolderDialog props( folder, folder->parent(), folderTree, i18n("Properties of Folder %1").arg( folder->label() ) ); props.exec(); updateFolderMenu(); } //----------------------------------------------------------------------------- void KMMainWidget::slotExpireFolder() { QString str; bool canBeExpired = true; if (!mFolder) return; if (!mFolder->isAutoExpire()) { canBeExpired = false; } else if (mFolder->getUnreadExpireUnits()==expireNever && mFolder->getReadExpireUnits()==expireNever) { canBeExpired = false; } if (!canBeExpired) { str = i18n("This folder does not have any expiry options set"); KMessageBox::information(this, str); return; } KConfig *config = KMKernel::config(); KConfigGroupSaver saver(config, "General"); if (config->readBoolEntry("warn-before-expire", true)) { str = i18n("Are you sure you want to expire the folder %1?").arg(QStyleSheet::escape( mFolder->label() )); if (KMessageBox::warningContinueCancel(this, str, i18n("Expire Folder"), i18n("&Expire")) != KMessageBox::Continue) return; } mFolder->expireOldMessages( true /*immediate*/); } //----------------------------------------------------------------------------- void KMMainWidget::slotEmptyFolder() { QString str; if (!mFolder) return; bool isTrash = kmkernel->folderIsTrash(mFolder); if (mConfirmEmpty) { QString title = (isTrash) ? i18n("Empty Trash") : i18n("Move to Trash"); QString text = (isTrash) ? i18n("Are you sure you want to empty the trash folder?") : i18n("Are you sure you want to move all messages from " "folder %1 to the trash?").arg( QStyleSheet::escape( mFolder->label() ) ); if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem( title, "edittrash")) != KMessageBox::Continue) return; } KCursorSaver busy(KBusyPtr::busy()); slotMarkAll(); if (isTrash) { /* Don't ask for confirmation again when deleting, the user has already confirmed. */ slotDeleteMsg( false ); } else slotTrashMsg(); if (mMsgView) mMsgView->clearCache(); if ( !isTrash ) BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash")); updateMessageActions(); } //----------------------------------------------------------------------------- void KMMainWidget::slotRemoveFolder() { QString str; QDir dir; if ( !mFolder ) return; if ( mFolder->isSystemFolder() ) return; if ( mFolder->isReadOnly() ) return; QString title; if ( mFolder->folderType() == KMFolderTypeSearch ) { title = i18n("Delete Search"); str = i18n("Are you sure you want to delete the search %1?
" "Any messages it shows will still be available in their original folder.
") .arg( QStyleSheet::escape( mFolder->label() ) ); } else { title = i18n("Delete Folder"); if ( mFolder->count() == 0 ) { if ( !mFolder->child() || mFolder->child()->isEmpty() ) { str = i18n("Are you sure you want to delete the empty folder " "%1?") .arg( QStyleSheet::escape( mFolder->label() ) ); } else { str = i18n("Are you sure you want to delete the empty folder " "%1 and all its subfolders? Those subfolders " "might not be empty and their contents will be " "discarded as well.") .arg( QStyleSheet::escape( mFolder->label() ) ); } } else { if ( !mFolder->child() || mFolder->child()->isEmpty() ) { str = i18n("Are you sure you want to delete the folder " "%1, discarding its contents?") .arg( QStyleSheet::escape( mFolder->label() ) ); } else { str = i18n("Are you sure you want to delete the folder " "%1 and all its subfolders, discarding their " "contents?") .arg( QStyleSheet::escape( mFolder->label() ) ); } } } if (KMessageBox::warningContinueCancel(this, str, title, KGuiItem( i18n("&Delete"), "editdelete")) == KMessageBox::Continue) { if ( mFolder->hasAccounts() ) { // this folder has an account, so we need to change that to the inbox for ( AccountList::Iterator it (mFolder->acctList()->begin() ), end( mFolder->acctList()->end() ); it != end; ++it ) { (*it)->setFolder( kmkernel->inboxFolder() ); KMessageBox::information(this, i18n("The folder you deleted was assoicated with the account " "%1 which delivered mail into it. The folder the account " "delivers new mail into was reset to the main Inbox folder.").arg( (*it)->name())); } } if (mFolder->folderType() == KMFolderTypeImap) kmkernel->imapFolderMgr()->remove(mFolder); else if (mFolder->folderType() == KMFolderTypeCachedImap) { // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2) KMFolderCachedImap* storage = static_cast( mFolder->storage() ); KMAcctCachedImap* acct = storage->account(); if ( acct ) acct->addDeletedFolder( mFolder ); kmkernel->dimapFolderMgr()->remove(mFolder); } else if (mFolder->folderType() == KMFolderTypeSearch) kmkernel->searchFolderMgr()->remove(mFolder); else kmkernel->folderMgr()->remove(mFolder); } } //----------------------------------------------------------------------------- void KMMainWidget::slotMarkAllAsRead() { if (!mFolder) return; mFolder->markUnreadAsRead(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCompactFolder() { if (mFolder) { int idx = mHeaders->currentItemIndex(); KCursorSaver busy(KBusyPtr::busy()); mFolder->compact( KMFolder::CompactNow ); // setCurrentItemByIndex will override the statusbar message, so save/restore it QString statusMsg = BroadcastStatus::instance()->statusMsg(); mHeaders->setCurrentItemByIndex(idx); BroadcastStatus::instance()->setStatusMsg( statusMsg ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotRefreshFolder() { if (mFolder) { if ( mFolder->folderType() == KMFolderTypeImap || mFolder->folderType() == KMFolderTypeCachedImap ) { if ( !kmkernel->askToGoOnline() ) { return; } } if (mFolder->folderType() == KMFolderTypeImap) { KMFolderImap *imap = static_cast(mFolder->storage()); imap->getAndCheckFolder(); } else if ( mFolder->folderType() == KMFolderTypeCachedImap ) { KMFolderCachedImap* f = static_cast( mFolder->storage() ); f->account()->processNewMailSingleFolder( mFolder ); } } } void KMMainWidget::slotTroubleshootFolder() { if (mFolder) { if ( mFolder->folderType() == KMFolderTypeCachedImap ) { KMFolderCachedImap* f = static_cast( mFolder->storage() ); f->slotTroubleshoot(); } } } void KMMainWidget::slotInvalidateIMAPFolders() { if ( KMessageBox::warningContinueCancel( this, i18n("Are you sure you want to refresh the IMAP cache?\n" "This will remove all changes that you have done " "locally to your IMAP folders."), i18n("Refresh IMAP Cache"), i18n("&Refresh") ) == KMessageBox::Continue ) kmkernel->acctMgr()->invalidateIMAPFolders(); } //----------------------------------------------------------------------------- void KMMainWidget::slotExpireAll() { KConfig *config = KMKernel::config(); int ret = 0; KConfigGroupSaver saver(config, "General"); if (config->readBoolEntry("warn-before-expire", true)) { ret = KMessageBox::warningContinueCancel(KMainWindow::memberList->first(), i18n("Are you sure you want to expire all old messages?"), i18n("Expire Old Messages?"), i18n("Expire")); if (ret != KMessageBox::Continue) { return; } } kmkernel->expireAllFoldersNow(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCompactAll() { KCursorSaver busy(KBusyPtr::busy()); kmkernel->compactAllFolders(); } //----------------------------------------------------------------------------- void KMMainWidget::slotOverrideHtml() { if( mHtmlPref == mFolderHtmlPref ) { int result = KMessageBox::warningContinueCancel( this, // the warning text is taken from configuredialog.cpp: i18n( "Use of HTML in mail will make you more vulnerable to " "\"spam\" and may increase the likelihood that your system will be " "compromised by other present and anticipated security exploits." ), i18n( "Security Warning" ), i18n( "Use HTML" ), "OverrideHtmlWarning", false); if( result == KMessageBox::Cancel ) { mPreferHtmlAction->setChecked( false ); return; } } mFolderHtmlPref = !mFolderHtmlPref; if (mMsgView) { mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->update( true ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotOverrideHtmlLoadExt() { if( mHtmlLoadExtPref == mFolderHtmlLoadExtPref ) { int result = KMessageBox::warningContinueCancel( this, // the warning text is taken from configuredialog.cpp: i18n( "Loading external references in html mail will make you more vulnerable to " "\"spam\" and may increase the likelihood that your system will be " "compromised by other present and anticipated security exploits." ), i18n( "Security Warning" ), i18n( "Load External References" ), "OverrideHtmlLoadExtWarning", false); if( result == KMessageBox::Cancel ) { mPreferHtmlLoadExtAction->setChecked( false ); return; } } mFolderHtmlLoadExtPref = !mFolderHtmlLoadExtPref; if (mMsgView) { mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); mMsgView->update( true ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotOverrideThread() { mFolderThreadPref = !mFolderThreadPref; mHeaders->setNestedOverride(mFolderThreadPref); mThreadBySubjectAction->setEnabled(mThreadMessagesAction->isChecked()); } //----------------------------------------------------------------------------- void KMMainWidget::slotToggleSubjectThreading() { mFolderThreadSubjPref = !mFolderThreadSubjPref; mHeaders->setSubjectThreading(mFolderThreadSubjPref); } //----------------------------------------------------------------------------- void KMMainWidget::slotToggleShowQuickSearch() { GlobalSettings::self()->setQuickSearchActive( !GlobalSettings::self()->quickSearchActive() ); if ( GlobalSettings::self()->quickSearchActive() ) mSearchToolBar->show(); else { mQuickSearchLine->reset(); mSearchToolBar->hide(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotMessageQueuedOrDrafted() { if (!kmkernel->folderIsDraftOrOutbox(mFolder)) return; if (mMsgView) mMsgView->update(true); } //----------------------------------------------------------------------------- void KMMainWidget::slotForwardMsg() { KMMessageList* selected = mHeaders->selectedMsgs(); KMCommand *command = 0L; if(selected && !selected->isEmpty()) { command = new KMForwardCommand( this, *selected, mFolder->identity() ); } else { command = new KMForwardCommand( this, mHeaders->currentMsg(), mFolder->identity() ); } command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotForwardAttachedMsg() { KMMessageList* selected = mHeaders->selectedMsgs(); KMCommand *command = 0L; if(selected && !selected->isEmpty()) { command = new KMForwardAttachedCommand( this, *selected, mFolder->identity() ); } else { command = new KMForwardAttachedCommand( this, mHeaders->currentMsg(), mFolder->identity() ); } command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotEditMsg() { KMCommand *command = new KMEditMsgCommand( this, mHeaders->currentMsg() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotResendMsg() { KMCommand *command = new KMResendMessageCommand( this, mHeaders->currentMsg() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotTrashMsg() { mHeaders->deleteMsg(); } //----------------------------------------------------------------------------- void KMMainWidget::slotDeleteMsg( bool confirmDelete ) { mHeaders->moveMsgToFolder( 0, confirmDelete ); } //----------------------------------------------------------------------------- void KMMainWidget::slotTrashThread() { mHeaders->highlightCurrentThread(); mHeaders->deleteMsg(); } //----------------------------------------------------------------------------- void KMMainWidget::slotDeleteThread( bool confirmDelete ) { mHeaders->highlightCurrentThread(); mHeaders->moveMsgToFolder( 0, confirmDelete ); } //----------------------------------------------------------------------------- void KMMainWidget::slotReplyToMsg() { QString text = mMsgView? mMsgView->copyText() : ""; KMCommand *command = new KMReplyToCommand( this, mHeaders->currentMsg(), text ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotReplyAuthorToMsg() { QString text = mMsgView? mMsgView->copyText() : ""; KMCommand *command = new KMReplyAuthorCommand( this, mHeaders->currentMsg(), text ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotReplyAllToMsg() { QString text = mMsgView? mMsgView->copyText() : ""; KMCommand *command = new KMReplyToAllCommand( this, mHeaders->currentMsg(), text ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotRedirectMsg() { KMCommand *command = new KMRedirectCommand( this, mHeaders->currentMsg() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotReplyListToMsg() { QString text = mMsgView? mMsgView->copyText() : ""; KMCommand *command = new KMReplyListCommand( this, mHeaders->currentMsg(), text ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotNoQuoteReplyToMsg() { KMCommand *command = new KMNoQuoteReplyToCommand( this, mHeaders->currentMsg() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSubjectFilter() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; KMCommand *command = new KMFilterCommand( "Subject", msg->subject() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotMailingListFilter() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; KMCommand *command = new KMMailingListFilterCommand( this, msg ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFromFilter() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; AddrSpecList al = msg->extractAddrSpecs( "From" ); KMCommand *command; if ( al.empty() ) command = new KMFilterCommand( "From", msg->from() ); else command = new KMFilterCommand( "From", al.front().asString() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotToFilter() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; KMCommand *command = new KMFilterCommand( "To", msg->to() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::updateListFilterAction() { //Proxy the mListFilterAction to update the action text QCString name; QString value; QString lname = MailingList::name( mHeaders->currentMsg(), name, value ); mListFilterAction->setText( i18n("Filter on Mailing-List...") ); if ( lname.isNull() ) mListFilterAction->setEnabled( false ); else { mListFilterAction->setEnabled( true ); mListFilterAction->setText( i18n( "Filter on Mailing-List %1..." ).arg( lname ) ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotUndo() { mHeaders->undo(); updateMessageActions(); } //----------------------------------------------------------------------------- void KMMainWidget::slotToggleUnread() { mFolderTree->toggleColumn(KMFolderTree::unread); } //----------------------------------------------------------------------------- void KMMainWidget::slotToggleTotalColumn() { mFolderTree->toggleColumn(KMFolderTree::total, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotMoveMsg() { KMail::KMFolderSelDlg dlg( this, i18n("Move Message to Folder"), true ); KMFolder* dest; if (!dlg.exec()) return; if (!(dest = dlg.folder())) return; mHeaders->moveMsgToFolder(dest); } //----------------------------------------------------------------------------- void KMMainWidget::slotMoveMsgToFolder( KMFolder *dest) { mHeaders->moveMsgToFolder(dest); } //----------------------------------------------------------------------------- void KMMainWidget::slotCopyMsgToFolder( KMFolder *dest) { mHeaders->copyMsgToFolder(dest); } //----------------------------------------------------------------------------- void KMMainWidget::slotApplyFilters() { mHeaders->applyFiltersOnMsg(); } //----------------------------------------------------------------------------- void KMMainWidget::slotEditVacation() { if ( !kmkernel->askToGoOnline() ) { return; } if ( mVacation ) return; mVacation = new Vacation( this ); if ( mVacation->isUsable() ) { connect( mVacation, SIGNAL(result(bool)), mVacation, SLOT(deleteLater()) ); } else { QString msg = i18n("KMail's Out of Office Reply functionality relies on " "server-side filtering. You have not yet configured an " "IMAP server for this.\n" "You can do this on the \"Filtering\" tab of the IMAP " "account configuration."); KMessageBox::sorry( this, msg, i18n("No Server-Side Filtering Configured") ); delete mVacation; // QGuardedPtr sets itself to 0! } } //----------------------------------------------------------------------------- void KMMainWidget::slotDebugSieve() { #if !defined(NDEBUG) if ( mSieveDebugDialog ) return; mSieveDebugDialog = new SieveDebugDialog( this ); mSieveDebugDialog->exec(); delete mSieveDebugDialog; #endif } //----------------------------------------------------------------------------- void KMMainWidget::slotStartCertManager() { KProcess certManagerProc; // save to create on the heap, since // there is no parent certManagerProc << "kleopatra"; if( !certManagerProc.start( KProcess::DontCare ) ) KMessageBox::error( this, i18n( "Could not start certificate manager; " "please check your installation." ), i18n( "KMail Error" ) ); else kdDebug(5006) << "\nslotStartCertManager(): certificate manager started.\n" << endl; // process continues to run even after the KProcess object goes // out of scope here, since it is started in DontCare run mode. } //----------------------------------------------------------------------------- void KMMainWidget::slotStartWatchGnuPG() { KProcess certManagerProc; certManagerProc << "kwatchgnupg"; if( !certManagerProc.start( KProcess::DontCare ) ) KMessageBox::error( this, i18n( "Could not start GnuPG LogViewer (kwatchgnupg); " "please check your installation." ), i18n( "KMail Error" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotCopyMsg() { KMail::KMFolderSelDlg dlg( this, i18n("Copy Message to Folder"), true ); KMFolder* dest; if (!dlg.exec()) return; if (!(dest = dlg.folder())) return; mHeaders->copyMsgToFolder(dest); } //----------------------------------------------------------------------------- void KMMainWidget::slotPrintMsg() { bool htmlOverride = mMsgView ? mMsgView->htmlOverride() : false; bool htmlLoadExtOverride = mMsgView ? mMsgView->htmlLoadExtOverride() : false; KConfigGroup reader( KMKernel::config(), "Reader" ); bool useFixedFont = mMsgView ? mMsgView->isFixedFont() : reader.readBoolEntry( "useFixedFont", false ); KMCommand *command = new KMPrintCommand( this, mHeaders->currentMsg(), htmlOverride, htmlLoadExtOverride, useFixedFont, overrideEncoding() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotConfigChanged() { readConfig(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSaveMsg() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( this, *mHeaders->selectedMsgs() ); if (saveCommand->url().isEmpty()) delete saveCommand; else saveCommand->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotOpenMsg() { KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, 0, overrideEncoding() ); openCommand->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSaveAttachments() { KMMessage *msg = mHeaders->currentMsg(); if (!msg) return; KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( this, *mHeaders->selectedMsgs() ); saveCommand->start(); } void KMMainWidget::slotOnlineStatus() { if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) { // if online; then toggle and set it offline. - actionCollection()->action( "online_status" )->setText( i18n("Networkstate (offline)") ); + actionCollection()->action( "online_status" )->setText( i18n("Network State (offline)") ); kmkernel->stopNetworkJobs(); BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended")); } else { - actionCollection()->action( "online_status" )->setText( i18n("Networkstate (online)") ); + actionCollection()->action( "online_status" )->setText( i18n("Network State (online)") ); kmkernel->resumeNetworkJobs(); BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed")); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSendQueued() { if ( !kmkernel->askToGoOnline() ) { return; } kmkernel->msgSender()->sendQueued(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSendQueuedVia( int item ) { if ( !kmkernel->askToGoOnline() ) { return; } QStringList availTransports= KMail::TransportManager::transportNames(); QString customTransport = availTransports[ item ]; kmkernel->msgSender()->sendQueued( customTransport ); } //----------------------------------------------------------------------------- void KMMainWidget::slotViewChange() { if(mBodyPartsMenu->isItemChecked(mBodyPartsMenu->idAt(0))) { mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(0),FALSE); mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(1),TRUE); } else if(mBodyPartsMenu->isItemChecked(mBodyPartsMenu->idAt(1))) { mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(1),FALSE); mBodyPartsMenu->setItemChecked(mBodyPartsMenu->idAt(0),TRUE); } //mMsgView->setInline(!mMsgView->isInline()); } //----------------------------------------------------------------------------- void KMMainWidget::folderSelectedUnread( KMFolder* aFolder ) { folderSelected( aFolder, true ); slotChangeCaption( mFolderTree->currentItem() ); } //----------------------------------------------------------------------------- void KMMainWidget::folderSelected() { folderSelected( mFolder ); updateFolderMenu(); // opened() before the getAndCheckFolder() in folderSelected if ( mFolder && mFolder->folderType() == KMFolderTypeImap ) mFolder->close(); } //----------------------------------------------------------------------------- void KMMainWidget::folderSelected( KMFolder* aFolder, bool forceJumpToUnread ) { KCursorSaver busy(KBusyPtr::busy()); if (mMsgView) mMsgView->clear(true); if ( mFolder && mFolder->folderType() == KMFolderTypeImap && !mFolder->noContent() ) { KMFolderImap *imap = static_cast(mFolder->storage()); if ( mFolder->needsCompacting() && imap->autoExpunge() ) imap->expungeFolder(imap, TRUE); } // Re-enable the msg list and quicksearch if we're showing a splash // screen. This is true either if there's no active folder, or if we // have a timer that is no longer active (i.e. it has already fired) // To make the if() a bit more complicated, we suppress the hiding // when the new folder is also an IMAP folder, because that's an // async operation and we don't want flicker if it results in just // a new splash. bool newFolder = ( mFolder != aFolder ); bool isNewImapFolder = aFolder && aFolder->folderType() == KMFolderTypeImap && newFolder; if( !mFolder || ( !isNewImapFolder && mShowBusySplashTimer && !mShowBusySplashTimer->isActive() ) || ( newFolder && mShowingOfflineScreen && !( isNewImapFolder && kmkernel->isOffline() ) ) ) { if ( mMsgView ) { mMsgView->enableMsgDisplay(); mMsgView->clear( true ); } if( mSearchAndHeaders && mHeaders ) mSearchAndHeaders->show(); mShowingOfflineScreen = false; } // Delete any pending timer, if needed it will be recreated below delete mShowBusySplashTimer; mShowBusySplashTimer = 0; if ( newFolder ) writeFolderConfig(); if ( mFolder ) { disconnect( mFolder, SIGNAL( changed() ), this, SLOT( updateMarkAsReadAction() ) ); disconnect( mFolder, SIGNAL( msgHeaderChanged( KMFolder*, int ) ), this, SLOT( updateMarkAsReadAction() ) ); disconnect( mFolder, SIGNAL( msgAdded( int ) ), this, SLOT( updateMarkAsReadAction() ) ); disconnect( mFolder, SIGNAL( msgRemoved( KMFolder * ) ), this, SLOT( updateMarkAsReadAction() ) ); } mFolder = aFolder; if ( aFolder && aFolder->folderType() == KMFolderTypeImap ) { if ( kmkernel->isOffline() ) { showOfflinePage(); return; } KMFolderImap *imap = static_cast(aFolder->storage()); if ( newFolder && !mFolder->noContent() ) { imap->open(); // will be closed in the folderSelected slot // first get new headers before we select the folder imap->setSelected( true ); connect( imap, SIGNAL( folderComplete( KMFolderImap*, bool ) ), this, SLOT( folderSelected() ) ); imap->getAndCheckFolder(); mHeaders->setFolder( 0 ); updateFolderMenu(); mForceJumpToUnread = forceJumpToUnread; // Set a timer to show a splash screen if fetching folder contents // takes more than a second mShowBusySplashTimer = new QTimer( this ); connect( mShowBusySplashTimer, SIGNAL( timeout() ), this, SLOT( slotShowBusySplash() ) ); mShowBusySplashTimer->start( 1000, true ); return; } else { // the folder is complete now - so go ahead disconnect( imap, SIGNAL( folderComplete( KMFolderImap*, bool ) ), this, SLOT( folderSelected() ) ); forceJumpToUnread = mForceJumpToUnread; } } if ( mFolder ) { // == 0 -> pointing to toplevel ("Welcome to KMail") folder connect( mFolder, SIGNAL( changed() ), this, SLOT( updateMarkAsReadAction() ) ); connect( mFolder, SIGNAL( msgHeaderChanged( KMFolder*, int ) ), this, SLOT( updateMarkAsReadAction() ) ); connect( mFolder, SIGNAL( msgAdded( int ) ), this, SLOT( updateMarkAsReadAction() ) ); connect( mFolder, SIGNAL( msgRemoved(KMFolder *) ), this, SLOT( updateMarkAsReadAction() ) ); } readFolderConfig(); if (mMsgView) { mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); } mHeaders->setFolder( mFolder, forceJumpToUnread ); updateMessageActions(); updateFolderMenu(); if (!aFolder) slotIntro(); } //----------------------------------------------------------------------------- void KMMainWidget::slotShowBusySplash() { if ( mReaderWindowActive ) { mMsgView->displayBusyPage(); // hide widgets that are in the way: if ( mSearchAndHeaders && mHeaders && mLongFolderList ) mSearchAndHeaders->hide(); } } void KMMainWidget::showOfflinePage() { if ( !mReaderWindowActive ) return; mShowingOfflineScreen = true; mMsgView->displayOfflinePage(); // hide widgets that are in the way: if ( mSearchAndHeaders && mHeaders && mLongFolderList ) mSearchAndHeaders->hide(); } //----------------------------------------------------------------------------- void KMMainWidget::slotMsgSelected(KMMessage *msg) { if ( msg && msg->parent() && !msg->isComplete() ) { if ( msg->transferInProgress() ) return; mMsgView->clear(); mMsgView->setWaitingForSerNum( msg->getMsgSerNum() ); if ( mJob ) { disconnect( mJob, 0, mMsgView, 0 ); delete mJob; } mJob = msg->parent()->createJob( msg, FolderJob::tGetMessage, 0, "STRUCTURE", mMsgView->attachmentStrategy() ); connect(mJob, SIGNAL(messageRetrieved(KMMessage*)), mMsgView, SLOT(slotMessageArrived(KMMessage*))); mJob->start(); } else { mMsgView->setMsg(msg); } // reset HTML override to the folder setting mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); } //----------------------------------------------------------------------------- void KMMainWidget::slotMsgChanged() { mHeaders->msgChanged(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSelectFolder(KMFolder* folder) { QListViewItem* item = mFolderTree->indexOfFolder(folder); if ( item ) { mFolderTree->ensureItemVisible( item ); mFolderTree->doFolderSelected( item ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSelectMessage(KMMessage* msg) { int idx = mFolder->find(msg); if (idx != -1) { mHeaders->setCurrentMsg(idx); if (mMsgView) mMsgView->setMsg(msg); } } //----------------------------------------------------------------------------- void KMMainWidget::slotReplaceMsgByUnencryptedVersion() { kdDebug(5006) << "KMMainWidget::slotReplaceMsgByUnencryptedVersion()" << endl; KMMessage* oldMsg = mHeaders->currentMsg(); if( oldMsg ) { kdDebug(5006) << "KMMainWidget - old message found" << endl; if( oldMsg->hasUnencryptedMsg() ) { kdDebug(5006) << "KMMainWidget - extra unencrypted message found" << endl; KMMessage* newMsg = oldMsg->unencryptedMsg(); // adjust the message id { QString msgId( oldMsg->msgId() ); QString prefix("DecryptedMsg."); int oldIdx = msgId.find(prefix, 0, false); if( -1 == oldIdx ) { int leftAngle = msgId.findRev( '<' ); msgId = msgId.insert( (-1 == leftAngle) ? 0 : ++leftAngle, prefix ); } else { // toggle between "DecryptedMsg." and "DeCryptedMsg." // to avoid same message id QCharRef c = msgId[ oldIdx+2 ]; if( 'C' == c ) c = 'c'; else c = 'C'; } newMsg->setMsgId( msgId ); mMsgView->setIdOfLastViewedMessage( msgId ); } // insert the unencrypted message kdDebug(5006) << "KMMainWidget - adding unencrypted message to folder" << endl; mFolder->addMsg( newMsg ); /* Figure out its index in the folder for selecting. This must be count()-1, * since we append. Be safe and do find, though, just in case. */ int newMsgIdx = mFolder->find( newMsg ); Q_ASSERT( newMsgIdx != -1 ); /* we need this unget, to have the message displayed correctly initially */ mFolder->unGetMsg( newMsgIdx ); int idx = mFolder->find( oldMsg ); Q_ASSERT( idx != -1 ); /* only select here, so the old one is not un-Gotten before, which would * render the pointer we hold invalid so that find would fail */ mHeaders->setCurrentItemByIndex( newMsgIdx ); // remove the old one if ( idx != -1 ) { kdDebug(5006) << "KMMainWidget - deleting encrypted message" << endl; mFolder->take( idx ); } kdDebug(5006) << "KMMainWidget - updating message actions" << endl; updateMessageActions(); kdDebug(5006) << "KMMainWidget - done." << endl; } else kdDebug(5006) << "KMMainWidget - NO EXTRA UNENCRYPTED MESSAGE FOUND" << endl; } else kdDebug(5006) << "KMMainWidget - PANIC: NO OLD MESSAGE FOUND" << endl; } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusNew() { mHeaders->setMsgStatus(KMMsgStatusNew); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusUnread() { mHeaders->setMsgStatus(KMMsgStatusUnread); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusRead() { mHeaders->setMsgStatus(KMMsgStatusRead); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusFlag() { mHeaders->setMsgStatus(KMMsgStatusFlag, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusSpam() { mHeaders->setMsgStatus( KMMsgStatusSpam, true ); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusHam() { mHeaders->setMsgStatus( KMMsgStatusHam, true ); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusReplied() { mHeaders->setMsgStatus(KMMsgStatusReplied, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusForwarded() { mHeaders->setMsgStatus(KMMsgStatusForwarded, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusQueued() { mHeaders->setMsgStatus(KMMsgStatusQueued, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusTodo() { mHeaders->setMsgStatus(KMMsgStatusTodo, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetMsgStatusSent() { mHeaders->setMsgStatus(KMMsgStatusSent, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusNew() { mHeaders->setThreadStatus(KMMsgStatusNew); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusUnread() { mHeaders->setThreadStatus(KMMsgStatusUnread); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusFlag() { mHeaders->setThreadStatus(KMMsgStatusFlag, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusRead() { mHeaders->setThreadStatus(KMMsgStatusRead); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusReplied() { mHeaders->setThreadStatus(KMMsgStatusReplied, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusForwarded() { mHeaders->setThreadStatus(KMMsgStatusForwarded, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusQueued() { mHeaders->setThreadStatus(KMMsgStatusQueued, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusTodo() { mHeaders->setThreadStatus(KMMsgStatusTodo, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusSent() { mHeaders->setThreadStatus(KMMsgStatusSent, true); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusWatched() { mHeaders->setThreadStatus(KMMsgStatusWatched, true); if (mWatchThreadAction->isChecked()) { mIgnoreThreadAction->setChecked(false); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusIgnored() { mHeaders->setThreadStatus(KMMsgStatusIgnored, true); if (mIgnoreThreadAction->isChecked()) { mWatchThreadAction->setChecked(false); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusSpam() { mHeaders->setThreadStatus( KMMsgStatusSpam, true ); } //----------------------------------------------------------------------------- void KMMainWidget::slotSetThreadStatusHam() { mHeaders->setThreadStatus( KMMsgStatusHam, true ); } //----------------------------------------------------------------------------- void KMMainWidget::slotNextMessage() { mHeaders->nextMessage(); } void KMMainWidget::slotNextUnreadMessage() { if ( !mHeaders->nextUnreadMessage() ) if ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) mFolderTree->nextUnreadFolder(true); } void KMMainWidget::slotNextImportantMessage() { //mHeaders->nextImportantMessage(); } void KMMainWidget::slotPrevMessage() { mHeaders->prevMessage(); } void KMMainWidget::slotPrevUnreadMessage() { if ( !mHeaders->prevUnreadMessage() ) if ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) mFolderTree->prevUnreadFolder(); } void KMMainWidget::slotPrevImportantMessage() { //mHeaders->prevImportantMessage(); } void KMMainWidget::slotDisplayCurrentMessage() { if ( mHeaders->currentMsg() ) slotMsgActivated( mHeaders->currentMsg() ); } //----------------------------------------------------------------------------- //called from headers. Message must not be deleted on close void KMMainWidget::slotMsgActivated(KMMessage *msg) { if ( !msg ) return; if (msg->parent() && !msg->isComplete()) { FolderJob *job = msg->parent()->createJob(msg); connect(job, SIGNAL(messageRetrieved(KMMessage*)), SLOT(slotMsgActivated(KMMessage*))); job->start(); return; } if (kmkernel->folderIsDraftOrOutbox(mFolder)) { slotEditMsg(); return; } assert( msg != 0 ); KMReaderMainWin *win = new KMReaderMainWin( mFolderHtmlPref, mFolderHtmlLoadExtPref ); KConfigGroup reader( KMKernel::config(), "Reader" ); bool useFixedFont = mMsgView ? mMsgView->isFixedFont() : reader.readBoolEntry( "useFixedFont", false ); win->setUseFixedFont( useFixedFont ); KMMessage *newMessage = new KMMessage(*msg); newMessage->setParent( msg->parent() ); newMessage->setMsgSerNum( msg->getMsgSerNum() ); newMessage->setReadyToShow( true ); win->showMsg( overrideEncoding(), newMessage ); win->show(); } //----------------------------------------------------------------------------- void KMMainWidget::slotMarkAll() { mHeaders->selectAll( TRUE ); } //----------------------------------------------------------------------------- void KMMainWidget::slotMsgPopup(KMMessage&, const KURL &aUrl, const QPoint& aPoint) { KPopupMenu * menu = new KPopupMenu; updateMessageMenu(); mUrlCurrent = aUrl; bool urlMenuAdded = false; if (!aUrl.isEmpty()) { if (aUrl.protocol() == "mailto") { // popup on a mailto URL mMsgView->mailToComposeAction()->plug( menu ); mMsgView->mailToReplyAction()->plug( menu ); mMsgView->mailToForwardAction()->plug( menu ); menu->insertSeparator(); mMsgView->addAddrBookAction()->plug( menu ); mMsgView->openAddrBookAction()->plug( menu ); mMsgView->copyURLAction()->plug( menu ); mMsgView->startImChatAction()->plug( menu ); // only enable if our KIMProxy is functional mMsgView->startImChatAction()->setEnabled( kmkernel->imProxy()->initialize() ); } else { // popup on a not-mailto URL mMsgView->urlOpenAction()->plug( menu ); mMsgView->addBookmarksAction()->plug( menu ); mMsgView->urlSaveAsAction()->plug( menu ); mMsgView->copyURLAction()->plug( menu ); } if ( aUrl.protocol() == "im" ) { // popup on an IM address // no need to check the KIMProxy is initialized, as these protocols will // only be present if it is. mMsgView->startImChatAction()->plug( menu ); } urlMenuAdded=true; kdDebug( 0 ) << k_funcinfo << " URL is: " << aUrl << endl; } if(mMsgView && !mMsgView->copyText().isEmpty()) { if ( urlMenuAdded ) menu->insertSeparator(); mReplyActionMenu->plug(menu); menu->insertSeparator(); mMsgView->copyAction()->plug( menu ); mMsgView->selectAllAction()->plug( menu ); } else if ( !urlMenuAdded ) { // popup somewhere else (i.e., not a URL) on the message if (!mHeaders->currentMsg()) // no messages { delete menu; return; } if ( mFolder->isDrafts() || mFolder->isOutbox() ) { mEditAction->plug(menu); } else { if( !mFolder->isSent() ) mReplyActionMenu->plug(menu); mForwardActionMenu->plug(menu); } menu->insertSeparator(); mCopyActionMenu->plug( menu ); mMoveActionMenu->plug( menu ); menu->insertSeparator(); mStatusMenu->plug( menu ); menu->insertSeparator(); viewSourceAction()->plug(menu); if(mMsgView) { mMsgView->toggleFixFontAction()->plug(menu); } menu->insertSeparator(); mPrintAction->plug( menu ); mSaveAsAction->plug( menu ); mSaveAttachmentsAction->plug( menu ); menu->insertSeparator(); if( mFolder->isTrash() ) mDeleteAction->plug( menu ); else mTrashAction->plug( menu ); } KAcceleratorManager::manage(menu); menu->exec(aPoint, 0); delete menu; } //----------------------------------------------------------------------------- void KMMainWidget::getAccountMenu() { QStringList actList; mActMenu->clear(); actList = kmkernel->acctMgr()->getAccounts(); QStringList::Iterator it; int id = 0; for(it = actList.begin(); it != actList.end() ; ++it, id++) mActMenu->insertItem((*it).replace("&", "&&"), id); } //----------------------------------------------------------------------------- void KMMainWidget::getTransportMenu() { QStringList availTransports; mSendMenu->clear(); availTransports = KMail::TransportManager::transportNames(); QStringList::Iterator it; int id = 0; for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++) mSendMenu->insertItem((*it).replace("&", "&&"), id); } //----------------------------------------------------------------------------- void KMMainWidget::setupActions() { //----- File Menu mSaveAsAction = new KAction( i18n("Save &As..."), "filesave", KStdAccel::shortcut(KStdAccel::Save), this, SLOT(slotSaveMsg()), actionCollection(), "file_save_as" ); mOpenAction = KStdAction::open( this, SLOT( slotOpenMsg() ), actionCollection() ); (void) new KAction( i18n("&Compact All Folders"), 0, this, SLOT(slotCompactAll()), actionCollection(), "compact_all_folders" ); (void) new KAction( i18n("&Expire All Folders"), 0, this, SLOT(slotExpireAll()), actionCollection(), "expire_all_folders" ); (void) new KAction( i18n("&Refresh Local IMAP Cache"), "refresh", this, SLOT(slotInvalidateIMAPFolders()), actionCollection(), "file_invalidate_imap_cache" ); (void) new KAction( i18n("Empty All &Trash Folders"), 0, KMKernel::self(), SLOT(slotEmptyTrash()), actionCollection(), "empty_trash" ); (void) new KAction( i18n("Check &Mail"), "mail_get", CTRL+Key_L, this, SLOT(slotCheckMail()), actionCollection(), "check_mail" ); KActionMenu *actActionMenu = new KActionMenu( i18n("Check Mail &In"), "mail_get", actionCollection(), "check_mail_in" ); actActionMenu->setDelayed(true); //needed for checking "all accounts" connect(actActionMenu,SIGNAL(activated()),this,SLOT(slotCheckMail())); mActMenu = actActionMenu->popupMenu(); connect(mActMenu,SIGNAL(activated(int)),this,SLOT(slotCheckOneAccount(int))); connect(mActMenu,SIGNAL(aboutToShow()),this,SLOT(getAccountMenu())); (void) new KAction( i18n("&Send Queued Messages"), "mail_send", 0, this, SLOT(slotSendQueued()), actionCollection(), "send_queued"); (void) new KAction( i18n("Onlinestatus (unknown)"), "online_status", 0, this, SLOT(slotOnlineStatus()), actionCollection(), "online_status"); KActionMenu *sendActionMenu = new - KActionMenu( i18n("Send Queued Messages via"), "mail_send_via", actionCollection(), + KActionMenu( i18n("Send Queued Messages Via"), "mail_send_via", actionCollection(), "send_queued_via" ); sendActionMenu->setDelayed(true); mSendMenu = sendActionMenu->popupMenu(); connect(mSendMenu,SIGNAL(activated(int)), this, SLOT(slotSendQueuedVia(int))); connect(mSendMenu,SIGNAL(aboutToShow()),this,SLOT(getTransportMenu())); KAction *act; //----- Tools menu if (parent()->inherits("KMMainWin")) { act = new KAction( i18n("&Address Book..."), "contents", 0, this, SLOT(slotAddrBook()), actionCollection(), "addressbook" ); if (KStandardDirs::findExe("kaddressbook").isEmpty()) act->setEnabled(false); } act = new KAction( i18n("Certificate Manager..."), "pgp-keys", 0, this, SLOT(slotStartCertManager()), actionCollection(), "tools_start_certman"); // disable action if no certman binary is around if (KStandardDirs::findExe("kleopatra").isEmpty()) act->setEnabled(false); act = new KAction( i18n("GnuPG Log Viewer..."), "pgp-keys", 0, this, SLOT(slotStartWatchGnuPG()), actionCollection(), "tools_start_kwatchgnupg"); // disable action if no kwatchgnupg binary is around if (KStandardDirs::findExe("kwatchgnupg").isEmpty()) act->setEnabled(false); act = new KAction( i18n("&Import Messages..."), "fileopen", 0, this, SLOT(slotImport()), actionCollection(), "import" ); if (KStandardDirs::findExe("kmailcvt").isEmpty()) act->setEnabled(false); #if !defined(NDEBUG) (void) new KAction( i18n("&Debug Sieve..."), "idea", 0, this, SLOT(slotDebugSieve()), actionCollection(), "tools_debug_sieve" ); #endif // @TODO (marc/bo): Test (void) new KAction( i18n("Edit \"Out of Office\" Replies..."), "configure", 0, this, SLOT(slotEditVacation()), actionCollection(), "tools_edit_vacation" ); (void) new KAction( i18n("Filter &Log Viewer..."), 0, this, SLOT(slotFilterLogViewer()), actionCollection(), "filter_log_viewer" ); (void) new KAction( i18n("&Anti-Spam Wizard..."), 0, this, SLOT(slotAntiSpamWizard()), actionCollection(), "antiSpamWizard" ); (void) new KAction( i18n("&Anti-Virus Wizard..."), 0, this, SLOT(slotAntiVirusWizard()), actionCollection(), "antiVirusWizard" ); //----- Edit Menu mTrashAction = new KAction( KGuiItem( i18n("&Move to Trash"), "edittrash", i18n("Move message to trashcan") ), Key_Delete, this, SLOT(slotTrashMsg()), actionCollection(), "move_to_trash" ); /* The delete action is nowhere in the gui, by default, so we need to make * sure it is plugged into the KAccel now, since that won't happen on * XMLGui construction or manual ->plug(). This is only a problem when run * as a part, though. */ mDeleteAction = new KAction( i18n("&Delete"), "editdelete", SHIFT+Key_Delete, this, SLOT(slotDeleteMsg()), actionCollection(), "delete" ); mDeleteAction->plugAccel( actionCollection()->kaccel() ); mTrashThreadAction = new KAction( KGuiItem( i18n("M&ove Thread to Trash"), "edittrash", i18n("Move thread to trashcan") ), CTRL+Key_Delete, this, SLOT(slotTrashThread()), actionCollection(), "move_thread_to_trash" ); mDeleteThreadAction = new KAction( i18n("Delete T&hread"), "editdelete", CTRL+SHIFT+Key_Delete, this, SLOT(slotDeleteThread()), actionCollection(), "delete_thread" ); (void) new KAction( i18n("&Find Messages..."), "mail_find", Key_S, this, SLOT(slotSearch()), actionCollection(), "search_messages" ); mFindInMessageAction = new KAction( i18n("&Find in Message..."), "find", KStdAccel::shortcut(KStdAccel::Find), this, SLOT(slotFind()), actionCollection(), "find_in_messages" ); (void) new KAction( i18n("Select &All Messages"), KStdAccel::selectAll(), this, SLOT(slotMarkAll()), actionCollection(), "mark_all_messages" ); //----- Folder Menu (void) new KAction( i18n("&New Folder..."), "folder_new", 0, mFolderTree, SLOT(addChildFolder()), actionCollection(), "new_folder" ); mModifyFolderAction = new KAction( i18n("&Properties"), "configure", 0, this, SLOT(slotModifyFolder()), actionCollection(), "modify" ); mFolderMailingListPropertiesAction = new KAction( i18n("&Mailing List Management"), /*"folder_mailinglist_properties",*/ 0, this, SLOT( slotFolderMailingListProperties() ), actionCollection(), "folder_mailinglist_properties" ); mFolderShortCutCommandAction = new KAction( i18n("&Assign Shortcut..."), "configure_shortcuts", 0, this, SLOT( slotFolderShortcutCommand() ), actionCollection(), "folder_shortcut_command" ); mMarkAllAsReadAction = new KAction( i18n("Mark All Messages as &Read"), "goto", 0, this, SLOT(slotMarkAllAsRead()), actionCollection(), "mark_all_as_read" ); mExpireFolderAction = new KAction(i18n("&Expiration Settings"), 0, this, SLOT(slotExpireFolder()), actionCollection(), "expire"); mCompactFolderAction = new KAction( i18n("&Compact Folder"), 0, this, SLOT(slotCompactFolder()), actionCollection(), "compact" ); mRefreshFolderAction = new KAction( i18n("Check Mail &in This Folder"), "reload", KStdAccel::shortcut( KStdAccel::Reload ), this, SLOT(slotRefreshFolder()), actionCollection(), "refresh_folder" ); mTroubleshootFolderAction = 0; // set in initializeIMAPActions mEmptyFolderAction = new KAction( "foo", "edittrash", 0, this, SLOT(slotEmptyFolder()), actionCollection(), "empty" ); mRemoveFolderAction = new KAction( "foo", "editdelete", 0, this, SLOT(slotRemoveFolder()), actionCollection(), "delete_folder" ); mPreferHtmlAction = new KToggleAction( i18n("Prefer &HTML to Plain Text"), 0, this, SLOT(slotOverrideHtml()), actionCollection(), "prefer_html" ); mPreferHtmlLoadExtAction = new KToggleAction( i18n("Load E&xternal References"), 0, this, SLOT(slotOverrideHtmlLoadExt()), actionCollection(), "prefer_html_external_refs" ); mThreadMessagesAction = new KToggleAction( i18n("&Thread Messages"), 0, this, SLOT(slotOverrideThread()), actionCollection(), "thread_messages" ); mThreadBySubjectAction = new KToggleAction( i18n("Thread Messages also by &Subject"), 0, this, SLOT(slotToggleSubjectThreading()), actionCollection(), "thread_messages_by_subject" ); //----- Message Menu (void) new KAction( i18n("&New Message..."), "mail_new", KStdAccel::shortcut(KStdAccel::New), this, SLOT(slotCompose()), actionCollection(), "new_message" ); (void) new KAction( i18n("New Message t&o Mailing-List..."), "mail_post_to", CTRL+SHIFT+Key_N, this, SLOT(slotPostToML()), actionCollection(), "post_message" ); mForwardActionMenu = new KActionMenu( i18n("Message->","&Forward"), "mail_forward", actionCollection(), "message_forward" ); connect( mForwardActionMenu, SIGNAL(activated()), this, SLOT(slotForwardMsg()) ); mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."), "mail_forward", Key_F, this, SLOT(slotForwardAttachedMsg()), actionCollection(), "message_forward_as_attachment" ); mForwardActionMenu->insert( forwardAttachedAction() ); mForwardAction = new KAction( i18n("&Inline..."), "mail_forward", SHIFT+Key_F, this, SLOT(slotForwardMsg()), actionCollection(), "message_forward_inline" ); mForwardActionMenu->insert( forwardAction() ); mSendAgainAction = new KAction( i18n("Send A&gain..."), 0, this, SLOT(slotResendMsg()), actionCollection(), "send_again" ); mReplyActionMenu = new KActionMenu( i18n("Message->","&Reply"), "mail_reply", actionCollection(), "message_reply_menu" ); connect( mReplyActionMenu, SIGNAL(activated()), this, SLOT(slotReplyToMsg()) ); mReplyAction = new KAction( i18n("&Reply..."), "mail_reply", Key_R, this, SLOT(slotReplyToMsg()), actionCollection(), "reply" ); mReplyActionMenu->insert( mReplyAction ); mReplyAuthorAction = new KAction( i18n("Reply to A&uthor..."), "mail_reply", SHIFT+Key_A, this, SLOT(slotReplyAuthorToMsg()), actionCollection(), "reply_author" ); mReplyActionMenu->insert( mReplyAuthorAction ); mReplyAllAction = new KAction( i18n("Reply to &All..."), "mail_replyall", Key_A, this, SLOT(slotReplyAllToMsg()), actionCollection(), "reply_all" ); mReplyActionMenu->insert( mReplyAllAction ); mReplyListAction = new KAction( i18n("Reply to Mailing-&List..."), "mail_replylist", Key_L, this, SLOT(slotReplyListToMsg()), actionCollection(), "reply_list" ); mReplyActionMenu->insert( mReplyListAction ); mRedirectAction = new KAction( i18n("Message->Forward->","&Redirect..."), "mail_forward", Key_E, this, SLOT(slotRedirectMsg()), actionCollection(), "message_forward_redirect" ); mForwardActionMenu->insert( redirectAction() ); mNoQuoteReplyAction = new KAction( i18n("Reply Without &Quote..."), SHIFT+Key_R, this, SLOT(slotNoQuoteReplyToMsg()), actionCollection(), "noquotereply" ); //----- Create filter actions mFilterMenu = new KActionMenu( i18n("&Create Filter"), "filter", actionCollection(), "create_filter" ); connect( mFilterMenu, SIGNAL(activated()), this, SLOT(slotFilter()) ); mSubjectFilterAction = new KAction( i18n("Filter on &Subject..."), 0, this, SLOT(slotSubjectFilter()), actionCollection(), "subject_filter"); mFilterMenu->insert( mSubjectFilterAction ); mFromFilterAction = new KAction( i18n("Filter on &From..."), 0, this, SLOT(slotFromFilter()), actionCollection(), "from_filter"); mFilterMenu->insert( mFromFilterAction ); mToFilterAction = new KAction( i18n("Filter on &To..."), 0, this, SLOT(slotToFilter()), actionCollection(), "to_filter"); mFilterMenu->insert( mToFilterAction ); mListFilterAction = new KAction( i18n("Filter on Mailing-&List..."), 0, this, SLOT(slotMailingListFilter()), actionCollection(), "mlist_filter"); mFilterMenu->insert( mListFilterAction ); mPrintAction = KStdAction::print (this, SLOT(slotPrintMsg()), actionCollection()); mEditAction = new KAction( i18n("&Edit Message"), "edit", Key_T, this, SLOT(slotEditMsg()), actionCollection(), "edit" ); //----- "Mark Message" submenu mStatusMenu = new KActionMenu ( i18n( "Mar&k Message" ), actionCollection(), "set_status" ); mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &Read"), "kmmsgread", i18n("Mark selected messages as read")), 0, this, SLOT(slotSetMsgStatusRead()), actionCollection(), "status_read")); mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &New"), "kmmsgnew", i18n("Mark selected messages as new")), 0, this, SLOT(slotSetMsgStatusNew()), actionCollection(), "status_new" )); mStatusMenu->insert(new KAction(KGuiItem(i18n("Mark Message as &Unread"), "kmmsgunseen", i18n("Mark selected messages as unread")), 0, this, SLOT(slotSetMsgStatusUnread()), actionCollection(), "status_unread")); mStatusMenu->insert( new KActionSeparator( this ) ); // -------- Toggle Actions mToggleFlagAction = new KToggleAction(i18n("Mark Message as &Important"), "mail_flag", 0, this, SLOT(slotSetMsgStatusFlag()), actionCollection(), "status_flag"); mToggleFlagAction->setCheckedState( i18n("Remove &Important Message Mark") ); mStatusMenu->insert( mToggleFlagAction ); mToggleTodoAction = new KToggleAction(i18n("Mark Message as &To-do"), "mail_todo", 0, this, SLOT(slotSetMsgStatusTodo()), actionCollection(), "status_todo"); mToggleTodoAction->setCheckedState( i18n("Mark Message as Not &To-do") ); mStatusMenu->insert( mToggleTodoAction ); mToggleRepliedAction = new KToggleAction(i18n("Mark Message as Re&plied"), "kmmsgreplied", 0, this, SLOT(slotSetMsgStatusReplied()), actionCollection(), "status_replied"); mToggleRepliedAction->setCheckedState( i18n("Mark Message as Not Re&plied") ); mStatusMenu->insert( mToggleRepliedAction ); mToggleForwardedAction = new KToggleAction(i18n("Mark Message as &Forwarded"), "kmmsgforwarded", 0, this, SLOT(slotSetMsgStatusForwarded()), actionCollection(), "status_forwarded"); mToggleForwardedAction->setCheckedState( i18n("Mark Message as Not &Forwarded") ); mStatusMenu->insert( mToggleForwardedAction ); mToggleQueuedAction = new KToggleAction(i18n("Mark Message as &Queued"), "kmmsgqueued", 0, this, SLOT(slotSetMsgStatusQueued()), actionCollection(), "status_queued"); mToggleQueuedAction->setCheckedState( i18n("Mark Message as Not &Queued") ); mStatusMenu->insert( mToggleQueuedAction ); mToggleSentAction = new KToggleAction(i18n("Mark Message as &Sent"), "kmmsgsent", 0, this, SLOT(slotSetMsgStatusSent()), actionCollection(), "status_sent"); mToggleSentAction->setCheckedState( i18n("Mark Message as Not &Sent") ); mStatusMenu->insert( mToggleSentAction ); //----- "Mark Thread" submenu mThreadStatusMenu = new KActionMenu ( i18n( "Mark &Thread" ), actionCollection(), "thread_status" ); mMarkThreadAsReadAction = new KAction(KGuiItem(i18n("Mark Thread as &Read"), "kmmsgread", i18n("Mark all messages in the selected thread as read")), 0, this, SLOT(slotSetThreadStatusRead()), actionCollection(), "thread_read"); mThreadStatusMenu->insert( mMarkThreadAsReadAction ); mMarkThreadAsNewAction = new KAction(KGuiItem(i18n("Mark Thread as &New"), "kmmsgnew", i18n("Mark all messages in the selected thread as new")), 0, this, SLOT(slotSetThreadStatusNew()), actionCollection(), "thread_new"); mThreadStatusMenu->insert( mMarkThreadAsNewAction ); mMarkThreadAsUnreadAction = new KAction(KGuiItem(i18n("Mark Thread as &Unread"), "kmmsgunseen", i18n("Mark all messages in the selected thread as unread")), 0, this, SLOT(slotSetThreadStatusUnread()), actionCollection(), "thread_unread"); mThreadStatusMenu->insert( mMarkThreadAsUnreadAction ); mThreadStatusMenu->insert( new KActionSeparator( this ) ); //----- "Mark Thread" toggle actions mToggleThreadFlagAction = new KToggleAction(i18n("Mark Thread as &Important"), "mail_flag", 0, this, SLOT(slotSetThreadStatusFlag()), actionCollection(), "thread_flag"); mToggleThreadFlagAction->setCheckedState( i18n("Remove &Important Thread Mark") ); mThreadStatusMenu->insert( mToggleThreadFlagAction ); mToggleThreadTodoAction = new KToggleAction(i18n("Mark Thread as &To-do"), "mail_todo", 0, this, SLOT(slotSetThreadStatusTodo()), actionCollection(), "thread_todo"); mToggleThreadTodoAction->setCheckedState( i18n("Mark Thread as Not &To-do") ); mThreadStatusMenu->insert( mToggleThreadTodoAction ); mToggleThreadRepliedAction = new KToggleAction(i18n("Mark Thread as R&eplied"), "kmmsgreplied", 0, this, SLOT(slotSetThreadStatusReplied()), actionCollection(), "thread_replied"); mToggleThreadRepliedAction->setCheckedState( i18n("Mark Thread as Not R&eplied") ); mThreadStatusMenu->insert( mToggleThreadRepliedAction ); mToggleThreadForwardedAction = new KToggleAction(i18n("Mark Thread as &Forwarded"), "kmmsgforwarded", 0, this, SLOT(slotSetThreadStatusForwarded()), actionCollection(), "thread_forwarded"); mToggleThreadForwardedAction->setCheckedState( i18n("Mark Thread as Not &Forwarded") ); mThreadStatusMenu->insert( mToggleThreadForwardedAction ); mToggleThreadQueuedAction = new KToggleAction(i18n("Mark Thread as &Queued"), "kmmsgqueued", 0, this, SLOT(slotSetThreadStatusQueued()), actionCollection(), "thread_queued"); mToggleThreadQueuedAction->setCheckedState( i18n("Mark Thread as Not &Queued") ); mThreadStatusMenu->insert( mToggleThreadQueuedAction ); mToggleThreadSentAction = new KToggleAction(i18n("Mark Thread as &Sent"), "kmmsgsent", 0, this, SLOT(slotSetThreadStatusSent()), actionCollection(), "thread_sent"); mToggleThreadSentAction->setCheckedState( i18n("Mark Thread as Not &Sent") ); mThreadStatusMenu->insert( mToggleThreadSentAction ); mThreadStatusMenu->insert( new KActionSeparator( this ) ); //------- "Watch and ignore thread" actions mWatchThreadAction = new KToggleAction(i18n("&Watch Thread"), "kmmsgwatched", 0, this, SLOT(slotSetThreadStatusWatched()), actionCollection(), "thread_watched"); mIgnoreThreadAction = new KToggleAction(i18n("&Ignore Thread"), "mail_ignore", 0, this, SLOT(slotSetThreadStatusIgnored()), actionCollection(), "thread_ignored"); mSaveAttachmentsAction = new KAction( i18n("Save A&ttachments..."), "attach", 0, this, SLOT(slotSaveAttachments()), actionCollection(), "file_save_attachments" ); mMoveActionMenu = new KActionMenu( i18n("&Move To" ), actionCollection(), "move_to" ); mCopyActionMenu = new KActionMenu( i18n("&Copy To" ), actionCollection(), "copy_to" ); mApplyAllFiltersAction = new KAction( i18n("Appl&y All Filters"), "filter", CTRL+Key_J, this, SLOT(slotApplyFilters()), actionCollection(), "apply_filters" ); mApplyFilterActionsMenu = new KActionMenu( i18n("A&pply Filter" ), actionCollection(), "apply_filter_actions" ); //----- View Menu // Unread Submenu KActionMenu * unreadMenu = new KActionMenu( i18n("View->", "&Unread Count"), actionCollection(), "view_unread" ); unreadMenu->setToolTip( i18n("Choose how to display the count of unread messages") ); mUnreadColumnToggle = new KRadioAction( i18n("View->Unread Count", "View in &Separate Column"), 0, this, SLOT(slotToggleUnread()), actionCollection(), "view_unread_column" ); mUnreadColumnToggle->setExclusiveGroup( "view_unread_group" ); unreadMenu->insert( mUnreadColumnToggle ); mUnreadTextToggle = new KRadioAction( i18n("View->Unread Count", "View After &Folder Name"), 0, this, SLOT(slotToggleUnread()), actionCollection(), "view_unread_text" ); mUnreadTextToggle->setExclusiveGroup( "view_unread_group" ); unreadMenu->insert( mUnreadTextToggle ); // toggle for total column mTotalColumnToggle = new KToggleAction( i18n("View->", "&Total Column"), 0, this, SLOT(slotToggleTotalColumn()), actionCollection(), "view_columns_total" ); mTotalColumnToggle->setToolTip( i18n("Toggle display of column showing the " "total number of messages in folders.") ); (void)new KAction( KGuiItem( i18n("View->","&Expand Thread"), QString::null, i18n("Expand the current thread") ), Key_Period, this, SLOT(slotExpandThread()), actionCollection(), "expand_thread" ); (void)new KAction( KGuiItem( i18n("View->","&Collapse Thread"), QString::null, i18n("Collapse the current thread") ), Key_Comma, this, SLOT(slotCollapseThread()), actionCollection(), "collapse_thread" ); (void)new KAction( KGuiItem( i18n("View->","Ex&pand All Threads"), QString::null, i18n("Expand all threads in the current folder") ), CTRL+Key_Period, this, SLOT(slotExpandAllThreads()), actionCollection(), "expand_all_threads" ); (void)new KAction( KGuiItem( i18n("View->","C&ollapse All Threads"), QString::null, i18n("Collapse all threads in the current folder") ), CTRL+Key_Comma, this, SLOT(slotCollapseAllThreads()), actionCollection(), "collapse_all_threads" ); mViewSourceAction = new KAction( i18n("&View Source"), Key_V, this, SLOT(slotShowMsgSrc()), actionCollection(), "view_source" ); KAction* dukeOfMonmoth = new KAction( i18n("&Display Message"), Key_Return, this, SLOT( slotDisplayCurrentMessage() ), actionCollection(), "display_message" ); dukeOfMonmoth->plugAccel( actionCollection()->kaccel() ); //----- Go Menu new KAction( KGuiItem( i18n("&Next Message"), QString::null, i18n("Go to the next message") ), "N;Right", this, SLOT(slotNextMessage()), actionCollection(), "go_next_message" ); new KAction( KGuiItem( i18n("Next &Unread Message"), QApplication::reverseLayout() ? "previous" : "next", i18n("Go to the next unread message") ), Key_Plus, this, SLOT(slotNextUnreadMessage()), actionCollection(), "go_next_unread_message" ); /* ### needs better support from folders: new KAction( KGuiItem( i18n("Next &Important Message"), QString::null, i18n("Go to the next important message") ), 0, this, SLOT(slotNextImportantMessage()), actionCollection(), "go_next_important_message" ); */ new KAction( KGuiItem( i18n("&Previous Message"), QString::null, i18n("Go to the previous message") ), "P;Left", this, SLOT(slotPrevMessage()), actionCollection(), "go_prev_message" ); new KAction( KGuiItem( i18n("Previous Unread &Message"), QApplication::reverseLayout() ? "next" : "previous", i18n("Go to the previous unread message") ), Key_Minus, this, SLOT(slotPrevUnreadMessage()), actionCollection(), "go_prev_unread_message" ); /* needs better support from folders: new KAction( KGuiItem( i18n("Previous I&mportant Message"), QString::null, i18n("Go to the previous important message") ), 0, this, SLOT(slotPrevImportantMessage()), actionCollection(), "go_prev_important_message" ); */ KAction *action = new KAction( KGuiItem( i18n("Next Unread &Folder"), QString::null, i18n("Go to the next folder with unread messages") ), ALT+Key_Plus, this, SLOT(slotNextUnreadFolder()), actionCollection(), "go_next_unread_folder" ); KShortcut shortcut = action->shortcut(); shortcut.append( KKey( CTRL+Key_Plus ) ); action->setShortcut( shortcut ); action = new KAction( KGuiItem( i18n("Previous Unread F&older"), QString::null, i18n("Go to the previous folder with unread messages") ), ALT+Key_Minus, this, SLOT(slotPrevUnreadFolder()), actionCollection(), "go_prev_unread_folder" ); shortcut = action->shortcut(); shortcut.append( KKey( CTRL+Key_Minus ) ); action->setShortcut( shortcut ); new KAction( KGuiItem( i18n("Go->","Next Unread &Text"), QString::null, i18n("Go to the next unread text"), i18n("Scroll down current message. " "If at end of current message, " "go to next unread message.") ), Key_Space, this, SLOT(slotReadOn()), actionCollection(), "go_next_unread_text" ); //----- Settings Menu mToggleShowQuickSearchAction = new KToggleAction(i18n("Show Quick Search"), QString::null, 0, this, SLOT(slotToggleShowQuickSearch()), actionCollection(), "show_quick_search"); mToggleShowQuickSearchAction->setChecked( GlobalSettings::self()->quickSearchActive() ); mToggleShowQuickSearchAction->setWhatsThis( i18n( GlobalSettings::self()->quickSearchActiveItem()->whatsThis().utf8() ) ); (void) new KAction( i18n("Configure &Filters..."), 0, this, SLOT(slotFilter()), actionCollection(), "filter" ); (void) new KAction( i18n("Configure &POP Filters..."), 0, this, SLOT(slotPopFilter()), actionCollection(), "popFilter" ); (void) new KAction( i18n("Manage &Sieve Scripts..."), 0, this, SLOT(slotManageSieveScripts()), actionCollection(), "sieveFilters" ); (void) new KAction( KGuiItem( i18n("KMail &Introduction"), 0, i18n("Display KMail's Welcome Page") ), 0, this, SLOT(slotIntro()), actionCollection(), "help_kmail_welcomepage" ); // ----- Standard Actions // KStdAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection()); (void) new KAction( i18n("Configure &Notifications..."), "knotify", 0, this, SLOT(slotEditNotifications()), actionCollection(), "kmail_configure_notifications" ); // KStdAction::preferences(this, SLOT(slotSettings()), actionCollection()); (void) new KAction( i18n("&Configure KMail..."), "configure", 0, kmkernel, SLOT(slotShowConfigurationDialog()), actionCollection(), "kmail_configure_kmail" ); KStdAction::undo(this, SLOT(slotUndo()), actionCollection(), "kmail_undo"); KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() ); menutimer = new QTimer( this, "menutimer" ); connect( menutimer, SIGNAL( timeout() ), SLOT( updateMessageActions() ) ); connect( kmkernel->undoStack(), SIGNAL( undoStackChanged() ), this, SLOT( slotUpdateUndo() )); initializeIMAPActions( false ); // don't set state, config not read yet updateMessageActions(); } //----------------------------------------------------------------------------- void KMMainWidget::slotEditNotifications() { if(kmkernel->xmlGuiInstance()) KNotifyDialog::configure(this, 0, kmkernel->xmlGuiInstance()->aboutData()); else KNotifyDialog::configure(this); } void KMMainWidget::slotEditKeys() { KKeyDialog::configure( actionCollection(), true /*allow one-letter shortcuts*/ ); } //----------------------------------------------------------------------------- void KMMainWidget::slotReadOn() { if ( !mMsgView ) return; if ( !mMsgView->atBottom() ) { mMsgView->slotJumpDown(); return; } slotNextUnreadMessage(); } void KMMainWidget::slotNextUnreadFolder() { if ( !mFolderTree ) return; mFolderTree->nextUnreadFolder(); } void KMMainWidget::slotPrevUnreadFolder() { if ( !mFolderTree ) return; mFolderTree->prevUnreadFolder(); } void KMMainWidget::slotExpandThread() { mHeaders->slotExpandOrCollapseThread( true ); // expand } void KMMainWidget::slotCollapseThread() { mHeaders->slotExpandOrCollapseThread( false ); // collapse } void KMMainWidget::slotExpandAllThreads() { mHeaders->slotExpandOrCollapseAllThreads( true ); // expand } void KMMainWidget::slotCollapseAllThreads() { mHeaders->slotExpandOrCollapseAllThreads( false ); // collapse } //----------------------------------------------------------------------------- void KMMainWidget::slotShowMsgSrc() { KMMessage *msg = mHeaders->currentMsg(); if ( !msg ) return; KMCommand *command = new KMShowMsgSrcCommand( this, msg, mMsgView ? mMsgView->isFixedFont() : false ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::moveSelectedToFolder( int menuId ) { if (mMenuToFolder[menuId]) mHeaders->moveMsgToFolder( mMenuToFolder[menuId] ); } //----------------------------------------------------------------------------- void KMMainWidget::copySelectedToFolder(int menuId ) { if (mMenuToFolder[menuId]) mHeaders->copyMsgToFolder( mMenuToFolder[menuId] ); } //----------------------------------------------------------------------------- void KMMainWidget::updateMessageMenu() { mMenuToFolder.clear(); folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage, this, &mMenuToFolder, mMoveActionMenu->popupMenu() ); folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage, this, &mMenuToFolder, mCopyActionMenu->popupMenu() ); updateMessageActions(); } void KMMainWidget::startUpdateMessageActionsTimer() { menutimer->stop(); menutimer->start( 20, true ); } void KMMainWidget::updateMessageActions() { int count = 0; QPtrList selectedItems; if ( mFolder ) { for (QListViewItem *item = mHeaders->firstChild(); item; item = item->itemBelow()) if (item->isSelected() ) selectedItems.append(item); if ( selectedItems.isEmpty() && mFolder->count() ) // there will always be one in mMsgView count = 1; else count = selectedItems.count(); } updateListFilterAction(); bool allSelectedInCommonThread = false; if ( mHeaders->isThreaded() && count > 1 ) { allSelectedInCommonThread = true; QListViewItem * curItemParent = mHeaders->currentItem(); while ( curItemParent->parent() ) curItemParent = curItemParent->parent(); for ( QPtrListIterator it( selectedItems ) ; it.current() ; ++ it ) { QListViewItem * item = *it; while ( item->parent() ) item = item->parent(); if ( item != curItemParent ) { allSelectedInCommonThread = false; break; } } } else if ( mHeaders->isThreaded() && count == 1 ) { allSelectedInCommonThread = true; } bool mass_actions = count >= 1; bool thread_actions = mass_actions && allSelectedInCommonThread && mHeaders->isThreaded(); mStatusMenu->setEnabled( mass_actions ); mThreadStatusMenu->setEnabled( thread_actions ); // these need to be handled individually, the user might have them // in the toolbar mWatchThreadAction->setEnabled( thread_actions ); mIgnoreThreadAction->setEnabled( thread_actions ); mMarkThreadAsNewAction->setEnabled( thread_actions ); mMarkThreadAsReadAction->setEnabled( thread_actions ); mMarkThreadAsUnreadAction->setEnabled( thread_actions ); mToggleThreadRepliedAction->setEnabled( thread_actions ); mToggleThreadForwardedAction->setEnabled( thread_actions ); mToggleThreadQueuedAction->setEnabled( thread_actions ); mToggleThreadTodoAction->setEnabled( thread_actions ); mToggleThreadSentAction->setEnabled( thread_actions ); mToggleThreadFlagAction->setEnabled( thread_actions ); mTrashThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() ); mDeleteThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() ); if (mFolder && mHeaders && mHeaders->currentMsg()) { mToggleRepliedAction->setChecked(mHeaders->currentMsg()->isReplied()); mToggleForwardedAction->setChecked(mHeaders->currentMsg()->isForwarded()); mToggleQueuedAction->setChecked(mHeaders->currentMsg()->isQueued()); mToggleTodoAction->setChecked(mHeaders->currentMsg()->isTodo()); mToggleSentAction->setChecked(mHeaders->currentMsg()->isSent()); mToggleFlagAction->setChecked(mHeaders->currentMsg()->isImportant()); if (thread_actions) { mToggleThreadRepliedAction->setChecked(mHeaders->currentMsg()->isReplied()); mToggleThreadForwardedAction->setChecked(mHeaders->currentMsg()->isForwarded()); mToggleThreadQueuedAction->setChecked(mHeaders->currentMsg()->isQueued()); mToggleThreadTodoAction->setChecked(mHeaders->currentMsg()->isTodo()); mToggleThreadSentAction->setChecked(mHeaders->currentMsg()->isSent()); mToggleThreadFlagAction->setChecked(mHeaders->currentMsg()->isImportant()); mWatchThreadAction->setChecked( mHeaders->currentMsg()->isWatched()); mIgnoreThreadAction->setChecked( mHeaders->currentMsg()->isIgnored()); } } mMoveActionMenu->setEnabled( mass_actions && !mFolder->isReadOnly() ); mCopyActionMenu->setEnabled( mass_actions ); mTrashAction->setEnabled( mass_actions && !mFolder->isReadOnly() ); mDeleteAction->setEnabled( mass_actions && !mFolder->isReadOnly() ); mFindInMessageAction->setEnabled( mass_actions ); mForwardAction->setEnabled( mass_actions ); mForwardAttachedAction->setEnabled( mass_actions ); forwardMenu()->setEnabled( mass_actions ); bool single_actions = count == 1; mEditAction->setEnabled( single_actions && kmkernel->folderIsDraftOrOutbox(mFolder)); replyMenu()->setEnabled( single_actions ); filterMenu()->setEnabled( single_actions ); replyAction()->setEnabled( single_actions ); noQuoteReplyAction()->setEnabled( single_actions ); replyAuthorAction()->setEnabled( single_actions ); replyAllAction()->setEnabled( single_actions ); replyListAction()->setEnabled( single_actions ); redirectAction()->setEnabled( single_actions ); printAction()->setEnabled( single_actions ); viewSourceAction()->setEnabled( single_actions ); mSendAgainAction->setEnabled( single_actions && ( mHeaders->currentMsg() && mHeaders->currentMsg()->isSent() ) || ( mFolder && kmkernel->folderIsDraftOrOutbox( mFolder ) ) || ( mFolder && kmkernel->folderIsSentMailFolder( mFolder ) ) ); mSaveAsAction->setEnabled( mass_actions ); bool mails = mFolder && mFolder->count(); bool enable_goto_unread = mails || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders); actionCollection()->action( "go_next_message" )->setEnabled( mails ); actionCollection()->action( "go_next_unread_message" )->setEnabled( enable_goto_unread ); actionCollection()->action( "go_prev_message" )->setEnabled( mails ); actionCollection()->action( "go_prev_unread_message" )->setEnabled( enable_goto_unread ); actionCollection()->action( "send_queued" )->setEnabled( kmkernel->outboxFolder()->count() > 0 ); actionCollection()->action( "send_queued_via" )->setEnabled( kmkernel->outboxFolder()->count() > 0 ); if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) - actionCollection()->action( "online_status" )->setText( i18n("Networkstate (online)") ); + actionCollection()->action( "online_status" )->setText( i18n("Network State (online)") ); else - actionCollection()->action( "online_status" )->setText( i18n("Networkstate (offline)") ); + actionCollection()->action( "online_status" )->setText( i18n("Network State (offline)") ); if (action( "edit_undo" )) action( "edit_undo" )->setEnabled( mHeaders->canUndo() ); if ( count == 1 ) { KMMessage *msg; int aIdx; if((aIdx = mHeaders->currentItemIndex()) <= -1) return; if(!(msg = mFolder->getMsg(aIdx))) return; if (mFolder == kmkernel->outboxFolder()) mEditAction->setEnabled( !msg->transferInProgress() ); } mApplyAllFiltersAction->setEnabled(count); mApplyFilterActionsMenu->setEnabled(count); } // This needs to be updated more often, so it is in its method. void KMMainWidget::updateMarkAsReadAction() { mMarkAllAsReadAction->setEnabled( mFolder && (mFolder->countUnread() > 0) ); } //----------------------------------------------------------------------------- void KMMainWidget::updateFolderMenu() { bool folderWithContent = mFolder && !mFolder->noContent(); mModifyFolderAction->setEnabled( folderWithContent ); mFolderMailingListPropertiesAction->setEnabled( folderWithContent ); mCompactFolderAction->setEnabled( folderWithContent ); // This is the refresh-folder action in the menu. See kmfoldertree for the one in the RMB... bool imap = mFolder && mFolder->folderType() == KMFolderTypeImap; bool cachedImap = mFolder && mFolder->folderType() == KMFolderTypeCachedImap; // For dimap, check that the imap path is known before allowing "check mail in this folder". bool knownImapPath = cachedImap && !static_cast( mFolder->storage() )->imapPath().isEmpty(); mRefreshFolderAction->setEnabled( folderWithContent && ( imap || ( cachedImap && knownImapPath ) ) ); if ( mTroubleshootFolderAction ) mTroubleshootFolderAction->setEnabled( folderWithContent && ( cachedImap && knownImapPath ) ); mEmptyFolderAction->setEnabled( folderWithContent && ( mFolder->count() > 0 ) && !mFolder->isReadOnly() ); mEmptyFolderAction->setText( (mFolder && kmkernel->folderIsTrash(mFolder)) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash") ); mRemoveFolderAction->setEnabled( mFolder && !mFolder->isSystemFolder() && !mFolder->isReadOnly() ); if(mFolder) { mRemoveFolderAction->setText( mFolder->folderType() == KMFolderTypeSearch ? i18n("&Delete Search") : i18n("&Delete Folder") ); } mExpireFolderAction->setEnabled( mFolder && mFolder->isAutoExpire() ); updateMarkAsReadAction(); // the visual ones only make sense if we are showing a message list mPreferHtmlAction->setEnabled( mHeaders->folder() ? true : false ); mPreferHtmlLoadExtAction->setEnabled( mHeaders->folder() && (mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref) ? true : false ); mThreadMessagesAction->setEnabled( mHeaders->folder() ? true : false ); mPreferHtmlAction->setChecked( mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref ); mPreferHtmlLoadExtAction->setChecked( mHtmlLoadExtPref ? !mFolderHtmlLoadExtPref : mFolderHtmlLoadExtPref ); mThreadMessagesAction->setChecked( mThreadPref ? !mFolderThreadPref : mFolderThreadPref ); mThreadBySubjectAction->setEnabled( mHeaders->folder() ? ( mThreadMessagesAction->isChecked()) : false ); mThreadBySubjectAction->setChecked( mFolderThreadSubjPref ); } #ifdef MALLOC_DEBUG static QString fmt(long n) { char buf[32]; if(n > 1024*1024*1024) sprintf(buf, "%0.2f GB", ((double)n)/1024.0/1024.0/1024.0); else if(n > 1024*1024) sprintf(buf, "%0.2f MB", ((double)n)/1024.0/1024.0); else if(n > 1024) sprintf(buf, "%0.2f KB", ((double)n)/1024.0); else sprintf(buf, "%ld Byte", n); return QString(buf); } #endif void KMMainWidget::slotMemInfo() { #ifdef MALLOC_DEBUG struct mallinfo mi; mi = mallinfo(); QString s = QString("\nMALLOC - Info\n\n" "Number of mmapped regions : %1\n" "Memory allocated in use : %2\n" "Memory allocated, not used: %3\n" "Memory total allocated : %4\n" "Max. freeable memory : %5\n") .arg(mi.hblks).arg(fmt(mi.uordblks)).arg(fmt(mi.fordblks)) .arg(fmt(mi.arena)).arg(fmt(mi.keepcost)); KMessageBox::information(0, s, "Malloc information", s); #endif } //----------------------------------------------------------------------------- void KMMainWidget::slotIntro() { if ( !mMsgView ) return; mMsgView->clear( true ); // hide widgets that are in the way: if ( mSearchAndHeaders && mHeaders && mLongFolderList ) mSearchAndHeaders->hide(); mMsgView->displayAboutPage(); mFolder = 0; } void KMMainWidget::slotShowStartupFolder() { if ( mFolderTree ) { mFolderTree->reload(); mFolderTree->readConfig(); // get rid of old-folders mFolderTree->cleanupConfigFile(); } connect( kmkernel->filterMgr(), SIGNAL( filterListUpdated() ), this, SLOT( initializeFilterActions() )); // plug shortcut filter actions now initializeFilterActions(); // plug folder shortcut actions initializeFolderShortcutActions(); QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5(); if ( kmkernel->firstStart() || GlobalSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5 ) { GlobalSettings::self()->setPreviousNewFeaturesMD5( newFeaturesMD5 ); slotIntro(); return; } KMFolder* startup = 0; if ( !mStartupFolder.isEmpty() ) { // find the startup-folder startup = kmkernel->findFolderById( mStartupFolder ); } if ( !startup ) startup = kmkernel->inboxFolder(); if ( mFolderTree ) { mFolderTree->showFolder( startup ); } } void KMMainWidget::slotShowTip() { KTipDialog::showTip( this, QString::null, true ); } //----------------------------------------------------------------------------- void KMMainWidget::slotChangeCaption(QListViewItem * i) { if ( !i ) return; // set the caption to the current full path QStringList names; for ( QListViewItem * item = i ; item ; item = item->parent() ) names.prepend( item->text(0) ); emit captionChangeRequest( names.join( "/" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::removeDuplicates() { if (!mFolder) return; KMFolder *oFolder = mFolder; mHeaders->setFolder(0); QMap< QString, QValueList > idMD5s; QValueList redundantIds; QValueList::Iterator kt; mFolder->open(); for (int i = mFolder->count() - 1; i >= 0; --i) { QString id = (*mFolder)[i]->msgIdMD5(); if ( !id.isEmpty() ) { QString subjMD5 = (*mFolder)[i]->strippedSubjectMD5(); int other = -1; if ( idMD5s.contains(id) ) other = idMD5s[id].first(); else idMD5s[id].append( i ); if ( other != -1 ) { QString otherSubjMD5 = (*mFolder)[other]->strippedSubjectMD5(); if (otherSubjMD5 == subjMD5) idMD5s[id].append( i ); } } } QMap< QString, QValueList >::Iterator it; for ( it = idMD5s.begin(); it != idMD5s.end() ; ++it ) { QValueList::Iterator jt; bool finished = false; for ( jt = (*it).begin(); jt != (*it).end() && !finished; ++jt ) if (!((*mFolder)[*jt]->isUnread())) { (*it).remove( jt ); (*it).prepend( *jt ); finished = true; } for ( jt = (*it).begin(), ++jt; jt != (*it).end(); ++jt ) redundantIds.append( *jt ); } qHeapSort( redundantIds ); kt = redundantIds.end(); int numDuplicates = 0; if (kt != redundantIds.begin()) do { mFolder->removeMsg( *(--kt) ); ++numDuplicates; } while (kt != redundantIds.begin()); mFolder->close(); mHeaders->setFolder(oFolder); QString msg; if ( numDuplicates ) msg = i18n("Removed %n duplicate message.", "Removed %n duplicate messages.", numDuplicates ); else msg = i18n("No duplicate messages found."); BroadcastStatus::instance()->setStatusMsg( msg ); } //----------------------------------------------------------------------------- void KMMainWidget::slotUpdateUndo() { if (actionCollection()->action( "edit_undo" )) actionCollection()->action( "edit_undo" )->setEnabled( mHeaders->canUndo() ); } //----------------------------------------------------------------------------- void KMMainWidget::clearFilterActions() { if ( !mFilterTBarActions.isEmpty() ) { if ( mGUIClient->factory() ) mGUIClient->unplugActionList( "toolbar_filter_actions" ); mFilterTBarActions.clear(); } mApplyFilterActionsMenu->popupMenu()->clear(); if ( !mFilterMenuActions.isEmpty() ) { if ( mGUIClient->factory() ) mGUIClient->unplugActionList( "menu_filter_actions" ); mFilterMenuActions.clear(); } mFilterCommands.clear(); } //----------------------------------------------------------------------------- void KMMainWidget::initializeFolderShortcutActions() { // If we are loaded as a part, this will be set to fals, since the part // does xml loading. Temporarily set to true, in that case, so the // accels are added to the collection as expected. bool old = actionCollection()->isAutoConnectShortcuts(); actionCollection()->setAutoConnectShortcuts( true ); QValueList< QGuardedPtr< KMFolder > > folders = kmkernel->allFolders(); QValueList< QGuardedPtr< KMFolder > >::Iterator it = folders.begin(); while ( it != folders.end() ) { KMFolder *folder = (*it); ++it; slotShortcutChanged( folder ); // load the initial accel } actionCollection()->setAutoConnectShortcuts( old ); } //----------------------------------------------------------------------------- void KMMainWidget::initializeFilterActions() { QString filterName, normalizedName; KMMetaFilterActionCommand *filterCommand; KAction *filterAction = 0; clearFilterActions(); mApplyAllFiltersAction->plug(mApplyFilterActionsMenu->popupMenu()); bool addedSeparator = false; QValueListConstIterator it = kmkernel->filterMgr()->filters().constBegin(); for ( ;it != kmkernel->filterMgr()->filters().constEnd(); ++it ) { if (!(*it)->isEmpty() && (*it)->configureShortcut()) { filterName = QString("Filter %1").arg((*it)->name()); normalizedName = filterName.replace(" ", "_"); if (action(normalizedName.utf8())) continue; filterCommand = new KMMetaFilterActionCommand(*it, mHeaders, this); mFilterCommands.append(filterCommand); QString as = i18n("Filter %1").arg((*it)->name()); QString icon = (*it)->icon(); if ( icon.isEmpty() ) icon = "gear"; filterAction = new KAction(as, icon, (*it)->shortcut(), filterCommand, SLOT(start()), actionCollection(), normalizedName.local8Bit()); if(!addedSeparator) { mApplyFilterActionsMenu->popupMenu()->insertSeparator(); addedSeparator = !addedSeparator; } filterAction->plug( mApplyFilterActionsMenu->popupMenu() ); mFilterMenuActions.append(filterAction); if ( (*it)->configureToolbar() ) mFilterTBarActions.append(filterAction); } } if ( !mFilterMenuActions.isEmpty() && mGUIClient->factory() ) mGUIClient->plugActionList( "menu_filter_actions", mFilterMenuActions ); if ( !mFilterTBarActions.isEmpty() && mGUIClient->factory() ) { mFilterTBarActions.prepend( mToolbarActionSeparator ); mGUIClient->plugActionList( "toolbar_filter_actions", mFilterTBarActions ); } } void KMMainWidget::slotFolderRemoved( KMFolder *folder ) { mFolderShortcutCommands.remove( folder->idString() ); } //----------------------------------------------------------------------------- void KMMainWidget::initializeIMAPActions( bool setState /* false the first time, true later on */ ) { bool hasImapAccount = false; for( KMAccount *a = kmkernel->acctMgr()->first(); a; a = kmkernel->acctMgr()->next() ) { if ( a->type() == "cachedimap" ) { hasImapAccount = true; break; } } if ( hasImapAccount == ( mTroubleshootFolderAction != 0 ) ) return; // nothing to do KXMLGUIFactory* factory = mGUIClient->factory(); if ( factory ) factory->removeClient( mGUIClient ); if ( !mTroubleshootFolderAction ) { mTroubleshootFolderAction = new KAction( i18n("&Troubleshoot IMAP Cache..."), "wizard", 0, this, SLOT(slotTroubleshootFolder()), actionCollection(), "troubleshoot_folder" ); if ( setState ) updateFolderMenu(); // set initial state of the action } else { delete mTroubleshootFolderAction ; mTroubleshootFolderAction = 0; } if ( factory ) factory->addClient( mGUIClient ); } bool KMMainWidget::shortcutIsValid( const KShortcut &sc ) const { KActionPtrList actions = actionCollection()->actions(); KActionPtrList::Iterator it( actions.begin() ); for ( ; it != actions.end(); it++ ) { if ( (*it)->shortcut() == sc ) return false; } return true; } void KMMainWidget::slotShortcutChanged( KMFolder *folder ) { // remove the old one, autodelete mFolderShortcutCommands.remove( folder->idString() ); if ( folder->shortcut().isNull() ) return; FolderShortcutCommand *c = new FolderShortcutCommand( this, folder ); mFolderShortcutCommands.insert( folder->idString(), c ); QString actionlabel = QString( "FolderShortcut %1").arg( folder->prettyURL() ); QString actionname = QString( "FolderShortcut %1").arg( folder->idString() ); QString normalizedName = actionname.replace(" ", "_"); KAction* action = new KAction(actionlabel, folder->shortcut(), c, SLOT(start()), actionCollection(), normalizedName.local8Bit()); action->setIcon( folder->unreadIconPath() ); c->setAction( action ); // will be deleted along with the command } //----------------------------------------------------------------------------- void KMMainWidget::slotSubscriptionDialog() { if (!mFolder) return; if ( !kmkernel->askToGoOnline() ) { return; } ImapAccountBase* account; QString startPath; if (mFolder->folderType() == KMFolderTypeImap) { startPath = static_cast(mFolder->storage())->imapPath(); account = static_cast(mFolder->storage())->account(); } else if (mFolder->folderType() == KMFolderTypeCachedImap) { startPath = static_cast(mFolder->storage())->imapPath(); account = static_cast(mFolder->storage())->account(); } else return; if ( !account ) return; SubscriptionDialog *dialog = new SubscriptionDialog(this, i18n("Subscription"), account, startPath); // start a new listing if ( dialog->exec() ) { if (mFolder->folderType() == KMFolderTypeImap) static_cast(mFolder->storage())->account()->listDirectory(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotFolderTreeColumnsChanged() { mTotalColumnToggle->setChecked( mFolderTree->isTotalActive() ); mUnreadColumnToggle->setChecked( mFolderTree->isUnreadActive() ); } void KMMainWidget::toggleSystemTray() { if ( !mSystemTray && GlobalSettings::self()->systemTrayEnabled() ) { mSystemTray = new KMSystemTray(); } else if ( mSystemTray && !GlobalSettings::self()->systemTrayEnabled() ) { // Get rid of system tray on user's request kdDebug(5006) << "deleting systray" << endl; delete mSystemTray; mSystemTray = 0; } // Set mode of systemtray. If mode has changed, tray will handle this. if ( mSystemTray ) mSystemTray->setMode( GlobalSettings::self()->systemTrayPolicy() ); } //----------------------------------------------------------------------------- void KMMainWidget::slotAntiSpamWizard() { AntiSpamWizard wiz( AntiSpamWizard::AntiSpam, this, folderTree() ); wiz.exec(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAntiVirusWizard() { AntiSpamWizard wiz( AntiSpamWizard::AntiVirus, this, folderTree() ); wiz.exec(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFilterLogViewer() { FilterLogDialog * dlg = new FilterLogDialog( 0 ); dlg->show(); } //----------------------------------------------------------------------------- void KMMainWidget::updateFileMenu() { QStringList actList = kmkernel->acctMgr()->getAccounts(); actionCollection()->action("check_mail")->setEnabled( actList.size() > 0 ); actionCollection()->action("check_mail_in")->setEnabled( actList.size() > 0 ); } //----------------------------------------------------------------------------- void KMMainWidget::setAccelsEnabled( bool enabled ) { if ( mAccel ) mAccel->setEnabled( enabled ); } //----------------------------------------------------------------------------- KMSystemTray *KMMainWidget::systray() const { return mSystemTray; } //----------------------------------------------------------------------------- QString KMMainWidget::overrideEncoding() const { if ( mMsgView ) return mMsgView->overrideEncoding(); else return GlobalSettings::self()->overrideCharacterEncoding(); } diff --git a/kmail/kmsender.cpp b/kmail/kmsender.cpp index f639bfc85d..91f436d344 100644 --- a/kmail/kmsender.cpp +++ b/kmail/kmsender.cpp @@ -1,1165 +1,1165 @@ // kmsender.cpp #include #define REALLY_WANT_KMSENDER #include "kmsender.h" #include "kmsender_p.h" #undef REALLY_WANT_KMSENDER #include using namespace KMime::Types; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmfiltermgr.h" #include "kcursorsaver.h" #include #include #include "progressmanager.h" #include "kmaccount.h" #include "kmtransport.h" #include "kmfolderindex.h" #include "kmfoldermgr.h" #include "kmmsgdict.h" #include "kmmsgpart.h" #include "protocols.h" #include "kmcommands.h" #include #define SENDER_GROUP "sending mail" //----------------------------------------------------------------------------- KMSender::KMSender() : mOutboxFolder( 0 ), mSentFolder( 0 ) { mPrecommand = 0; mSendProc = 0; mSendProcStarted = FALSE; mSendInProgress = FALSE; mCurrentMsg = 0; mTransportInfo = new KMTransportInfo(); readConfig(); mSendAborted = false; mSentMessages = 0; mTotalMessages = 0; mFailedMessages = 0; mSentBytes = 0; mTotalBytes = 0; mProgressItem = 0; } //----------------------------------------------------------------------------- KMSender::~KMSender() { writeConfig(FALSE); delete mSendProc; delete mPrecommand; delete mTransportInfo; } //----------------------------------------------------------------------------- void KMSender::setStatusMsg(const QString &msg) { if ( mProgressItem ) mProgressItem->setStatus(msg); } //----------------------------------------------------------------------------- void KMSender::readConfig(void) { QString str; KConfigGroup config(KMKernel::config(), SENDER_GROUP); mSendImmediate = config.readBoolEntry("Immediate", TRUE); mSendQuotedPrintable = config.readBoolEntry("Quoted-Printable", TRUE); } //----------------------------------------------------------------------------- void KMSender::writeConfig(bool aWithSync) { KConfigGroup config(KMKernel::config(), SENDER_GROUP); config.writeEntry("Immediate", mSendImmediate); config.writeEntry("Quoted-Printable", mSendQuotedPrintable); if (aWithSync) config.sync(); } //----------------------------------------------------------------------------- bool KMSender::settingsOk() const { if (KMTransportInfo::availableTransports().isEmpty()) { KMessageBox::information(0,i18n("Please create an account for sending and try again.")); return false; } return true; } static void handleRedirections( KMMessage * m ) { const QString from = m->headerField("X-KMail-Redirect-From"); const QString msgId = m->msgId(); if( from.isEmpty() || msgId.isEmpty() ) m->setMsgId( KMMessage::generateMessageId( m->sender() ) ); } //----------------------------------------------------------------------------- bool KMSender::doSend(KMMessage* aMsg, short sendNow) { if(!aMsg) return false; if (!settingsOk()) return FALSE; if (aMsg->to().isEmpty()) { // RFC822 says: // Note that the "Bcc" field may be empty, while the "To" field is required to // have at least one address. // // however: // // The following string is accepted according to RFC 2822, // section 3.4 "Address Specification" where they say: // // "An address may either be an individual mailbox, // or a group of mailboxes." // and: // "group + display-name ":" [mailbox-list / CFWS] ";" // [CFWS]" // // In this syntax our "undisclosed-recipients: ;" // just specifies an empty group. // // In further explanations RFC 2822 states that it *is* // allowed to have a ZERO number of mailboxes in the "mailbox-list". aMsg->setTo("Undisclosed.Recipients: ;"); } handleRedirections( aMsg ); if (sendNow==-1) sendNow = mSendImmediate; kmkernel->outboxFolder()->open(); const KMFolderCloser openOutbox( kmkernel->outboxFolder() ); aMsg->setStatus(KMMsgStatusQueued); if ( const int err = openOutbox.folder()->addMsg(aMsg) ) { Q_UNUSED( err ); KMessageBox::information(0,i18n("Cannot add message to outbox folder")); return false; } //Ensure the message is correctly and fully parsed openOutbox.folder()->unGetMsg( openOutbox.folder()->count() - 1 ); if ( !sendNow || mSendInProgress ) return true; return sendQueued(); } //----------------------------------------------------------------------------- void KMSender::outboxMsgAdded(int idx) { ++mTotalMessages; KMMsgBase* msg = kmkernel->outboxFolder()->getMsgBase(idx); Q_ASSERT(msg); if ( msg ) mTotalBytes += msg->msgSize(); } //----------------------------------------------------------------------------- bool KMSender::doSendQueued( const QString &customTransport ) { if (!settingsOk()) return FALSE; if (mSendInProgress) { return FALSE; } // open necessary folders mOutboxFolder = kmkernel->outboxFolder(); mOutboxFolder->open(); mTotalMessages = mOutboxFolder->count(); if (mTotalMessages == 0) { // Nothing in the outbox. We are done. mOutboxFolder->close(); mOutboxFolder = 0; return TRUE; } mTotalBytes = 0; for( int i = 0 ; igetMsgBase(i)->msgSize(); connect( mOutboxFolder, SIGNAL(msgAdded(int)), this, SLOT(outboxMsgAdded(int)) ); mCurrentMsg = 0; mSentFolder = kmkernel->sentFolder(); mSentFolder->open(); kmkernel->filterMgr()->ref(); // start sending the messages mCustomTransport = customTransport; doSendMsg(); return TRUE; } //----------------------------------------------------------------------------- void KMSender::emitProgressInfo( int currentFileProgress ) { int percent = (mTotalBytes) ? ( 100 * (mSentBytes+currentFileProgress) / mTotalBytes ) : 0; if (percent > 100) percent = 100; mProgressItem->setProgress(percent); } //----------------------------------------------------------------------------- void KMSender::doSendMsg() { if (!kmkernel) //To handle message sending in progress when kaplan is exited return; //TODO: handle this case better const bool someSent = mCurrentMsg; if (someSent) { mSentMessages++; mSentBytes += mCurrentMsg->msgSize(); } // Post-process sent message (filtering) KMFolder *sentFolder = 0, *imapSentFolder = 0; if (mCurrentMsg && kmkernel->filterMgr()) { mCurrentMsg->setTransferInProgress( FALSE ); if( mCurrentMsg->hasUnencryptedMsg() ) { kdDebug(5006) << "KMSender::doSendMsg() post-processing: replace mCurrentMsg body by unencryptedMsg data" << endl; // delete all current body parts mCurrentMsg->deleteBodyParts(); // copy Content-[..] headers from unencrypted message to current one KMMessage & newMsg( *mCurrentMsg->unencryptedMsg() ); mCurrentMsg->dwContentType() = newMsg.dwContentType(); mCurrentMsg->setContentTransferEncodingStr( newMsg.contentTransferEncodingStr() ); QCString newDispo = newMsg.headerField("Content-Disposition").latin1(); if( newDispo.isEmpty() ) mCurrentMsg->removeHeaderField( "Content-Disposition" ); else mCurrentMsg->setHeaderField( "Content-Disposition", newDispo ); // copy the body mCurrentMsg->setBody( newMsg.body() ); // copy all the body parts KMMessagePart msgPart; for( int i = 0; i < newMsg.numBodyParts(); ++i ) { newMsg.bodyPart( i, &msgPart ); mCurrentMsg->addBodyPart( &msgPart ); } } mCurrentMsg->setStatus(KMMsgStatusSent); mCurrentMsg->setStatus(KMMsgStatusRead); // otherwise it defaults to new on imap mCurrentMsg->updateAttachmentState(); const KPIM::Identity & id = kmkernel->identityManager() ->identityForUoidOrDefault( mCurrentMsg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() ); if ( !mCurrentMsg->fcc().isEmpty() ) { sentFolder = kmkernel->folderMgr()->findIdString( mCurrentMsg->fcc() ); if ( sentFolder == 0 ) // This is *NOT* supposed to be imapSentFolder! sentFolder = kmkernel->dimapFolderMgr()->findIdString( mCurrentMsg->fcc() ); if ( sentFolder == 0 ) imapSentFolder = kmkernel->imapFolderMgr()->findIdString( mCurrentMsg->fcc() ); } // No, or no usable sentFolder, and no, or no usable imapSentFolder, // let's try the on in the identity if ( ( sentFolder == 0 || sentFolder->isReadOnly() ) && ( imapSentFolder == 0 || imapSentFolder->isReadOnly() ) && !id.fcc().isEmpty() ) { sentFolder = kmkernel->folderMgr()->findIdString( id.fcc() ); if ( sentFolder == 0 ) // This is *NOT* supposed to be imapSentFolder! sentFolder = kmkernel->dimapFolderMgr()->findIdString( id.fcc() ); if ( sentFolder == 0 ) imapSentFolder = kmkernel->imapFolderMgr()->findIdString( id.fcc() ); } if (imapSentFolder && ( imapSentFolder->noContent() || imapSentFolder->isReadOnly() ) ) imapSentFolder = 0; if ( sentFolder == 0 || sentFolder->isReadOnly() ) sentFolder = kmkernel->sentFolder(); if ( sentFolder ) { if ( const int err = sentFolder->open() ) { Q_UNUSED( err ); cleanup(); return; } } // Disable the emitting of msgAdded signal, because the message is taken out of the // current folder (outbox) and re-added, to make filter actions changing the message // work. We don't want that to screw up message counts. if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet( true ); const int processResult = kmkernel->filterMgr()->process(mCurrentMsg,KMFilterMgr::Outbound); if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet( false ); // 0==processed ok, 1==no filter matched, 2==critical error, abort! switch (processResult) { case 2: perror("Critical error: Unable to process sent mail (out of space?)"); KMessageBox::information(0, i18n("Critical error: " "Unable to process sent mail (out of space?)" "Moving failing message to \"sent-mail\" folder.")); sentFolder->moveMsg(mCurrentMsg); sentFolder->close(); cleanup(); return; case 1: if (sentFolder->moveMsg(mCurrentMsg) != 0) { KMessageBox::error(0, i18n("Moving the sent message \"%1\" from the " "\"outbox\" to the \"sent-mail\" folder failed.\n" "Possible reasons are lack of disk space or write permission. " "Please try to fix the problem and move the message manually.") .arg(mCurrentMsg->subject())); cleanup(); return; } if (imapSentFolder) { // Does proper folder refcounting and message locking KMCommand *command = new KMMoveCommand( imapSentFolder, mCurrentMsg ); command->keepFolderOpen( sentFolder ); // will open it, and close it once done command->start(); } default: break; } setStatusByLink( mCurrentMsg ); if (mCurrentMsg->parent() && !imapSentFolder) { // for speed optimization, this code assumes that mCurrentMsg is the // last one in it's parent folder; make sure that's really the case: assert( mCurrentMsg->parent()->find( mCurrentMsg ) == mCurrentMsg->parent()->count() - 1 ); // unGet this message: mCurrentMsg->parent()->unGetMsg( mCurrentMsg->parent()->count() -1 ); } mCurrentMsg = 0; } // See if there is another queued message mCurrentMsg = mOutboxFolder->getMsg(mFailedMessages); if ( mCurrentMsg && !mCurrentMsg->transferInProgress() && mCurrentMsg->sender().isEmpty() ) { // if we do not have a sender address then use the email address of the // message's identity or of the default identity unless those two are also // empty const KPIM::Identity & id = kmkernel->identityManager() ->identityForUoidOrDefault( mCurrentMsg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() ); if ( !id.emailAddr().isEmpty() ) { mCurrentMsg->setFrom( id.fullEmailAddr() ); } else if ( !kmkernel->identityManager()->defaultIdentity().emailAddr().isEmpty() ) { mCurrentMsg->setFrom( kmkernel->identityManager()->defaultIdentity().fullEmailAddr() ); } else { KMessageBox::sorry( 0, i18n( "It's not possible to send messages " "without specifying a sender address.\n" "Please set the email address of " "identity '%1' in the Identities " "section of the configuration dialog " "and then try again." ) .arg( id.identityName() ) ); mOutboxFolder->unGetMsg( mFailedMessages ); mCurrentMsg = 0; } } if (!mCurrentMsg || mCurrentMsg->transferInProgress()) { // a message is locked finish the send if (mCurrentMsg && mCurrentMsg->transferInProgress()) mCurrentMsg = 0; // no more message: cleanup and done if ( sentFolder != 0 ) sentFolder->close(); if ( someSent ) { if ( mSentMessages == mTotalMessages ) { setStatusMsg(i18n("%n queued message successfully sent.", "%n queued messages successfully sent.", mSentMessages)); } else { setStatusMsg(i18n("%1 of %2 queued messages successfully sent.") .arg(mSentMessages).arg( mTotalMessages )); } } cleanup(); return; } mCurrentMsg->setTransferInProgress( TRUE ); // start the sender process or initialize communication if (!mSendInProgress) { Q_ASSERT( !mProgressItem ); mProgressItem = KPIM::ProgressManager::createProgressItem( "Sender", i18n( "Sending messages" ), i18n("Initiating sender process..."), true ); connect( mProgressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), this, SLOT( slotAbortSend() ) ); kapp->ref(); mSendInProgress = TRUE; } QString msgTransport = mCustomTransport; if ( msgTransport.isEmpty() ) { msgTransport = mCurrentMsg->headerField("X-KMail-Transport"); } if ( msgTransport.isEmpty() ) { const QStringList sl = KMTransportInfo::availableTransports(); if (!sl.empty()) msgTransport = sl.front(); } if (!mSendProc || msgTransport != mMethodStr) { if (mSendProcStarted && mSendProc) { mSendProc->finish(); mSendProcStarted = FALSE; } mSendProc = createSendProcFromString(msgTransport); mMethodStr = msgTransport; if( mTransportInfo->encryption == "TLS" || mTransportInfo->encryption == "SSL" ) { mProgressItem->setUsesCrypto( true ); } else if ( !mCustomTransport.isEmpty() ) { int result = KMessageBox::warningContinueCancel( 0, i18n( "You have chosen to send all queued email using an unencrypted transport, do you want to continue? "), i18n( "Security Warning" ), - i18n( "Send unencrypted" ), + i18n( "Send Unencrypted" ), "useCustomTransportWithoutAsking", false); if( result == KMessageBox::Cancel ) { mProgressItem->cancel(); mProgressItem->setComplete(); slotAbortSend(); cleanup(); return; } } if (!mSendProc) sendProcStarted(false); else { connect(mSendProc, SIGNAL(idle()), SLOT(slotIdle())); connect(mSendProc, SIGNAL(started(bool)), SLOT(sendProcStarted(bool))); // Run the precommand if there is one if ( !mTransportInfo->precommand.isEmpty() ) { runPrecommand( mTransportInfo->precommand ); return; } mSendProc->start(); } } else if (!mSendProcStarted) mSendProc->start(); else doSendMsgAux(); } bool KMSender::runPrecommand( const QString & cmd ) { setStatusMsg( i18n("Executing precommand %1").arg( cmd ) ); mPrecommand = new KMPrecommand( cmd ); connect( mPrecommand, SIGNAL(finished(bool)), SLOT(slotPrecommandFinished(bool)) ); if ( !mPrecommand->start() ) { delete mPrecommand; mPrecommand = 0; return false; } return true; } //----------------------------------------------------------------------------- void KMSender::sendProcStarted(bool success) { if (!success) { if (mSendProc) mSendProc->finish(); else setStatusMsg(i18n("Unrecognized transport protocol. Unable to send message.")); mSendProc = 0; mSendProcStarted = false; cleanup(); return; } doSendMsgAux(); } static QStringList addrSpecListToStringList( const AddrSpecList & l, bool allowEmpty=false ) { QStringList result; for ( AddrSpecList::const_iterator it = l.begin(), end = l.end() ; it != end ; ++it ) { const QString s = (*it).asString(); if ( allowEmpty || !s.isEmpty() ) result.push_back( s ); } return result; } static void extractSenderToCCAndBcc( KMMessage * aMsg, QString * sender, QStringList * to, QStringList * cc, QStringList * bcc ) { if ( sender ) *sender = aMsg->sender(); if( !aMsg->headerField("X-KMail-Recipients").isEmpty() ) { // extended BCC handling to prevent TOs and CCs from seeing // BBC information by looking at source of an OpenPGP encrypted mail if ( to ) *to = addrSpecListToStringList( aMsg->extractAddrSpecs( "X-KMail-Recipients" ) ); aMsg->removeHeaderField( "X-KMail-Recipients" ); } else { if ( to ) *to = addrSpecListToStringList( aMsg->extractAddrSpecs( "To" ) ); if ( cc ) *cc = addrSpecListToStringList( aMsg->extractAddrSpecs( "Cc" ) ); if ( bcc ) *bcc = addrSpecListToStringList( aMsg->extractAddrSpecs( "Bcc" ) ); } } //----------------------------------------------------------------------------- void KMSender::doSendMsgAux() { mSendProcStarted = TRUE; // start sending the current message setStatusMsg(i18n("%3: subject of message","Sending message %1 of %2: %3") .arg(mSentMessages+mFailedMessages+1).arg(mTotalMessages) .arg(mCurrentMsg->subject())); QStringList to, cc, bcc; QString sender; extractSenderToCCAndBcc( mCurrentMsg, &sender, &to, &cc, &bcc ); const QCString message = mCurrentMsg->asSendableString(); if ( sender.isEmpty() || !mSendProc->send( sender, to, cc, bcc, message ) ) { mCurrentMsg->setTransferInProgress( false ); mOutboxFolder->unGetMsg( mFailedMessages ); mCurrentMsg = 0; cleanup(); setStatusMsg(i18n("Failed to send (some) queued messages.")); return; } // Do *not* add code here, after send(). It can happen that this method // is called recursively if send() emits the idle signal directly. } //----------------------------------------------------------------------------- void KMSender::cleanup(void) { kdDebug(5006) << k_funcinfo << endl; if (mSendProc && mSendProcStarted) mSendProc->finish(); mSendProc = 0; mSendProcStarted = FALSE; if (mSendInProgress) kapp->deref(); mSendInProgress = FALSE; if (mCurrentMsg) { mCurrentMsg->setTransferInProgress( FALSE ); mCurrentMsg = 0; } if ( mSentFolder ) { mSentFolder->close(); mSentFolder = 0; } if ( mOutboxFolder ) { disconnect( mOutboxFolder, SIGNAL(msgAdded(int)), this, SLOT(outboxMsgAdded(int)) ); mOutboxFolder->close(); if ( mOutboxFolder->count( true ) == 0 ) { mOutboxFolder->expunge(); } else if ( mOutboxFolder->needsCompacting() ) { mOutboxFolder->compact( KMFolder::CompactSilentlyNow ); } mOutboxFolder = 0; } mSendAborted = false; mSentMessages = 0; mFailedMessages = 0; mSentBytes = 0; if ( mProgressItem ) mProgressItem->setComplete(); mProgressItem = 0; kmkernel->filterMgr()->deref(); } //----------------------------------------------------------------------------- void KMSender::slotAbortSend() { mSendAborted = true; delete mPrecommand; mPrecommand = 0; if (mSendProc) mSendProc->abort(); } //----------------------------------------------------------------------------- void KMSender::slotIdle() { assert(mSendProc != 0); QString msg; QString errString; if (mSendProc) errString = mSendProc->lastErrorMessage(); if (mSendAborted) { // sending of message aborted if ( mCurrentMsg ) { mCurrentMsg->setTransferInProgress( false ); mOutboxFolder->unGetMsg( mFailedMessages ); mCurrentMsg = 0; } msg = i18n("Sending aborted:\n%1\n" "The message will stay in the 'outbox' folder until you either " "fix the problem (e.g. a broken address) or remove the message " "from the 'outbox' folder.\n" "The following transport protocol was used:\n %2") .arg(errString) .arg(mMethodStr); if (!errString.isEmpty()) KMessageBox::error(0,msg); setStatusMsg( i18n( "Sending aborted." ) ); } else { if (!mSendProc->sendOk()) { mCurrentMsg->setTransferInProgress( false ); mOutboxFolder->unGetMsg( mFailedMessages ); mCurrentMsg = 0; mFailedMessages++; // Sending of message failed. if (!errString.isEmpty()) { int res = KMessageBox::Yes; if (mSentMessages+mFailedMessages != mTotalMessages) { msg = i18n("

Sending failed:

" "

%1

" "

The message will stay in the 'outbox' folder until you either " "fix the problem (e.g. a broken address) or remove the message " "from the 'outbox' folder.

" "

The following transport protocol was used: %2

" "

Do you want me to continue sending the remaining messages?

") .arg(errString) .arg(mMethodStr); res = KMessageBox::warningYesNo( 0 , msg , i18n( "Continue Sending" ), i18n( "&Continue Sending" ), i18n("&Abort Sending") ); } else { msg = i18n("Sending failed:\n%1\n" "The message will stay in the 'outbox' folder until you either " "fix the problem (e.g. a broken address) or remove the message " "from the 'outbox' folder.\n" "The following transport protocol was used:\n %2") .arg(errString) .arg(mMethodStr); KMessageBox::error(0,msg); } if (res == KMessageBox::Yes) { // Try the next one. doSendMsg(); return; } else { setStatusMsg( i18n( "Sending aborted." ) ); } } } else { // Sending suceeded. doSendMsg(); return; } } mSendProc->finish(); mSendProc = 0; mSendProcStarted = false; cleanup(); } //----------------------------------------------------------------------------- void KMSender::slotPrecommandFinished(bool normalExit) { delete mPrecommand; mPrecommand = 0; if (normalExit) mSendProc->start(); else slotIdle(); } //----------------------------------------------------------------------------- void KMSender::setSendImmediate(bool aSendImmediate) { mSendImmediate = aSendImmediate; } //----------------------------------------------------------------------------- void KMSender::setSendQuotedPrintable(bool aSendQuotedPrintable) { mSendQuotedPrintable = aSendQuotedPrintable; } //----------------------------------------------------------------------------- KMSendProc* KMSender::createSendProcFromString( const QString & transport ) { mTransportInfo->type = QString::null; int nr = KMTransportInfo::findTransport(transport); if (nr) { mTransportInfo->readConfig(nr); } else { if (transport.startsWith("smtp://")) // should probably use KURL and SMTP_PROTOCOL { mTransportInfo->type = "smtp"; mTransportInfo->auth = FALSE; mTransportInfo->encryption = "NONE"; QString serverport = transport.mid(7); int colon = serverport.find(':'); if (colon != -1) { mTransportInfo->host = serverport.left(colon); mTransportInfo->port = serverport.mid(colon + 1); } else { mTransportInfo->host = serverport; mTransportInfo->port = "25"; } } else if (transport.startsWith("smtps://")) // should probably use KURL and SMTPS_PROTOCOL { mTransportInfo->type = "smtps"; mTransportInfo->auth = FALSE; mTransportInfo->encryption = "ssl"; QString serverport = transport.mid(7); int colon = serverport.find(':'); if (colon != -1) { mTransportInfo->host = serverport.left(colon); mTransportInfo->port = serverport.mid(colon + 1); } else { mTransportInfo->host = serverport; mTransportInfo->port = "465"; } } else if (transport.startsWith("file://")) { mTransportInfo->type = "sendmail"; mTransportInfo->host = transport.mid(7); } } // strip off a trailing "/" while (mTransportInfo->host.endsWith("/")) { mTransportInfo->host.truncate(mTransportInfo->host.length()-1); } if (mTransportInfo->type == "sendmail") return new KMSendSendmail(this); if (mTransportInfo->type == "smtp" || mTransportInfo->type == "smtps") return new KMSendSMTP(this); return 0L; } //----------------------------------------------------------------------------- void KMSender::setStatusByLink(const KMMessage *aMsg) { int n = 0; while (1) { ulong msn; KMMsgStatus status; aMsg->getLink(n, &msn, &status); if (!msn || !status) break; n++; KMFolder *folder = 0; int index = -1; KMMsgDict::instance()->getLocation(msn, &folder, &index); if (folder && index != -1) { folder->open(); if ( status == KMMsgStatusDeleted ) { // Move the message to the trash folder KMDeleteMsgCommand *cmd = new KMDeleteMsgCommand( folder, folder->getMsg( index ) ); cmd->start(); } else { folder->setStatus(index, status); } folder->close(); } else { kdWarning(5006) << k_funcinfo << "Cannot update linked message, it could not be found!" << endl; } } } //============================================================================= //============================================================================= KMSendProc::KMSendProc( KMSender * sender ) : QObject( 0 ), mSender( sender ), mLastErrorMessage(), mSendOk( false ), mSending( false ) { } //----------------------------------------------------------------------------- void KMSendProc::reset() { mSending = FALSE; mSendOk = FALSE; mLastErrorMessage = QString::null; } //----------------------------------------------------------------------------- void KMSendProc::failed(const QString &aMsg) { mSending = FALSE; mSendOk = FALSE; mLastErrorMessage = aMsg; } //----------------------------------------------------------------------------- void KMSendProc::statusMsg(const QString& aMsg) { if (mSender) mSender->setStatusMsg(aMsg); } //============================================================================= //============================================================================= KMSendSendmail::KMSendSendmail( KMSender * sender ) : KMSendProc( sender ), mMsgStr(), mMsgPos( 0 ), mMsgRest( 0 ), mMailerProc( 0 ) { } KMSendSendmail::~KMSendSendmail() { delete mMailerProc; mMailerProc = 0; } bool KMSendSendmail::doStart() { if (mSender->transportInfo()->host.isEmpty()) { const QString str = i18n("Please specify a mailer program in the settings."); const QString msg = i18n("Sending failed:\n%1\n" "The message will stay in the 'outbox' folder and will be resent.\n" "Please remove it from there if you do not want the message to " "be resent.\n" "The following transport protocol was used:\n %2") .arg(str + "\n") .arg("sendmail://"); KMessageBox::information(0,msg); return false; } if (!mMailerProc) { mMailerProc = new KProcess; assert(mMailerProc != 0); connect(mMailerProc,SIGNAL(processExited(KProcess*)), this, SLOT(sendmailExited(KProcess*))); connect(mMailerProc,SIGNAL(wroteStdin(KProcess*)), this, SLOT(wroteStdin(KProcess*))); connect(mMailerProc,SIGNAL(receivedStderr(KProcess*,char*,int)), this, SLOT(receivedStderr(KProcess*, char*, int))); } return true; } void KMSendSendmail::doFinish() { delete mMailerProc; mMailerProc = 0; } void KMSendSendmail::abort() { delete mMailerProc; mMailerProc = 0; mSendOk = false; mMsgStr = 0; idle(); } bool KMSendSendmail::doSend( const QString & sender, const QStringList & to, const QStringList & cc, const QStringList & bcc, const QCString & message ) { mMailerProc->clearArguments(); *mMailerProc << mSender->transportInfo()->host << "-i" << "-f" << sender << to << cc << bcc ; mMsgStr = message; if ( !mMailerProc->start( KProcess::NotifyOnExit, KProcess::All ) ) { KMessageBox::information( 0, i18n("Failed to execute mailer program %1") .arg( mSender->transportInfo()->host ) ); return false; } mMsgPos = mMsgStr.data(); mMsgRest = mMsgStr.length(); wroteStdin( mMailerProc ); return true; } void KMSendSendmail::wroteStdin(KProcess *proc) { char* str; int len; assert(proc!=0); Q_UNUSED( proc ); str = mMsgPos; len = (mMsgRest>1024 ? 1024 : mMsgRest); if (len <= 0) { mMailerProc->closeStdin(); } else { mMsgRest -= len; mMsgPos += len; mMailerProc->writeStdin(str,len); // if code is added after writeStdin() KProcess probably initiates // a race condition. } } void KMSendSendmail::receivedStderr(KProcess *proc, char *buffer, int buflen) { assert(proc!=0); Q_UNUSED( proc ); mLastErrorMessage.replace(mLastErrorMessage.length(), buflen, buffer); } void KMSendSendmail::sendmailExited(KProcess *proc) { assert(proc!=0); mSendOk = (proc->normalExit() && proc->exitStatus()==0); if (!mSendOk) failed(i18n("Sendmail exited abnormally.")); mMsgStr = 0; emit idle(); } //----------------------------------------------------------------------------- //============================================================================= //============================================================================= KMSendSMTP::KMSendSMTP(KMSender *sender) : KMSendProc(sender), mInProcess(false), mJob(0), mSlave(0) { KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *, int, const QString &)), this, SLOT(slaveError(KIO::Slave *, int, const QString &))); } KMSendSMTP::~KMSendSMTP() { if (mJob) mJob->kill(); } bool KMSendSMTP::doSend( const QString & sender, const QStringList & to, const QStringList & cc, const QStringList & bcc, const QCString & message ) { QString query = "headers=0&from="; query += KURL::encode_string( sender ); if ( !to.empty() ) query += "&to=" + to.join( "&to=" ); if ( !cc.empty() ) query += "&cc=" + cc.join( "&cc=" ); if ( !bcc.empty() ) query += "&bcc=" + bcc.join( "&bcc=" ); KMTransportInfo * ti = mSender->transportInfo(); if ( ti->specifyHostname ) query += "&hostname=" + KURL::encode_string( ti->localHostname ); if ( !kmkernel->msgSender()->sendQuotedPrintable() ) query += "&body=8bit"; KURL destination; destination.setProtocol((ti->encryption == "SSL") ? SMTPS_PROTOCOL : SMTP_PROTOCOL); destination.setHost(ti->host); destination.setPort(ti->port.toUShort()); if (ti->auth) { if( (ti->user.isEmpty() || ti->passwd().isEmpty()) && ti->authType != "GSSAPI" ) { bool b = FALSE; int result; KCursorSaver idle(KBusyPtr::idle()); QString passwd = ti->passwd(); result = KIO::PasswordDialog::getNameAndPassword(ti->user, passwd, &b, i18n("You need to supply a username and a password to use this " "SMTP server."), FALSE, QString::null, ti->name, QString::null); if ( result != QDialog::Accepted ) { abort(); return FALSE; } if (int id = KMTransportInfo::findTransport(ti->name)) { ti->setPasswd( passwd ); ti->writeConfig(id); } } destination.setUser(ti->user); destination.setPass(ti->passwd()); } if (!mSlave || !mInProcess) { KIO::MetaData slaveConfig; slaveConfig.insert("tls", (ti->encryption == "TLS") ? "on" : "off"); if (ti->auth) slaveConfig.insert("sasl", ti->authType); mSlave = KIO::Scheduler::getConnectedSlave(destination, slaveConfig); } if (!mSlave) { abort(); return false; } // dotstuffing is now done by the slave (see setting of metadata) mMessage = message; mMessageLength = mMessage.length(); mMessageOffset = 0; if ( mMessageLength ) // allow +5% for subsequent LF->CRLF and dotstuffing (an average // over 2G-lines gives an average line length of 42-43): query += "&size=" + QString::number( qRound( mMessageLength * 1.05 ) ); destination.setPath("/send"); destination.setQuery( query ); mJob = KIO::put( destination, -1, false, false, false ); if ( !mJob ) { abort(); return false; } mJob->addMetaData( "lf2crlf+dotstuff", "slave" ); KIO::Scheduler::assignJobToSlave(mSlave, mJob); connect(mJob, SIGNAL(result(KIO::Job *)), this, SLOT(result(KIO::Job *))); connect(mJob, SIGNAL(dataReq(KIO::Job *, QByteArray &)), this, SLOT(dataReq(KIO::Job *, QByteArray &))); mSendOk = true; mInProcess = true; return true; } void KMSendSMTP::cleanup() { if(mJob) { mJob->kill(TRUE); mJob = 0; mSlave = 0; } if (mSlave) { KIO::Scheduler::disconnectSlave(mSlave); mSlave = 0; } mInProcess = false; } void KMSendSMTP::abort() { cleanup(); emit idle(); } void KMSendSMTP::doFinish() { cleanup(); } void KMSendSMTP::dataReq(KIO::Job *, QByteArray &array) { // Send it by 32K chuncks const int chunkSize = QMIN( mMessageLength - mMessageOffset, 32*1024 ); if ( chunkSize > 0 ) { array.duplicate(mMessage.data() + mMessageOffset, chunkSize); mMessageOffset += chunkSize; } else { array.resize(0); mMessage.resize(0); } mSender->emitProgressInfo( mMessageOffset ); } void KMSendSMTP::result(KIO::Job *_job) { if (!mJob) return; mJob = 0; if(_job->error()) { mSendOk = false; if (_job->error() == KIO::ERR_SLAVE_DIED) mSlave = 0; failed(_job->errorString()); abort(); } else { emit idle(); } } void KMSendSMTP::slaveError(KIO::Slave *aSlave, int error, const QString &errorMsg) { if (aSlave == mSlave) { if (error == KIO::ERR_SLAVE_DIED) mSlave = 0; mSendOk = false; mJob = 0; failed(KIO::buildErrorString(error, errorMsg)); abort(); } } #include "kmsender.moc" #include "kmsender_p.moc" diff --git a/kmail/searchwindow.cpp b/kmail/searchwindow.cpp index 64f031f9b7..3519018086 100644 --- a/kmail/searchwindow.cpp +++ b/kmail/searchwindow.cpp @@ -1,817 +1,817 @@ /* * kmail: KDE mail client * Copyright (c) 1996-1998 Stefan Taferner * Copyright (c) 2001 Aaron J. Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "kmcommands.h" #include "searchwindow.h" #include "kmmainwidget.h" #include "kmmsgdict.h" #include "kmmsgpart.h" #include "kmfolderimap.h" #include "kmfoldermgr.h" #include "kmfoldersearch.h" #include "kmfoldertree.h" #include "kmsearchpatternedit.h" #include "kmsearchpattern.h" #include "folderrequester.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include //for mPatternEdit->queryList( 0, "mRuleField" )->first(); #include #include #include #include #include #include namespace KMail { const int SearchWindow::MSGID_COLUMN = 4; //----------------------------------------------------------------------------- SearchWindow::SearchWindow(KMMainWidget* w, const char* name, KMFolder *curFolder, bool modal): KDialogBase(0, name, modal, i18n("Find Messages"), User1 | User2 | Close, User1, false, KGuiItem( i18n("&Search"), "find" ), - KGuiItem( i18n("S&top"), "cancel" )), + KStdGuiItem::stop()), mStopped(false), mCloseRequested(false), mSortColumn(0), mSortOrder(Ascending), mFolder(0), mTimer(new QTimer(this)), mLastFocus(0), mKMMainWidget(w) { #if !KDE_IS_VERSION( 3, 2, 91 ) // HACK - KWin keeps all dialogs on top of their mainwindows, but that's probably // wrong (#76026), and should be done only for modals. CVS HEAD should get // proper fix in KWin (l.lunak@kde.org) XDeleteProperty( qt_xdisplay(), winId(), XA_WM_TRANSIENT_FOR ); #endif KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon()); KConfig* config = KMKernel::config(); config->setGroup("SearchDialog"); QWidget* searchWidget = new QWidget(this); QVBoxLayout *vbl = new QVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" ); QButtonGroup * radioGroup = new QButtonGroup( searchWidget ); radioGroup->hide(); mChkbxAllFolders = new QRadioButton(i18n("Search in &all local folders"), searchWidget); vbl->addWidget( mChkbxAllFolders ); radioGroup->insert( mChkbxAllFolders ); QHBoxLayout *hbl = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl" ); mChkbxSpecificFolders = new QRadioButton(i18n("Search &only in:"), searchWidget); hbl->addWidget(mChkbxSpecificFolders); mChkbxSpecificFolders->setChecked(true); radioGroup->insert( mChkbxSpecificFolders ); mCbxFolders = new FolderRequester( searchWidget, kmkernel->getKMMainWidget()->folderTree() ); mCbxFolders->setMustBeReadWrite( false ); mCbxFolders->setFolder(curFolder); hbl->addWidget(mCbxFolders); mChkSubFolders = new QCheckBox(i18n("I&nclude sub-folders"), searchWidget); mChkSubFolders->setChecked(true); hbl->addWidget(mChkSubFolders); QWidget *spacer = new QWidget( searchWidget, "spacer" ); spacer->setMinimumHeight( 2 ); vbl->addWidget( spacer ); mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true ); mPatternEdit->setFrameStyle( QFrame::NoFrame | QFrame::Plain ); mPatternEdit->setInsideMargin( 0 ); mSearchPattern = new KMSearchPattern(); KMFolderSearch *searchFolder = 0; if (curFolder) searchFolder = dynamic_cast(curFolder->storage()); if (searchFolder) { KConfig config(curFolder->location()); KMFolder *root = searchFolder->search()->root(); config.setGroup("Search Folder"); mSearchPattern->readConfig(&config); if (root) { mChkbxSpecificFolders->setChecked(true); mCbxFolders->setFolder(root); mChkSubFolders->setChecked(searchFolder->search()->recursive()); } else { mChkbxAllFolders->setChecked(true); } mFolder = searchFolder; } mPatternEdit->setSearchPattern( mSearchPattern ); QObjectList *list = mPatternEdit->queryList( 0, "mRuleField" ); QObject *object = 0; if ( list ) object = list->first(); delete list; if (!searchFolder && object && ::qt_cast(object)) static_cast(object)->setCurrentText("Subject"); vbl->addWidget( mPatternEdit ); // enable/disable widgets depending on radio buttons: connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)), mCbxFolders, SLOT(setEnabled(bool)) ); connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)), mChkSubFolders, SLOT(setEnabled(bool)) ); connect( mChkbxAllFolders, SIGNAL(toggled(bool)), this, SLOT(setEnabledSearchButton(bool)) ); mLbxMatches = new KListView(searchWidget, "Find Messages"); /* Default is to sort by date. TODO: Unfortunately this sorts *while* inserting, which looks rather strange - the user cannot read the results so far as they are constantly re-sorted --dnaber Sorting is now disabled when a search is started and reenabled when it stops. Items are appended to the list. This not only solves the above problem, but speeds searches with many hits up considerably. - till TODO: subclass KListViewItem and do proper (and performant) comapare functions */ mLbxMatches->setSorting(2, false); mLbxMatches->setShowSortIndicator(true); mLbxMatches->setAllColumnsShowFocus(true); mLbxMatches->setSelectionModeExt(KListView::Extended); mLbxMatches->addColumn(i18n("Subject"), config->readNumEntry("SubjectWidth", 150)); mLbxMatches->addColumn(i18n("Sender/Receiver"), config->readNumEntry("SenderWidth", 120)); mLbxMatches->addColumn(i18n("Date"), config->readNumEntry("DateWidth", 120)); mLbxMatches->addColumn(i18n("Folder"), config->readNumEntry("FolderWidth", 100)); mLbxMatches->addColumn(""); // should be hidden mLbxMatches->setColumnWidthMode( MSGID_COLUMN, QListView::Manual ); mLbxMatches->setColumnWidth(MSGID_COLUMN, 0); mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN); connect(mLbxMatches, SIGNAL(doubleClicked(QListViewItem *)), this, SLOT(slotShowMsg(QListViewItem *))); connect( mLbxMatches, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int )), this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); vbl->addWidget(mLbxMatches); QHBoxLayout *hbl2 = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" ); mSearchFolderLbl = new QLabel(i18n("Search folder &name:"), searchWidget); hbl2->addWidget(mSearchFolderLbl); mSearchFolderEdt = new KLineEdit(searchWidget); if (searchFolder) mSearchFolderEdt->setText(searchFolder->folder()->name()); else mSearchFolderEdt->setText(i18n("Last Search")); mSearchFolderLbl->setBuddy(mSearchFolderEdt); hbl2->addWidget(mSearchFolderEdt); mSearchFolderBtn = new QPushButton(i18n("&Rename"), searchWidget); mSearchFolderBtn->setEnabled(false); hbl2->addWidget(mSearchFolderBtn); mSearchFolderOpenBtn = new QPushButton(i18n("Op&en"), searchWidget); mSearchFolderOpenBtn->setEnabled(false); hbl2->addWidget(mSearchFolderOpenBtn); connect( mSearchFolderEdt, SIGNAL( textChanged( const QString &)), this, SLOT( updateCreateButton( const QString & ))); connect( mSearchFolderBtn, SIGNAL( clicked() ), this, SLOT( renameSearchFolder() )); connect( mSearchFolderOpenBtn, SIGNAL( clicked() ), this, SLOT( openSearchFolder() )); mStatusBar = new KStatusBar(searchWidget); mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true); mStatusBar->changeItem(i18n("Ready."), 0); mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter); mStatusBar->insertItem(QString::null, 1, 1, true); mStatusBar->setItemAlignment(1, AlignLeft | AlignVCenter); vbl->addWidget(mStatusBar); int mainWidth = config->readNumEntry("SearchWidgetWidth", 0); int mainHeight = config->readNumEntry("SearchWidgetHeight", 0); if (mainWidth || mainHeight) resize(mainWidth, mainHeight); setMainWidget(searchWidget); setButtonBoxOrientation(QWidget::Vertical); mBtnSearch = actionButton(KDialogBase::User1); mBtnStop = actionButton(KDialogBase::User2); mBtnStop->setEnabled(false); connect(this, SIGNAL(user1Clicked()), SLOT(slotSearch())); connect(this, SIGNAL(user2Clicked()), SLOT(slotStop())); connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); // give focus to the value field of the first search rule object = mPatternEdit->child( "regExpLineEdit" ); if ( object && object->isWidgetType() ) { static_cast(object)->setFocus(); //kdDebug(5006) << "SearchWindow: focus has been given to widget " // << object->name() << endl; } else kdDebug(5006) << "SearchWindow: regExpLineEdit not found" << endl; //set up actions KActionCollection *ac = actionCollection(); mReplyAction = new KAction( i18n("&Reply..."), "mail_reply", 0, this, SLOT(slotReplyToMsg()), ac, "search_reply" ); mReplyAllAction = new KAction( i18n("Reply to &All..."), "mail_replyall", 0, this, SLOT(slotReplyAllToMsg()), ac, "search_reply_all" ); mReplyListAction = new KAction( i18n("Reply to Mailing-&List..."), "mail_replylist", 0, this, SLOT(slotReplyListToMsg()), ac, "search_reply_list" ); mForwardActionMenu = new KActionMenu( i18n("Message->","&Forward"), "mail_forward", ac, "search_message_forward" ); connect( mForwardActionMenu, SIGNAL(activated()), this, SLOT(slotForwardMsg()) ); mForwardAction = new KAction( i18n("&Inline..."), "mail_forward", 0, this, SLOT(slotForwardMsg()), ac, "search_message_forward_inline" ); mForwardActionMenu->insert( mForwardAction ); mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."), "mail_forward", 0, this, SLOT(slotForwardAttachedMsg()), ac, "search_message_forward_as_attachment" ); mForwardActionMenu->insert( mForwardAttachedAction ); mSaveAsAction = KStdAction::saveAs( this, SLOT(slotSaveMsg()), ac, "search_file_save_as" ); mSaveAtchAction = new KAction( i18n("Save Attachments..."), "attach", 0, this, SLOT(slotSaveAttachments()), ac, "search_save_attachments" ); mPrintAction = KStdAction::print( this, SLOT(slotPrintMsg()), ac, "search_print" ); mClearAction = new KAction( i18n("Clear Selection"), 0, 0, this, SLOT(slotClearSelection()), ac, "search_clear_selection" ); connect(mTimer, SIGNAL(timeout()), this, SLOT(updStatus())); connect(kmkernel->searchFolderMgr(), SIGNAL(folderInvalidated(KMFolder*)), this, SLOT(folderInvalidated(KMFolder*))); connect(mCbxFolders, SIGNAL(folderChanged(KMFolder*)), this, SLOT(slotFolderActivated(KMFolder*))); } //----------------------------------------------------------------------------- SearchWindow::~SearchWindow() { QValueListIterator > fit; for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) { if (!(*fit)) continue; (*fit)->close(); } KConfig* config = KMKernel::config(); config->setGroup("SearchDialog"); config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0)); config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1)); config->writeEntry("DateWidth", mLbxMatches->columnWidth(2)); config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3)); config->writeEntry("SearchWidgetWidth", width()); config->writeEntry("SearchWidgetHeight", height()); config->sync(); } void SearchWindow::setEnabledSearchButton(bool) { //Make sure that button is enable //Before when we selected a folder == "Local Folder" as that it was not a folder //search button was disable, and when we select "Search in all local folder" //Search button was never enabled :( mBtnSearch->setEnabled( true ); } //----------------------------------------------------------------------------- void SearchWindow::updStatus(void) { QString genMsg, detailMsg; int numMatches = 0, count = 0; KMSearch const *search = (mFolder) ? (mFolder->search()) : 0; QString folderName; if (search) { numMatches = search->foundCount(); count = search->searchedCount(); folderName = search->currentFolder(); } if (mFolder && mFolder->search() && !mFolder->search()->running()) { if(!mStopped) { genMsg = i18n("Done"); detailMsg = i18n("%n match (%1)", "%n matches (%1)", numMatches) .arg(i18n("%n message processed", "%n messages processed", count)); } else { genMsg = i18n("Search canceled"); detailMsg = i18n("%n match so far (%1)", "%n matches so far (%1)", numMatches) .arg(i18n("%n message processed", "%n messages processed", count)); } } else { genMsg = i18n("%n match", "%n matches", numMatches); detailMsg = i18n("Searching in %1 (message %2)") .arg(folderName) .arg(count); } mStatusBar->changeItem(genMsg, 0); mStatusBar->changeItem(detailMsg, 1); } //----------------------------------------------------------------------------- void SearchWindow::keyPressEvent(QKeyEvent *evt) { KMSearch const *search = (mFolder) ? mFolder->search() : 0; bool searching = (search) ? search->running() : false; if (evt->key() == Key_Escape && searching) { mFolder->stopSearch(); return; } KDialogBase::keyPressEvent(evt); } //----------------------------------------------------------------------------- void SearchWindow::slotFolderActivated( KMFolder* folder ) { mChkbxSpecificFolders->setChecked(true); mBtnSearch->setEnabled(folder); } //----------------------------------------------------------------------------- void SearchWindow::activateFolder(KMFolder *curFolder) { mChkbxSpecificFolders->setChecked(true); mCbxFolders->setFolder(curFolder); } //----------------------------------------------------------------------------- void SearchWindow::slotSearch() { mLastFocus = focusWidget(); mBtnSearch->setFocus(); // set focus so we don't miss key event mStopped = false; mFetchingInProgress = 0; mSearchFolderOpenBtn->setEnabled(true); mBtnSearch->setEnabled(false); mBtnStop->setEnabled(true); mLbxMatches->clear(); mSortColumn = mLbxMatches->sortColumn(); mSortOrder = mLbxMatches->sortOrder(); mLbxMatches->setSorting(-1); mLbxMatches->setShowSortIndicator(false); // If we haven't openend an existing search folder, find or // create one. if (!mFolder) { KMFolderMgr *mgr = kmkernel->searchFolderMgr(); if (mSearchFolderEdt->text().isEmpty()) mSearchFolderEdt->setText(i18n("Last Search")); QString baseName = mSearchFolderEdt->text(); QString fullName = baseName; int count = 0; KMFolder *folder; while ((folder = mgr->find(fullName))) { if (folder->storage()->inherits("KMFolderSearch")) break; fullName = QString("%1 %2").arg(baseName).arg(++count); } if (!folder) folder = mgr->createFolder(fullName, FALSE, KMFolderTypeSearch, &mgr->dir()); mFolder = dynamic_cast( folder->storage() ); } mFolder->stopSearch(); disconnect(mFolder, SIGNAL(msgAdded(int)), this, SLOT(slotAddMsg(int))); disconnect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)), this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32))); connect(mFolder, SIGNAL(msgAdded(int)), this, SLOT(slotAddMsg(int))); connect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)), this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32))); KMSearch *search = new KMSearch(); connect(search, SIGNAL(finished(bool)), this, SLOT(searchDone())); if (mChkbxAllFolders->isChecked()) { search->setRecursive(true); } else { search->setRoot(mCbxFolders->folder()); search->setRecursive(mChkSubFolders->isChecked()); } mPatternEdit->updateSearchPattern(); KMSearchPattern *searchPattern = new KMSearchPattern(); *searchPattern = *mSearchPattern; //deep copy searchPattern->purify(); search->setSearchPattern(searchPattern); mFolder->setSearch(search); enableGUI(); if (mFolder && !mFolders.contains(mFolder.operator->()->folder())) { mFolder->open(); mFolders.append(mFolder.operator->()->folder()); } mTimer->start(200); } //----------------------------------------------------------------------------- void SearchWindow::searchDone() { mTimer->stop(); updStatus(); QTimer::singleShot(0, this, SLOT(enableGUI())); if(mLastFocus) mLastFocus->setFocus(); if (mCloseRequested) close(); mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending); mLbxMatches->setShowSortIndicator(true); } void SearchWindow::slotAddMsg(int idx) { if (!mFolder) return; bool unget = !mFolder->isMessage(idx); KMMessage *msg = mFolder->getMsg(idx); QString from, fName; KMFolder *pFolder = msg->parent(); if (!mFolders.contains(pFolder)) { mFolders.append(pFolder); pFolder->open(); } if(pFolder->whoField() == "To") from = msg->to(); else from = msg->from(); if (pFolder->isSystemFolder()) fName = i18n(pFolder->name().utf8()); else fName = pFolder->name(); (void)new KListViewItem(mLbxMatches, mLbxMatches->lastItem(), msg->subject(), from, msg->dateIsoStr(), fName, QString::number(mFolder->serNum(idx))); if (unget) mFolder->unGetMsg(idx); } void SearchWindow::slotRemoveMsg(KMFolder *, Q_UINT32 serNum) { if (!mFolder) return; QListViewItemIterator it(mLbxMatches); while (it.current()) { QListViewItem *item = *it; if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) { delete item; return; } ++it; } } //----------------------------------------------------------------------------- void SearchWindow::slotStop() { if (mFolder) mFolder->stopSearch(); mStopped = true; mBtnStop->setEnabled(false); } //----------------------------------------------------------------------------- void SearchWindow::slotClose() { accept(); } //----------------------------------------------------------------------------- void SearchWindow::closeEvent(QCloseEvent *e) { if (mFolder && mFolder->search() && mFolder->search()->running()) { mCloseRequested = true; //Cancel search in progress by setting the search folder search to //the null search mFolder->setSearch(new KMSearch()); QTimer::singleShot(0, this, SLOT(slotClose())); } else { KDialogBase::closeEvent(e); } } //----------------------------------------------------------------------------- void SearchWindow::updateCreateButton( const QString &s) { mSearchFolderBtn->setEnabled(s != i18n("Last Search") && mSearchFolderOpenBtn->isEnabled()); } //----------------------------------------------------------------------------- void SearchWindow::renameSearchFolder() { if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) { int i = 1; QString name = mSearchFolderEdt->text(); while (i < 100) { if (!kmkernel->searchFolderMgr()->find( name )) { mFolder->rename( name ); kmkernel->searchFolderMgr()->contentsChanged(); break; } name.setNum( i ); name = mSearchFolderEdt->text() + " " + name; ++i; } } } void SearchWindow::openSearchFolder() { renameSearchFolder(); mKMMainWidget->slotSelectFolder( mFolder->folder() ); slotClose(); } //----------------------------------------------------------------------------- void SearchWindow::folderInvalidated(KMFolder *folder) { if (folder->storage() == mFolder) { mLbxMatches->clear(); if (mFolder->search()) connect(mFolder->search(), SIGNAL(finished(bool)), this, SLOT(searchDone())); mTimer->start(200); enableGUI(); } } //----------------------------------------------------------------------------- bool SearchWindow::slotShowMsg(QListViewItem *item) { if(!item) return false; KMFolder* folder; int msgIndex; KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(), &folder, &msgIndex); if (!folder || msgIndex < 0) return false; mKMMainWidget->slotSelectFolder(folder); KMMessage* message = folder->getMsg(msgIndex); if (!message) return false; mKMMainWidget->slotSelectMessage(message); return true; } //----------------------------------------------------------------------------- void SearchWindow::enableGUI() { KMSearch const *search = (mFolder) ? (mFolder->search()) : 0; bool searching = (search) ? (search->running()) : false; actionButton(KDialogBase::Close)->setEnabled(!searching); mCbxFolders->setEnabled(!searching); mChkSubFolders->setEnabled(!searching); mChkbxAllFolders->setEnabled(!searching); mChkbxSpecificFolders->setEnabled(!searching); mPatternEdit->setEnabled(!searching); mBtnSearch->setEnabled(!searching); mBtnStop->setEnabled(searching); } //----------------------------------------------------------------------------- KMMessageList SearchWindow::selectedMessages() { KMMessageList msgList; KMFolder* folder = 0; int msgIndex = -1; for (QListViewItemIterator it(mLbxMatches); it.current(); it++) if (it.current()->isSelected()) { KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(), &folder, &msgIndex); if (folder && msgIndex >= 0) msgList.append(folder->getMsgBase(msgIndex)); } return msgList; } //----------------------------------------------------------------------------- KMMessage* SearchWindow::message() { QListViewItem *item = mLbxMatches->currentItem(); KMFolder* folder = 0; int msgIndex = -1; if (!item) return 0; KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(), &folder, &msgIndex); if (!folder || msgIndex < 0) return 0; return folder->getMsg(msgIndex); } //----------------------------------------------------------------------------- void SearchWindow::moveSelectedToFolder( int menuId ) { KMFolder *dest = mMenuToFolder[menuId]; if (!dest) return; KMMessageList msgList = selectedMessages(); KMCommand *command = new KMMoveCommand( dest, msgList ); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::copySelectedToFolder( int menuId ) { KMFolder *dest = mMenuToFolder[menuId]; if (!dest) return; KMMessageList msgList = selectedMessages(); KMCommand *command = new KMCopyCommand( dest, msgList ); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::updateContextMenuActions() { int count = selectedMessages().count(); bool single_actions = count == 1; mReplyAction->setEnabled( single_actions ); mReplyAllAction->setEnabled( single_actions ); mReplyListAction->setEnabled( single_actions ); mPrintAction->setEnabled( single_actions ); } //----------------------------------------------------------------------------- void SearchWindow::slotContextMenuRequested( QListViewItem *lvi, const QPoint &, int ) { if (!lvi) return; mLbxMatches->setSelected( lvi, TRUE ); mLbxMatches->setCurrentItem( lvi ); // FIXME is this ever unGetMsg()'d? if (!message()) return; QPopupMenu *menu = new QPopupMenu(this); updateContextMenuActions(); mMenuToFolder.clear(); QPopupMenu *msgMoveMenu = new QPopupMenu(menu); mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage, this, &mMenuToFolder, msgMoveMenu ); QPopupMenu *msgCopyMenu = new QPopupMenu(menu); mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage, this, &mMenuToFolder, msgCopyMenu ); // show most used actions mReplyAction->plug(menu); mReplyAllAction->plug(menu); mReplyListAction->plug(menu); mForwardActionMenu->plug(menu); menu->insertSeparator(); menu->insertItem(i18n("&Copy To"), msgCopyMenu); menu->insertItem(i18n("&Move To"), msgMoveMenu); mSaveAsAction->plug(menu); mSaveAtchAction->plug(menu); mPrintAction->plug(menu); menu->insertSeparator(); mClearAction->plug(menu); menu->exec (QCursor::pos(), 0); delete menu; } //----------------------------------------------------------------------------- void SearchWindow::slotClearSelection() { mLbxMatches->clearSelection(); } //----------------------------------------------------------------------------- void SearchWindow::slotReplyToMsg() { KMCommand *command = new KMReplyToCommand(this, message()); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotReplyAllToMsg() { KMCommand *command = new KMReplyToAllCommand(this, message()); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotReplyListToMsg() { KMCommand *command = new KMReplyListCommand(this, message()); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotForwardMsg() { KMCommand *command = new KMForwardCommand(this, selectedMessages()); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotForwardAttachedMsg() { KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages()); command->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotSaveMsg() { KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this, selectedMessages()); if (saveCommand->url().isEmpty()) delete saveCommand; else saveCommand->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotSaveAttachments() { KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this, selectedMessages()); saveCommand->start(); } //----------------------------------------------------------------------------- void SearchWindow::slotPrintMsg() { KMCommand *command = new KMPrintCommand(this, message()); command->start(); } } // namespace KMail #include "searchwindow.moc" diff --git a/kmail/smimeconfiguration.ui b/kmail/smimeconfiguration.ui index 28e79c5d56..d03089b688 100644 --- a/kmail/smimeconfiguration.ui +++ b/kmail/smimeconfiguration.ui @@ -1,416 +1,416 @@ SMimeConfiguration SMimeConfiguration 0 0 557 586 unnamed CRLRB Validate certificates using CRLs true If this option is selected, S/MIME certificates are validated using Certificate Revocation Lists (CRLs). OCSPRB Validate certificates online (OCSP) If this option is selected, S/MIME certificates are validated online using the Online Certificates Status Protocol (OCSP). Fill in the URL of the OCSP responder below. OCSPGroupBox Online Certificate Validation unnamed layout4 unnamed textLabel1 OCSP responder URL: OCSPResponderURL Enter here the address of the server for online validation of certificates (OCSP responder). The URL is usually starting with http://. layout5 unnamed textLabel2 OCSP responder signature: OCSPResponderSignature spacer7 Horizontal Expanding 150 20 ignoreServiceURLCB - Ignore Service URL of certificates + Ignore service URL of certificates doNotCheckCertPolicyCB Do not check certificate policies By default GnuPG uses the file ~/.gnupg/policies.txt to check if a certificate policy is allowed. If this option is selected, policies are not checked. neverConsultCB Never consult a CRL If this option is checked, Certificate Revocation Lists are never used to validate S/MIME certificates. fetchMissingCB Fetch missing issuer certificates If this option is checked, missing issuer certificates are fetched when necessary (this applies to both validation methods, CRLs and OCSP) HTTPGroupBox HTTP Requests unnamed disableHTTPCB Do not perform any HTTP requests Entirely disables the use of HTTP for S/MIME. frameHTTP NoFrame Plain unnamed 0 layout5 unnamed systemHTTPProxy no proxy useCustomHTTPProxyRB Use this proxy for HTTP requests: honorHTTPProxyRB Use system HTTP proxy: If this option is selected, the value of the HTTP proxy shown on the right (which comes from the environment variable http_proxy) will be used for any HTTP request. customHTTPProxy Enter here the location of your HTTP Proxy, which will be used for all HTTP requests relating to S/MIME. The syntax is host:port, for instance myproxy.nowhere.com:3128. ignoreHTTPDPCB - Ignore HTTP CRL Distribution Point of certificates + Ignore HTTP CRL distribution point of certificates When looking for the location of a CRL, the to-be-tested certificate usually contains what are known as "CRL Distribution Point" (DP) entries, which are URLs describing the way to access the URL. The first found DP entry is used. With this option all entries using the HTTP scheme are ignored when looking for a suitable DP. LDAPGroupBox LDAP Requests unnamed disableLDAPCB Do not perform any LDAP requests Entirely disables the use of LDAP for S/MIME. frameLDAP NoFrame Plain unnamed 0 ignoreLDAPDPCB - Ignore LDAP CRL Distribution Point of certificates + Ignore LDAP CRL distribution point of certificates When looking for the location of a CRL, the to-be-tested certificate usually contains what are known as "CRL Distribution Point" (DP) entries, which are URLs describing the way to access the URL. The first found DP entry is used. With this option all entries using the LDAP scheme are ignored when looking for a suitable DP. layout5 unnamed customLDAPLabel Primary host for LDAP requests: customLDAPProxy Entering a LDAP server here will make all LDAP requests go to that server first. More precisely, this setting overrides any specified host and port part in a LDAP URL and will also be used if host and port have been omitted from the URL. Other LDAP servers will be used only if the connection to the "proxy" failed. The syntax is "HOST" or "HOST:PORT". If PORT is omitted, port 389 (standard LDAP port) is used. spacer23 Vertical Expanding 20 73 Kleo::KeyRequester
../certmanager/lib/ui/keyrequester.h
-1 -1 0 5 5 0 0
CRLRB toggled(bool) OCSPGroupBox setDisabled(bool) OCSPRB toggled(bool) OCSPGroupBox setEnabled(bool) useCustomHTTPProxyRB toggled(bool) customHTTPProxy setEnabled(bool) honorHTTPProxyRB toggled(bool) customHTTPProxy setDisabled(bool) disableLDAPCB toggled(bool) frameLDAP setDisabled(bool) kleo::keyrequester.h
diff --git a/kmail/warningconfiguration.ui b/kmail/warningconfiguration.ui index 17b229d46a..7ed3ec9278 100644 --- a/kmail/warningconfiguration.ui +++ b/kmail/warningconfiguration.ui @@ -1,408 +1,408 @@ WarningConfiguration WarningConfiguration 0 0 552 325 unnamed mWarnUnsigned Warn when trying to send &unsigned messages true Check to be warned when sending unsigned messages. <qt> <h1>Warn When Trying To Send Unsigned Messages</h1> If this box is checked, you will be warned when you try to send parts of or the whole message unsigned. <p> It is recommended to leave this option turned on for maximum integrity. </qt> warnUnencryptedCB &Warn when trying to send unencrypted messages true Check to be warned when sending unencrypted messages. <qt> <h1>Warn When Trying To Send Unencrypted Messages</h1> If this box is checked, you will be warned when you try to send parts of or the whole message unencrypted. <p> It is recommended to leave this option turned on for maximum integrity. </qt> warnReceiverNotInCertificateCB - Warn if &receiver's email address is not in certificate + Warn if &Receiver's Email Address is Not in Certificate true Check to be warned if the address is not in the certificate <qt> <h1>Warn If Receiver's Email Address Is Not In Certificate</h1> If this option is checked, a warning is issued if the email address of the receiver is not contained in the certificate used for encrypting. <p> It is recommended to leave this option turned on for maximum security. </qt> warnGroupBox Warn if certificates/keys expire soon (configure thresholds below) true unnamed textLabel2 For signing AlignCenter textLabel2_2 For encryption AlignCenter mWarnSignKeyExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If Signature Certificate Expires</h1> Select the minimum number of days the signature certificate should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> mWarnEncrKeyExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If Encryption Certificate Expires</h1> Select the minimum number of days the encryption certificate should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> mWarnEncrChainCertExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If A Certificate In The Chain Expires</h1> Select the minimum number of days all certificates in the chain should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> mWarnSignChainCertExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If CA Certificate Expires</h1> Select the minimum number of days the CA certificate should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> mWarnSignRootCertExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If Root Certificate Expires</h1> Select the minimum number of days the root certificate should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> mWarnEncrRootCertExpiresSB days 999 1 14 Select the number of days here <qt> <h1>Warn If Root Certificate Expires</h1> Select the minimum number of days the root certificate should be valid without issuing a warning. <p> The recommended SPHINX setting is 14 days. </qt> textLabel1_2_2 For root certificates: mWarnSignRootCertExpiresSB textLabel1_2 For intermediate CA certificates: mWarnSignChainCertExpiresSB textLabel1 For end-user certificates/keys: mWarnSignKeyExpiresSB spacer5 Horizontal Expanding 40 20 spacer23 Vertical Expanding 20 90 layout1 unnamed spacer4 Horizontal Expanding 40 20 enableAllWarningsPB Re-enable All "Don't Ask Again" Warnings mWarnUnsigned warnUnencryptedCB warnReceiverNotInCertificateCB mWarnSignKeyExpiresSB mWarnSignChainCertExpiresSB mWarnSignRootCertExpiresSB mWarnEncrKeyExpiresSB mWarnEncrChainCertExpiresSB mWarnEncrRootCertExpiresSB enableAllWarningsPB diff --git a/knode/smtpaccountwidget_base.ui b/knode/smtpaccountwidget_base.ui index bc0c75eb45..153117c1e0 100644 --- a/knode/smtpaccountwidget_base.ui +++ b/knode/smtpaccountwidget_base.ui @@ -1,235 +1,235 @@ KNConfig::SmtpAccountWidgetBase SmtpAccountWidgetBase 0 0 306 320 SmtpAccountWidgetBase unnamed mUseExternalMailer - &Use External Mailer + &Use external mailer mServerLabel &Server: mServer mPortLabel &Port: mPort mUserLabel &User: mUser mPasswordLabel Pass&word: mPassword mLogin Server requires &authentication mSpacer Vertical Expanding 20 40 mPassword Password mUser mPort 25 0 65536 mServer mEncGroup Encryption unnamed mEncNone None mEncSSL SSL mEncTLS TLS mServer textChanged(const QString&) SmtpAccountWidgetBase changed() mPort valueChanged(int) SmtpAccountWidgetBase changed() mUseExternalMailer toggled(bool) SmtpAccountWidgetBase useExternalMailerToggled(bool) mUser textChanged(const QString&) SmtpAccountWidgetBase changed() mPassword textChanged(const QString&) SmtpAccountWidgetBase changed() mLogin toggled(bool) SmtpAccountWidgetBase loginToggled(bool) mEncGroup clicked(int) SmtpAccountWidgetBase changed() useExternalMailerToggled(bool) loginToggled(bool) kcmodule.h klineedit.h knuminput.h diff --git a/kode/kodemain.cpp b/kode/kodemain.cpp index 41bbe7581b..a567f20a07 100644 --- a/kode/kodemain.cpp +++ b/kode/kodemain.cpp @@ -1,633 +1,633 @@ /* This file is part of kdepim. Copyright (c) 2004 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "code.h" #include "printer.h" #include "license.h" #include "automakefile.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const KCmdLineOptions options[] = { { "c", 0, 0 }, { "create-class", I18N_NOOP("Create class"), 0 }, { "d", 0, 0 }, { "create-dialog", I18N_NOOP("Create dialog"), 0 }, { "create-kioslave", I18N_NOOP("Create kioslave"), 0 }, { "create-main", I18N_NOOP("Create main function template"), 0 }, { "y", 0, 0 }, { "codify", I18N_NOOP("Create generator code for given source"), 0 }, { "add-property", I18N_NOOP("Add property to class"), 0 }, { "inplace", I18N_NOOP("Change file in place"), 0 }, { "author-email ", I18N_NOOP("Add author with given email address"), 0 }, { "project ", I18N_NOOP("Name of project"), 0 }, { "gpl", I18N_NOOP("Use GPL as license"), 0 }, { "lgpl", I18N_NOOP("Use LGPL as license"), 0 }, { "classname ", I18N_NOOP("Name of class"), 0 }, { "filename ", I18N_NOOP("Name of file"), 0 }, { "namespace ", I18N_NOOP("Namespace"), 0 }, { "warning", I18N_NOOP("Create warning about code generation"), 0 }, - { "qt-exception", I18N_NOOP("Add Qt excpetion to GPL"), 0 }, + { "qt-exception", I18N_NOOP("Add Qt exception to GPL"), 0 }, { "singleton", I18N_NOOP("Create a singleton class"), 0 }, { "protocol", I18N_NOOP("kioslave protocol"), 0 }, { "+[filename]", I18N_NOOP("Source code file name"), 0 }, KCmdLineLastOption }; void addPropertyFunctions( QString &out, const QString &type, const QString &name ) { // FIXME: Use KODE::Function bool isReference = type.endsWith( "*" ) || type.endsWith( "&" ); QString argument; QString upper = KODE::Style::upperFirst( name ); if ( !isReference ) { argument = "const " + type + " &"; } else argument = type; KODE::Code code; code.setIndent( 4 ); code += "/**"; code += " Set ."; code += "*/"; code += "void set" + upper + "( " + argument + "v )"; code += "{"; code += " m" + upper + " = v;"; code += "}"; code += "/**"; code += " Get " + name + ". See set" + upper + "()."; code += "*/"; code += type + ( isReference ? "" : " " ) + name + "() const"; code += "{"; code += " return m" + upper + ";"; code += "}"; out += code.text(); } void addPropertyVariable( QString &out, const QString &type, const QString &name ) { QString upper = KODE::Style::upperFirst( name ); bool isReference = type.endsWith( "*" ) || type.endsWith( "&" ); KODE::Code code; code.setIndent( 4 ); code += type + ( isReference ? "" : " " ) + "m" + upper + ";"; out += code.text(); } // FIXME: Put addProperty in PropertyAdder class and add endReadAhead function. int addProperty( KCmdLineArgs *args ) { if ( args->count() != 3 ) { std::cerr << "Usage: kode --add-property " << "" << std::endl; return 1; } QString className = args->arg( 0 ); QString type = args->arg( 1 ); QString name = args->arg( 2 ); kdDebug() << "Add property: class " << className << ": " << type << " " << name << endl; QString headerFileName = className.lower() + ".h"; QFile headerFile( headerFileName ); if ( !headerFile.open( IO_ReadOnly ) ) { std::cerr << "Unable to open file '" << headerFileName.utf8() << "'" << std::endl; return 1; } QTextStream in( &headerFile ); enum State { FindClass, FindConstructor, FindProperties, FindPrivate, FindVariables, Finish }; State state = FindClass; QString accessor; QString mutator; QString out; QString readAhead; QString line; while ( !( line = in.readLine() ).isNull() ) { // std::cout << line.utf8() << std::endl; kdDebug() << state << " LINE: " << line << endl; QString readAheadPrevious = readAhead; readAhead += line + "\n"; // out += line + "\n"; switch( state ) { case FindClass: // if ( line.find( QRegExp( className ) ) >= 0 ) { if ( line.find( QRegExp( "^\\s*class\\s+" + className ) ) >= 0 ) { kdDebug() << " FOUND CLASS" << endl; state = FindConstructor; } break; case FindConstructor: if ( line.find( QRegExp( "^\\s*" + className + "\\s*\\(" ) ) >= 0 ) { kdDebug() << " FOUND CONSTRUCTOR" << endl; out += readAhead; readAhead = QString::null; state = FindProperties; } break; case FindProperties: { QRegExp re( "(\\w+)\\s*\\(" ); if ( re.search( line ) >= 0 ) { QString function = re.cap( 1 ).lower(); if ( !function.isEmpty() ) { kdDebug() << "Function: " << function << endl; if ( function == className || function == "~" + className ) { out += readAhead; readAhead = QString::null; } else { if ( function.startsWith( "set" ) ) { mutator = function.mid( 3 ); kdDebug() << "MUTATOR: " << mutator << endl; } else { if ( function == mutator ) { accessor = function; kdDebug() << "ACCESSOR: " << accessor << endl; out += readAhead; readAhead = QString::null; } else { kdDebug() << "CREATE PROPERTY" << endl; out += readAheadPrevious; addPropertyFunctions( out, type, name ); out += "\n"; readAhead = line + "\n"; state = FindPrivate; } } } } } else if ( line.find( QRegExp( "\\s*protected" ) ) >= 0 ) { state = FindPrivate; } else if ( line.find( QRegExp( "\\s*private" ) ) >= 0 ) { if ( accessor.isEmpty() ) { addPropertyFunctions( out, type, name ); out += readAhead; readAhead = QString::null; addPropertyVariable( out, type, name ); state = Finish; } else { if ( accessor == mutator ) { out += readAheadPrevious; addPropertyFunctions( out, type, name ); out += "\n"; out += line + "\n"; readAhead = QString::null; } state = FindVariables; } } } break; case FindPrivate: if ( line.find( QRegExp( "\\s*private" ) ) >= 0 ) { if ( accessor.isEmpty() ) { out += readAhead; readAhead = QString::null; addPropertyVariable( out, type, name ); state = Finish; } else { state = FindVariables; } } break; case FindVariables: { if ( line.find( "m" + accessor.lower(), 0, false ) >= 0 ) { out += readAhead; readAhead = QString::null; addPropertyVariable( out, type, name ); state = Finish; } } break; case Finish: break; } } headerFile.close(); out += readAhead; if ( args->isSet( "inplace" ) ) { QString headerFileNameOut = headerFileName + ".kodeorig" ; KProcess proc; proc << "cp" << QFile::encodeName( headerFileName ) << QFile::encodeName( headerFileNameOut ); if ( !proc.start( KProcess::Block ) ) { kdError() << "Copy failed" << endl; } else { kdDebug() << "Write to original file." << endl; if ( !headerFile.open( IO_WriteOnly ) ) { kdError() << "Unable to open file '" << headerFileName << "' for writing." << endl; return 1; } QTextStream o( &headerFile ); o << out << endl; } } else { std::cout << out.utf8() << std::endl; } return 0; } int codify( KCmdLineArgs *args ) { if ( args->count() != 1 ) { std::cerr << "Usage: kode --codify " << std::endl; return 1; } QString filename = args->arg( 0 ); QFile f( filename ); if ( !f.open( IO_ReadOnly ) ) { kdError() << "Unable to open file '" << filename << "'." << endl; return 1; } else { std::cout << "KODE::Code code;" << std::endl; QTextStream ts( &f ); QString line; while( !( line = ts.readLine() ).isNull() ) { line.replace( "\\", "\\\\" ); line.replace( "\"", "\\\"" ); line = "code += \"" + line; line.append( "\";" ); std::cout << line.local8Bit() << std::endl; } } return 0; } int create( KCmdLineArgs *args ) { KODE::Printer p; if ( args->isSet( "warning" ) ) p.setCreationWarning( true ); bool createKioslave = args->isSet( "create-kioslave" ); bool createMain = args->isSet( "create-main" ); QString filename = args->getOption( "filename" ); if ( createMain ) { if ( filename.isEmpty() ) { kdError() << "Error: No file name given." << endl; return 1; } if ( filename.endsWith( ".cpp" ) ) { filename = filename.left( filename.length() - 4 ); } } else { if ( !args->isSet( "classname" ) ) { kdError() << "Error: No class name given." << endl; return 1; } } QString className = args->getOption( "classname" ); QString protocol; if ( createKioslave ) { if ( !args->isSet( "protocol" ) ) { protocol = className.lower(); kdWarning() << "Warning: No protocol for kioslave given. Assuming '" << protocol << "'" << endl; } else { protocol = args->getOption( "protocol" ); } } KODE::File file; file.setProject( args->getOption( "project" ) ); QString authorEmail = args->getOption( "author-email" ); QString authorName; KABC::Addressee a; if ( authorEmail.isEmpty() ) { a = KABC::StdAddressBook::self()->whoAmI(); authorEmail = a.preferredEmail(); } else { KABC::Addressee::List as = KABC::StdAddressBook::self()->findByEmail( authorEmail ); if ( as.isEmpty() ) { kdDebug() << "Unable to find '" << authorEmail << "' in address book." << endl; } else { a = as.first(); } } if ( !a.isEmpty() ) { authorName = a.realName(); } if ( !authorEmail.isEmpty() ) { file.addCopyright( QDate::currentDate().year(), authorName, authorEmail ); } KODE::License l; if ( args->isSet( "gpl" ) ) l = KODE::License( KODE::License::GPL ); if ( args->isSet( "lgpl" ) ) l = KODE::License( KODE::License::LGPL ); l.setQtException( args->isSet( "qt-exception" ) ); file.setLicense( l ); file.setNameSpace( args->getOption( "namespace" ) ); if ( createMain ) { file.addInclude( "kaboutdata.h" ); file.addInclude( "kapplication.h" ); file.addInclude( "kdebug" ); file.addInclude( "klocale" ); file.addInclude( "kcmdlineargs" ); KODE::Code code; code += "static const KCmdLineOptions options[] ="; code += "{"; code += " { \"verbose\", \"Verbose output\", 0 },"; code += " KCmdLineLastOption"; code += "};"; file.addFileCode( code ); KODE::Function main( "main", "int" ); main.addArgument( "int argc" ); main.addArgument( "char **argv" ); code.clear(); code += "KAboutData aboutData(\"test\",\"Test\",\"0.1\");"; code += "KCmdLineArgs::init(argc,argv,&aboutData);"; code += "KCmdLineArgs::addCmdLineOptions( options );"; code += ""; code += "KApplication app;"; code += ""; code += "KCmdLineArgs *args = KCmdLineArgs::parsedArgs();"; code += ""; code += "Q_UNUSED( args );"; main.setBody( code ); file.addFileFunction( main ); file.setFilename( filename ); p.printImplementation( file, false ); return 0; } KODE::Class c( className ); if ( args->isSet( "create-dialog" ) ) { c.addBaseClass( KODE::Class( "KDialogBase" ) ); c.addInclude( "kdialogbase.h" ); } else if ( createKioslave ) { c.setDocs( "This class implements a kioslave for ..." ); c.addBaseClass( KODE::Class( "SlaveBase", "KIO" ) ); c.addHeaderInclude( "kio/slavebase.h" ); KODE::Function get( "get", "void" ); get.addArgument( "const KURL &url" ); KODE::Code code; code += "kdDebug(7000) << \"" + className + "::get()\" << endl;"; code += "kdDebug(7000) << \" URL: \" << url.url() << endl;"; code += "#if 1"; code += "kdDebug(7000) << \" Path: \" << url.path() << endl;"; code += "kdDebug(7000) << \" Query: \" << url.query() << endl;"; code += "kdDebug(7000) << \" Protocol: \" << url.protocol() << endl;"; code += "kdDebug(7000) << \" Filename: \" << url.filename() << endl;"; code += "#endif"; code.newLine(); code += "mimeType( \"text/plain\" );"; code.newLine(); code += "QCString str( \"Hello!\" );"; code += "data( str );"; code.newLine(); code += "finished();"; code.newLine(); code += "kdDebug(7000) << \"" + className + "CgiProtocol::get() done\" << endl;"; get.setBody( code ); c.addFunction( get ); c.addInclude( "kinstance.h" ); c.addInclude( "kdebug.h" ); c.addInclude( "sys/types.h" ); c.addInclude( "unistd.h" ); c.addInclude( "stdlib.h" ); KODE::Function main( "kdemain", "int" ); main.addArgument( "int argc" ); main.addArgument( "char **argv" ); code.clear(); code += "KInstance instance( \"kio_" + protocol + "\" );"; code += ""; code += "kdDebug(7000) << \"Starting kio_" + protocol + "(pid: \" << getpid() << \")\" << endl;"; code += ""; code += "if (argc != 4) {"; code.indent(); code += "fprintf( stderr, \"Usage: kio_" + protocol + " protocol domain-socket1 domain-socket2\\n\");"; code += "exit( -1 );"; code.unindent(); code += "}"; code += ""; code += className + " slave( argv[2], argv[3] );"; code += "slave.dispatchLoop();"; code += ""; code += "return 0;"; main.setBody( code ); file.addFileFunction( main ); file.addExternCDeclaration( p.functionSignature( main ) ); } KODE::Function constructor( className ); if ( args->isSet( "singleton" ) ) { constructor.setAccess( KODE::Function::Private ); KODE::Function self( "self", className + " *" ); self.setStatic( true ); KODE::Code code; code += "if ( !mSelf ) {"; code += " selfDeleter.setObject( mSelf, new " + className + "() );"; code += "}"; code += "return mSelf;"; self.setBody( code ); c.addFunction( self ); KODE::MemberVariable selfVar( "mSelf", className + " *", true ); selfVar.setInitializer( "0" ); c.addMemberVariable( selfVar ); KODE::Variable staticDeleter( "selfDeleter", "KStaticDeleter<" + className + ">", true ); file.addFileVariable( staticDeleter ); file.addInclude( "kstaticdeleter.h" ); } if ( createKioslave ) { constructor.addArgument( "const QCString &pool" ); constructor.addArgument( "const QCString &app" ); constructor.addInitializer( "SlaveBase( \"" + protocol + "\", pool, app )" ); } c.addFunction( constructor ); file.insertClass( c ); p.printHeader( file ); p.printImplementation( file ); if ( createKioslave ) { // Write automake Makefile KODE::AutoMakefile am; am.addEntry( "INCLUDES", "$(all_includes)" ); am.newLine(); am.addEntry( "noinst_HEADERS", className.lower() + ".h" ); am.newLine(); am.addEntry( "METASOURCES", "AUTO" ); am.newLine(); am.addEntry( "kdelnkdir", "$(kde_servicesdir)" ); am.addEntry( "kdelnk_DATA", protocol + ".protocol" ); KODE::AutoMakefile::Target t( "kde_module_LTLIBRARIES", "kio_" + protocol + ".la" ); t.setSources( className.lower() + ".cpp" ); t.setLibAdd( "$(LIB_KIO)" ); t.setLdFlags( "$(all_libraries) -module $(KDE_PLUGIN)" ); am.addTarget( t ); p.printAutoMakefile( am ); // Write protocol file QString protocolFilename = protocol + ".protocol"; QFileInfo fi( protocolFilename ); protocolFilename = fi.absFilePath(); KSaveFile::backupFile( protocolFilename, QString::null, ".backup" ); QFile::remove( protocolFilename ); KSimpleConfig protocolFile( protocolFilename ); protocolFile.setGroup( "Protocol" ); protocolFile.writeEntry( "exec", "kio_" + protocol ); protocolFile.writeEntry( "protocol", protocol ); protocolFile.writeEntry( "input", "none" ); protocolFile.writeEntry( "output", "filesystem" ); protocolFile.writeEntry( "reading", "true" ); protocolFile.writeEntry( "DocPath", "kioslave/" + protocol + ".html" ); protocolFile.sync(); } return 0; } int main(int argc,char **argv) { KAboutData aboutData( "kode", I18N_NOOP("KDE Code Generator"), "0.1" ); aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" ); KCmdLineArgs::init( argc, argv, &aboutData ); KCmdLineArgs::addCmdLineOptions( options ); KApplication app; KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); if ( args->isSet( "create-class" ) || args->isSet( "create-dialog" ) || args->isSet( "create-kioslave" ) || args->isSet( "create-main" ) ) { return create( args ); } else if ( args->isSet( "codify" ) ) { return codify( args ); } else if ( args->isSet( "add-property" ) ) { return addProperty( args ); } else { std::cerr << "Error: No command given." << std::endl; return 1; } } diff --git a/kode/kwsdl/kung/dispatcher.cpp b/kode/kwsdl/kung/dispatcher.cpp index 076a5a64e9..79f6bd949f 100644 --- a/kode/kwsdl/kung/dispatcher.cpp +++ b/kode/kwsdl/kung/dispatcher.cpp @@ -1,153 +1,153 @@ /* This file is part of Kung. Copyright (c) 2005 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "generalconversationmanager.h" #include "inputdialog.h" #include "inputfieldfactory.h" #include "outputdialog.h" #include "pageinputfield.h" #include "transport.h" #include "dispatcher.h" Dispatcher::Dispatcher() : QObject( 0, "Dispatcher" ), mConversationManager( 0 ) { } Dispatcher::~Dispatcher() { delete mConversationManager; mConversationManager = 0; } void Dispatcher::setWSDL( const KWSDL::WSDL &wsdl ) { mWSDL = wsdl; InputFieldFactory::self()->setTypes( mWSDL.types() ); mConversationManager = new GeneralConversationManager( mWSDL ); mTransport = new Transport( mWSDL.service().ports().first().mLocation ); connect( mTransport, SIGNAL( result( const QString& ) ), this, SLOT( result( const QString& ) ) ); connect( mTransport, SIGNAL( error( const QString& ) ), this, SLOT( error( const QString& ) ) ); } void Dispatcher::run() { nextMessage(); } void Dispatcher::nextMessage() { if ( !mConversationManager ) { qDebug( "No conversation manager set... aborting" ); return; } QStringList items = mConversationManager->nextActions( mLastMessage, QString() ); mCurrentMessage = QString(); if ( items.count() > 1 ) { - mCurrentMessage = KInputDialog::getItem( i18n( "Select a functionality of the service" ), i18n( "Functions" ), + mCurrentMessage = KInputDialog::getItem( i18n( "Select a functionality of the service:" ), i18n( "Functions" ), items ); } else mCurrentMessage = items.first(); if ( mCurrentMessage.isEmpty() ) { qApp->quit(); return; } KWSDL::Message message = mWSDL.findMessage( mCurrentMessage ); InputField *field = new PageInputField( message.name(), message ); QWidget *page = field->createWidget( 0 ); InputDialog dlg( page, 0 ); if ( dlg.exec() ) { QDomDocument doc( "kwsdl" ); doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement env = doc.createElement( "SOAP-ENV:Envelope" ); env.setAttribute( "xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/" ); env.setAttribute( "xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance" ); env.setAttribute( "xmlns:xsd", "http://www.w3.org/1999/XMLSchema" ); doc.appendChild( env ); QDomElement body = doc.createElement( "SOAP-ENV:Body" ); env.appendChild( body ); field->xmlData( doc, body ); QDomElement method = body.firstChild().toElement(); QString nameSpace = mWSDL.findBindingOperation( "", message.name() ).input().nameSpace(); method.setAttribute( "xmlns:ns1", "urn:GoogleSearch" ); method.setAttribute( "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/" ); body.appendChild( method ); if ( mTransport ) { qDebug( "%s", doc.toString( 2 ).latin1() ); mTransport->query( doc.toString( 2 ) ); } } else qApp->quit(); } void Dispatcher::result( const QString &xml ) { qDebug( "Got data %s", xml.latin1() ); KWSDL::Message message = mWSDL.findOutputMessage( mCurrentMessage ); InputField *field = new PageInputField( message.name(), message ); QDomDocument doc; doc.setContent( xml, true ); field->setXMLData( doc.documentElement().firstChild().firstChild().toElement() ); QWidget *page = field->createWidget( 0 ); OutputDialog dlg( page, 0 ); dlg.exec(); mLastMessage = mCurrentMessage; QTimer::singleShot( 0, this, SLOT( nextMessage() ) ); } void Dispatcher::error( const QString &errorMsg ) { KMessageBox::error( 0, errorMsg ); QTimer::singleShot( 0, this, SLOT( nextMessage() ) ); } #include "dispatcher.moc" diff --git a/kontact/plugins/specialdates/kcmsdsummary.cpp b/kontact/plugins/specialdates/kcmsdsummary.cpp index 13e29ef21f..5b214ac94f 100644 --- a/kontact/plugins/specialdates/kcmsdsummary.cpp +++ b/kontact/plugins/specialdates/kcmsdsummary.cpp @@ -1,248 +1,248 @@ /* This file is part of Kontact. Copyright (c) 2004 Tobias Koenig Copyright (c) 2004 Allen Winter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kcmsdsummary.h" #include extern "C" { KDE_EXPORT KCModule *create_sdsummary( QWidget *parent, const char * ) { return new KCMSDSummary( parent, "kcmsdsummary" ); } } KCMSDSummary::KCMSDSummary( QWidget *parent, const char *name ) : KCModule( parent, name ) { initGUI(); customDaysChanged( 1 ); connect( mDaysGroup, SIGNAL( clicked( int ) ), SLOT( modified() ) ); connect( mDaysGroup, SIGNAL( clicked( int ) ), SLOT( buttonClicked( int ) ) ); connect( mCalendarGroup, SIGNAL( clicked( int ) ), SLOT( modified() ) ); connect( mContactGroup, SIGNAL( clicked( int ) ), SLOT( modified() ) ); connect( mCustomDays, SIGNAL( valueChanged( int ) ), SLOT( modified() ) ); connect( mCustomDays, SIGNAL( valueChanged( int ) ), SLOT( customDaysChanged( int ) ) ); KAcceleratorManager::manage( this ); load(); } void KCMSDSummary::modified() { emit changed( true ); } void KCMSDSummary::buttonClicked( int id ) { mCustomDays->setEnabled( id == 4 ); } void KCMSDSummary::customDaysChanged( int value ) { mCustomDays->setSuffix( i18n( " day", " days", value ) ); } void KCMSDSummary::initGUI() { QGridLayout *layout = new QGridLayout( this, 3, 2, KDialog::spacingHint() ); mDaysGroup = new QButtonGroup( 0, Vertical, i18n( "Special Dates Summary" ), this ); QVBoxLayout *boxLayout = new QVBoxLayout( mDaysGroup->layout(), KDialog::spacingHint() ); QLabel *label = new QLabel( i18n( "How many days should the special dates summary display at once?" ), mDaysGroup ); boxLayout->addWidget( label ); QRadioButton *button = new QRadioButton( i18n( "One day" ), mDaysGroup ); boxLayout->addWidget( button ); button = new QRadioButton( i18n( "Five days" ), mDaysGroup ); boxLayout->addWidget( button ); button = new QRadioButton( i18n( "One week" ), mDaysGroup ); boxLayout->addWidget( button ); button = new QRadioButton( i18n( "One month" ), mDaysGroup ); boxLayout->addWidget( button ); QHBoxLayout *hbox = new QHBoxLayout( boxLayout, KDialog::spacingHint() ); button = new QRadioButton( "", mDaysGroup ); hbox->addWidget( button ); mCustomDays = new QSpinBox( 1, 365, 1, mDaysGroup ); mCustomDays->setEnabled( false ); hbox->addWidget( mCustomDays ); hbox->addStretch( 1 ); layout->addMultiCellWidget( mDaysGroup, 0, 0, 0, 1 ); - mCalendarGroup = new QButtonGroup( 1, Horizontal, i18n( "Special Dates from Calendar" ), this ); + mCalendarGroup = new QButtonGroup( 1, Horizontal, i18n( "Special Dates From Calendar" ), this ); mShowBirthdaysFromCal = new QCheckBox( i18n( "Show birthdays" ), mCalendarGroup ); mShowAnniversariesFromCal = new QCheckBox( i18n( "Show anniversaries" ), mCalendarGroup ); mShowHolidays = new QCheckBox( i18n( "Show holidays" ), mCalendarGroup ); mShowSpecialsFromCal = new QCheckBox( i18n( "Show special occasions" ), mCalendarGroup ); - mContactGroup = new QButtonGroup( 1, Horizontal, i18n( "Special Dates from Contact List" ), this ); + mContactGroup = new QButtonGroup( 1, Horizontal, i18n( "Special Dates From Contact List" ), this ); mShowBirthdaysFromKAB = new QCheckBox( i18n( "Show birthdays" ), mContactGroup ); mShowAnniversariesFromKAB = new QCheckBox( i18n( "Show anniversaries" ), mContactGroup ); layout->addWidget( mCalendarGroup, 1, 0 ); layout->addWidget( mContactGroup, 1, 1 ); layout->setRowStretch( 2, 1 ); } void KCMSDSummary::load() { KConfig config( "kcmsdsummaryrc" ); config.setGroup( "Days" ); int days = config.readNumEntry( "DaysToShow", 7 ); if ( days == 1 ) mDaysGroup->setButton( 0 ); else if ( days == 5 ) mDaysGroup->setButton( 1 ); else if ( days == 7 ) mDaysGroup->setButton( 2 ); else if ( days == 31 ) mDaysGroup->setButton( 3 ); else { mDaysGroup->setButton( 4 ); mCustomDays->setValue( days ); mCustomDays->setEnabled( true ); } config.setGroup( "EventTypes" ); mShowBirthdaysFromKAB-> setChecked( config.readBoolEntry( "ShowBirthdaysFromContacts", true ) ); mShowBirthdaysFromCal-> setChecked( config.readBoolEntry( "ShowBirthdaysFromCalendar", true ) ); mShowAnniversariesFromKAB-> setChecked( config.readBoolEntry( "ShowAnniversariesFromContacts", true ) ); mShowAnniversariesFromCal-> setChecked( config.readBoolEntry( "ShowAnniversariesFromCalendar", true ) ); mShowHolidays-> setChecked( config.readBoolEntry( "ShowHolidays", true ) ); mShowSpecialsFromCal-> setChecked( config.readBoolEntry( "ShowSpecialsFromCalendar", true ) ); emit changed( false ); } void KCMSDSummary::save() { KConfig config( "kcmsdsummaryrc" ); config.setGroup( "Days" ); int days; switch ( mDaysGroup->selectedId() ) { case 0: days = 1; break; case 1: days = 5; break; case 2: days = 7; break; case 3: days = 31; break; case 4: default: days = mCustomDays->value(); break; } config.writeEntry( "DaysToShow", days ); config.setGroup( "EventTypes" ); config.writeEntry( "ShowBirthdaysFromContacts", mShowBirthdaysFromKAB->isChecked() ); config.writeEntry( "ShowBirthdaysFromCalendar", mShowBirthdaysFromCal->isChecked() ); config.writeEntry( "ShowAnniversariesFromContacts", mShowAnniversariesFromKAB->isChecked() ); config.writeEntry( "ShowAnniversariesFromCalendar", mShowAnniversariesFromCal->isChecked() ); config.writeEntry( "ShowHolidays", mShowHolidays->isChecked() ); config.writeEntry( "ShowSpecialsFromCalendar", mShowSpecialsFromCal->isChecked() ); config.sync(); emit changed( false ); } void KCMSDSummary::defaults() { mDaysGroup->setButton( 7 ); mShowBirthdaysFromKAB->setChecked( true ); mShowBirthdaysFromCal->setChecked( true ); mShowAnniversariesFromKAB->setChecked( true ); mShowAnniversariesFromCal->setChecked( true ); mShowHolidays->setChecked( true ); mShowSpecialsFromCal->setChecked( true ); emit changed( true ); } const KAboutData* KCMSDSummary::aboutData() const { KAboutData *about = new KAboutData( I18N_NOOP( "kcmsdsummary" ), I18N_NOOP( "Special Dates Configuration Dialog" ), 0, 0, KAboutData::License_GPL, I18N_NOOP( "(c) 2004 Tobias Koenig" ) ); about->addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" ); about->addAuthor( "Allen Winter", 0, "winter@kde.org" ); return about; } #include "kcmsdsummary.moc" diff --git a/korganizer/koeditoralarms_base.ui b/korganizer/koeditoralarms_base.ui index 7d3152cbff..3894dfe911 100644 --- a/korganizer/koeditoralarms_base.ui +++ b/korganizer/koeditoralarms_base.ui @@ -1,706 +1,706 @@ KOEditorAlarms_base KOEditorAlarms_base 0 0 400 382 Alarms unnamed 0 groupBox2 Time unnamed layout3 unnamed mAlarmOffset 4 0 0 0 Minutes Hours Days mOffsetUnit Before the Start After the Start Before the End After the End mBeforeAfter layout8 unnamed mHowOftenLabel false 4 5 0 0 &How often: mRepeatCount mRepeatCount false time(s) 500 1 mIntervalLabel false &Interval: mRepeatInterval mRepeats 4 0 0 0 &Repeating: mRepeatInterval false every Minute(s) 999 1 groupBox1 Type unnamed mAlarmType 4 5 0 0 NoFrame 0 true unnamed 0 mTypeDisplayRadio &Display reminder true mTypeSoundRadio &Sound mTypeAppRadio - Application / Script + Application / script mTypeEmailRadio false Send Email spacer2 Vertical Expanding 21 41 line1 VLine Sunken Vertical widgetStack1 WStackPage 0 unnamed 0 mDisplayTextLabel Reminder &text: mDisplayText mDisplayText WStackPage 1 unnamed 0 mSoundFileLabel Sound &file: mSoundFile mSoundFile *.wav|Wav Files;*.mp3|MP3 files;*.*|All files spacer3 Vertical Expanding 20 61 WStackPage 2 unnamed 0 mApplicationLabel &Application / Script: mApplication mApplication *.*|All files mAppArgumentsLabel Ar&guments: mAppArguments mAppArguments spacer3_2 Vertical Expanding 20 16 WStackPage 3 unnamed 0 mEmailTextLabel &Text of the message: mEmailText mEmailText mEmailAddress mEmailToLabel &To: unnamed layout7 unnamed mRemoveButton &Remove... mAddButton &Add pushButton4 D&uplicate spacer1 Vertical Expanding 20 60 Offset true true true true Type true true Repeat true true 15 Minutes before the end Display mAlarmList true AllColumns mAlarmType clicked(int) widgetStack1 raiseWidget(int) mRepeats toggled(bool) mIntervalLabel setEnabled(bool) mRepeats toggled(bool) mRepeatInterval setEnabled(bool) mRepeats toggled(bool) mHowOftenLabel setEnabled(bool) mRepeats toggled(bool) mRepeatCount setEnabled(bool) addresseelineedit.h kurlrequester.h klineedit.h kpushbutton.h kurlrequester.h klineedit.h kpushbutton.h libkdepim/addresseelineedit.h diff --git a/korganizer/printing/calprinter.cpp b/korganizer/printing/calprinter.cpp index 3bc7358aed..d82a1e1ac4 100644 --- a/korganizer/printing/calprinter.cpp +++ b/korganizer/printing/calprinter.cpp @@ -1,272 +1,272 @@ /* This file is part of KOrganizer. Copyright (c) 1998 Preston Brown Copyright (C) 2003-2004 Reinhold Kainhofer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "korganizer/corehelper.h" #include "calprinthelper.h" #include "calprinter.h" #ifndef KORG_NOPRINTER #include "calprinter.moc" #include "calprintdefaultplugins.h" CalPrinter::CalPrinter( QWidget *parent, Calendar *calendar, KOrg::CoreHelper *helper ) : QObject( parent, "CalPrinter" ), mHelper( 0 ) { mParent = parent; mConfig = new KSimpleConfig( "korganizer_printing.rc" ); mCoreHelper = helper; init( new KPrinter, calendar ); } CalPrinter::~CalPrinter() { kdDebug(5850) << "~CalPrinter()" << endl; KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); for ( ; it != mPrintPlugins.end(); ++it ) { (*it)->doSaveConfig(); } mPrintPlugins.clear(); delete mConfig; delete mPrintDialog; delete mPrinter; if ( mHelper ) delete mHelper; } void CalPrinter::init( KPrinter *printer, Calendar *calendar ) { mCalendar = calendar; mPrinter = printer; mPrintPlugins.clear(); mPrintPlugins.setAutoDelete( true ); mPrintPlugins = mCoreHelper->loadPrintPlugins(); mPrintPlugins.prepend( new CalPrintTodos() ); mPrintPlugins.prepend( new CalPrintMonth() ); mPrintPlugins.prepend( new CalPrintWeek() ); mPrintPlugins.prepend( new CalPrintDay() ); mPrintDialog = new CalPrintDialog( mPrintPlugins, mPrinter, mParent ); KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); for ( ; it != mPrintPlugins.end(); ++it ) { (*it)->setConfig( mConfig ); (*it)->setCalendar( calendar ); (*it)->setPrinter( printer ); (*it)->doLoadConfig(); } } void CalPrinter::setDateRange( const QDate &fd, const QDate &td ) { KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); for ( ; it != mPrintPlugins.end(); ++it ) { (*it)->setDateRange( fd, td ); } } void CalPrinter::preview( PrintType type, const QDate &fd, const QDate &td ) { mPrintDialog->setPreview( true ); mPrintDialog->setPrintType( int( type ) ); setDateRange( fd, td ); if ( mPrintDialog->exec() == QDialog::Accepted ) { doPrint( mPrintDialog->selectedPlugin(), true ); } } void CalPrinter::print( PrintType type, const QDate &fd, const QDate &td ) { mPrintDialog->setPreview( false ); mPrintDialog->setPrintType( int( type ) ); setDateRange( fd, td ); if ( mPrintDialog->exec() == QDialog::Accepted ) { doPrint( mPrintDialog->selectedPlugin(), false ); } } void CalPrinter::doPrint( KOrg::PrintPlugin *selectedStyle, bool preview ) { if ( mHelper ) delete mHelper; KPrinter::Orientation printerOrientation = mPrinter->orientation(); mHelper = new CalPrintHelper( mPrinter, mCalendar, mConfig, mCoreHelper ); if ( preview ) mPrinter->setPreviewOnly( true ); switch ( mPrintDialog->orientation() ) { case eOrientPlugin: mPrinter->setOrientation( selectedStyle->orientation() ); break; case eOrientPortrait: mPrinter->setOrientation( KPrinter::Portrait ); break; case eOrientLandscape: mPrinter->setOrientation( KPrinter::Landscape ); break; case eOrientPrinter: default: break; } if ( preview || mPrinter->setup( mParent, i18n("Print Calendar") ) ) { selectedStyle->setKOrgCoreHelper( mCoreHelper ); selectedStyle->setCalPrintHelper( mHelper ); selectedStyle->doPrint(); } mPrinter->setPreviewOnly( false ); mPrinter->setOrientation( printerOrientation ); } /////////////////////////////////////////////////////////////////////////////// void CalPrinter::updateConfig() { } /****************************************************************************/ CalPrintDialog::CalPrintDialog( KOrg::PrintPlugin::List plugins, KPrinter *p, QWidget *parent, const char *name ) : KDialogBase( parent, name, /*modal*/true, i18n("Print"), Ok | Cancel ), mPrinter( p ), mPrintPlugins( plugins ) { QVBox *page = makeVBoxMainWidget(); QSplitter *splitter = new QSplitter( page ); splitter->setOrientation( QSplitter::Horizontal ); mTypeGroup = new QVButtonGroup( i18n("Print Style"), splitter, "buttonGroup" ); // use the minimal width possible = max width of the radio buttons, not extensible /* mTypeGroup->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, mTypeGroup->sizePolicy().hasHeightForWidth() ) );*/ QWidget *splitterRight = new QWidget( splitter, "splitterRight" ); QGridLayout *splitterRightLayout = new QGridLayout( splitterRight ); splitterRightLayout->setMargin( marginHint() ); splitterRightLayout->setSpacing( spacingHint() ); mConfigArea = new QWidgetStack( splitterRight, "configWidgetStack" ); splitterRightLayout->addMultiCellWidget( mConfigArea, 0,0, 0,1 ); QLabel *orientationLabel = new QLabel( i18n("Page &orientation:"), splitterRight, "orientationLabel" ); splitterRightLayout->addWidget( orientationLabel, 1, 0 ); mOrientationSelection = new QComboBox( splitterRight, "orientationCombo" ); mOrientationSelection->insertItem( i18n("Use Default Orientation of Selected Style") ); - mOrientationSelection->insertItem( i18n("Use printer default") ); + mOrientationSelection->insertItem( i18n("Use Printer Default") ); mOrientationSelection->insertItem( i18n("Portrait") ); mOrientationSelection->insertItem( i18n("Landscape") ); splitterRightLayout->addWidget( mOrientationSelection, 1, 1 ); // signals and slots connections connect( mTypeGroup, SIGNAL( clicked( int ) ), SLOT( setPrintType( int ) ) ); // buddies orientationLabel->setBuddy( mOrientationSelection ); KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); QRadioButton *radioButton; int id = 0; for ( ; it != mPrintPlugins.end(); ++it ) { radioButton = new QRadioButton( (*it)->description(), mTypeGroup ); mTypeGroup->insert( radioButton, id ); radioButton->setMinimumHeight( radioButton->sizeHint().height() - 5 ); mConfigArea->addWidget( (*it)->configWidget( mConfigArea ), id ); id++; } setMinimumSize( minimumSizeHint() ); resize( minimumSizeHint() ); } CalPrintDialog::~CalPrintDialog() { } void CalPrintDialog::setPreview(bool preview) { #if KDE_IS_VERSION( 3, 1, 93 ) setButtonOK( preview ? i18n("&Preview") : KStdGuiItem::print() ); #else setButtonOKText( preview ? i18n("&Preview") : i18n("&Print...") ); #endif } void CalPrintDialog::setPrintType( int i ) { // FIXME: Make a safe correlation between type and the radio button mTypeGroup->setButton( i ); mConfigArea->raiseWidget( i ); } KOrg::PrintPlugin *CalPrintDialog::selectedPlugin() { int pos = mTypeGroup->id( mTypeGroup->selected() ); if ( pos < 0 ) return 0; KOrg::PrintPlugin *retval = mPrintPlugins.at( pos ); return retval; } void CalPrintDialog::slotOk() { mOrientation = (CalPrinter::ePrintOrientation)mOrientationSelection->currentItem(); KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); for ( ; it != mPrintPlugins.end(); ++it ) { (*it)->readSettingsWidget(); } KDialogBase::slotOk(); } #endif diff --git a/korganizer/template_management_dialog_base.ui b/korganizer/template_management_dialog_base.ui index 153ec3f74f..093ff3c5ac 100644 --- a/korganizer/template_management_dialog_base.ui +++ b/korganizer/template_management_dialog_base.ui @@ -1,93 +1,93 @@ TemplateManagementDialog_base TemplateManagementDialog_base 0 0 355 272 Template Management unnamed 0 m_listBox m_buttonAdd &New m_buttonDelete false Delete m_introLabel NoFrame Select a template and click <b>Apply Template</b> to apply it to the current event or task. Click <b>New</b> to create a new template based on the current event or task. m_buttonApply - Apply template + Apply Template spacer1 Vertical Expanding 20 51 klistbox.h diff --git a/korganizer/templatemanagementdialog.cpp b/korganizer/templatemanagementdialog.cpp index ab9528bd5d..5d31f7fb16 100644 --- a/korganizer/templatemanagementdialog.cpp +++ b/korganizer/templatemanagementdialog.cpp @@ -1,133 +1,133 @@ /******************************************************************************* ** ** Filename : templatemanagementdialog.cpp ** Created on : 05 June, 2005 ** Copyright : (c) 2005 Till Adam ** Email : ** *******************************************************************************/ /******************************************************************************* ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** It 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. See the GNU ** General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ** ** In addition, as a special exception, the copyright holders give ** permission to link the code of this program with any edition of ** the Qt library by Trolltech AS, Norway (or with modified versions ** of Qt that use the same license as Qt), and distribute linked ** combinations including the two. You must obey the GNU General ** Public License in all respects for all of the code used other than ** Qt. If you modify this file, you may extend this exception to ** your version of the file, but you are not obligated to do so. If ** you do not wish to do so, delete this exception statement from ** your version. ** *******************************************************************************/ #include "templatemanagementdialog.h" #include #include #include #include #include #include TemplateManagementDialog::TemplateManagementDialog(QWidget *parent, const QStringList &templates ) :KDialogBase( parent, "template_management_dialog", true, i18n("Manage Templates"), Ok|Cancel, Ok, true , i18n("Apply Template")), m_templates( templates ), m_newTemplate( QString::null ), m_changed( false ) { m_base = new TemplateManagementDialog_base( this, "template_management_dialog_base" ); setMainWidget( m_base ); connect( m_base->m_buttonAdd, SIGNAL( clicked() ), SLOT( slotAddTemplate() ) ); connect( m_base->m_buttonDelete, SIGNAL( clicked() ), SLOT( slotDeleteTemplate() ) ); m_base->m_listBox->insertStringList( m_templates ); connect( m_base->m_listBox, SIGNAL( selectionChanged( QListBoxItem * ) ), SLOT( slotUpdateDeleteButton( QListBoxItem * ) ) ); connect( m_base->m_buttonApply, SIGNAL( clicked() ), SLOT( slotApplyTemplate() ) ); } void TemplateManagementDialog::slotAddTemplate() { bool ok; bool duplicate = false; const QString newTemplate = KInputDialog::getText( i18n("Template Name"), - i18n("Please enter a name for the new template"), + i18n("Please enter a name for the new template:"), i18n("New Template"), &ok ); if ( newTemplate.isEmpty() || !ok ) return; if ( m_templates.find( newTemplate) != m_templates.end() ) { int rc = KMessageBox::warningContinueCancel( this, i18n("A template with that name already exists, do you want to overwrite it?."), i18n("Duplicate Template Name"), i18n("Overwrite")); if ( rc == KMessageBox::Cancel ) { QTimer::singleShot(0, this, SLOT( slotAddTemplate() ) ); return; } duplicate = true; } if ( !duplicate ) { m_templates.append( newTemplate ); m_base->m_listBox->clear(); m_base->m_listBox->insertStringList( m_templates ); } m_newTemplate = newTemplate; m_changed = true; // From this point on we need to keep the original event around until the user has // closed the dialog, applying a template would make little sense m_base->m_buttonApply->setEnabled( false ); // neither does adding it again m_base->m_buttonAdd->setEnabled( false ); } void TemplateManagementDialog::slotDeleteTemplate() { QListBoxItem *const item = m_base->m_listBox->selectedItem(); if ( !item ) return; // can't happen (TM) unsigned int current = m_base->m_listBox->index(item); m_templates.remove( item->text() ); m_base->m_listBox->removeItem( m_base->m_listBox->currentItem() ); m_changed = true; m_base->m_listBox->setSelected(QMAX(current -1, 0), true); } void TemplateManagementDialog::slotUpdateDeleteButton( QListBoxItem *item ) { m_base->m_buttonDelete->setEnabled( item != 0 ); } void TemplateManagementDialog::slotApplyTemplate() { // Once the user has applied the current template to the event, it makes no sense to add it again m_base->m_buttonAdd->setEnabled( false ); const QString &cur = m_base->m_listBox->currentText(); if ( !cur.isEmpty() && cur != m_newTemplate ) emit loadTemplate( cur ); } void TemplateManagementDialog::slotOk() { // failure is not an option *cough* if ( !m_newTemplate.isEmpty() ) emit saveTemplate( m_newTemplate ); if ( m_changed ) emit templatesChanged( m_templates ); KDialogBase::slotOk(); } #include "templatemanagementdialog.moc" diff --git a/korn/kornaccountcfg.ui b/korn/kornaccountcfg.ui index 773a9da842..18b0682912 100644 --- a/korn/kornaccountcfg.ui +++ b/korn/kornaccountcfg.ui @@ -1,252 +1,249 @@ KornAccountCfg KornAccountCfg 0 0 472 471 - - KornAccountCfg - unnamed tab server_tab &Server lbProtocol 11 41 206 24 &Protocol: cbProtocol cbProtocol 223 41 206 24 TabPage &Account unnamed layout35 unnamed lbInterval C&heck every (sec): edInterval edInterval TabPage &Events unnamed chUseBox &Use settings of box true gbNewMail false On New Mail unnamed layout33 unnamed edRunCommand lbRunCommand Run &command: edRunCommand edPlaySound lbPlaySound Play sou&nd: edPlaySound chPassivePopup Show &passive popup chPassiveDate false Add &date to passive popup chUseBox toggled(bool) gbNewMail setDisabled(bool) chPassivePopup toggled(bool) chPassiveDate setEnabled(bool) cbProtocol activated(const QString&) KornAccountCfg slotProtocolChanged(const QString&) tab edInterval chUseBox edRunCommand edPlaySound chPassivePopup chPassiveDate slotProtocolChanged( const QString& ) kurlrequester.h klineedit.h kpushbutton.h kurlrequester.h klineedit.h kpushbutton.h diff --git a/libkcal/resourcecachedconfig.cpp b/libkcal/resourcecachedconfig.cpp index 479e3fedf8..0e9807486a 100644 --- a/libkcal/resourcecachedconfig.cpp +++ b/libkcal/resourcecachedconfig.cpp @@ -1,120 +1,120 @@ /* This file is part of libkcal. Copyright (c) 2004 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "resourcecached.h" #include "resourcecachedconfig.h" using namespace KCal; ResourceCachedReloadConfig::ResourceCachedReloadConfig( QWidget *parent, const char *name ) : QWidget( parent, name ) { QBoxLayout *topLayout = new QVBoxLayout( this ); mGroup = new QButtonGroup( 1, Horizontal, i18n("Automatic Reload"), this ); topLayout->addWidget( mGroup ); new QRadioButton( i18n("Never"), mGroup ); new QRadioButton( i18n("On startup"), mGroup ); - QRadioButton *intervalRadio = new QRadioButton( i18n("Regular Interval"), + QRadioButton *intervalRadio = new QRadioButton( i18n("Regular interval"), mGroup ); connect( intervalRadio, SIGNAL( stateChanged( int ) ), SLOT( slotIntervalStateChanged( int ) ) ); QHBox *intervalBox = new QHBox( mGroup ); new QLabel( i18n("Interval in minutes"), intervalBox ); mIntervalSpin = new QSpinBox( intervalBox ); mIntervalSpin->setEnabled( false ); } void ResourceCachedReloadConfig::loadSettings( ResourceCached *resource ) { mGroup->setButton( resource->reloadPolicy() ); mIntervalSpin->setValue( resource->reloadInterval() ); } void ResourceCachedReloadConfig::saveSettings( ResourceCached *resource ) { resource->setReloadPolicy( mGroup->selectedId() ); resource->setReloadInterval( mIntervalSpin->value() ); } void ResourceCachedReloadConfig::slotIntervalStateChanged( int state ) { if ( state == QButton::On ) mIntervalSpin->setEnabled( true ); else mIntervalSpin->setEnabled( false ); } ResourceCachedSaveConfig::ResourceCachedSaveConfig( QWidget *parent, const char *name ) : QWidget( parent, name ) { QBoxLayout *topLayout = new QVBoxLayout( this ); mGroup = new QButtonGroup( 1, Horizontal, i18n("Automatic Save"), this ); topLayout->addWidget( mGroup ); new QRadioButton( i18n("Never"), mGroup ); new QRadioButton( i18n("On exit"), mGroup ); - QRadioButton *intervalRadio = new QRadioButton( i18n("Regular Interval"), + QRadioButton *intervalRadio = new QRadioButton( i18n("Regular interval"), mGroup ); connect( intervalRadio, SIGNAL( stateChanged( int ) ), SLOT( slotIntervalStateChanged( int ) ) ); QHBox *intervalBox = new QHBox( mGroup ); new QLabel( i18n("Interval in minutes"), intervalBox ); mIntervalSpin = new QSpinBox( intervalBox ); mIntervalSpin->setEnabled( false ); new QRadioButton( i18n("Delayed after changes"), mGroup ); new QRadioButton( i18n("On every change"), mGroup ); } void ResourceCachedSaveConfig::loadSettings( ResourceCached *resource ) { mGroup->setButton( resource->savePolicy() ); mIntervalSpin->setValue( resource->saveInterval() ); } void ResourceCachedSaveConfig::saveSettings( ResourceCached *resource ) { resource->setSavePolicy( mGroup->selectedId() ); resource->setSaveInterval( mIntervalSpin->value() ); } void ResourceCachedSaveConfig::slotIntervalStateChanged( int state ) { if ( state == QButton::On ) mIntervalSpin->setEnabled( true ); else mIntervalSpin->setEnabled( false ); } #include "resourcecachedconfig.moc"