diff options
-rw-r--r-- | SwifTools/AutoUpdater/AutoUpdater.h | 3 | ||||
-rw-r--r-- | SwifTools/AutoUpdater/SparkleAutoUpdater.h | 3 | ||||
-rw-r--r-- | SwifTools/AutoUpdater/SparkleAutoUpdater.mm | 9 | ||||
-rw-r--r-- | Swift/QtUI/QtAboutWidget.cpp | 54 | ||||
-rw-r--r-- | Swift/QtUI/QtAboutWidget.h | 15 | ||||
-rw-r--r-- | Swift/QtUI/QtLoginWindow.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtSwift.cpp | 37 | ||||
-rw-r--r-- | Swift/QtUI/QtSwift.h | 1 | ||||
-rw-r--r-- | Swift/QtUI/QtUISettingConstants.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtUISettingConstants.h | 9 | ||||
-rw-r--r-- | Swift/QtUI/QtUpdateFeedSelectionDialog.cpp | 83 | ||||
-rw-r--r-- | Swift/QtUI/QtUpdateFeedSelectionDialog.h | 30 | ||||
-rw-r--r-- | Swift/QtUI/QtUpdateFeedSelectionDialog.ui | 146 | ||||
-rw-r--r-- | Swift/QtUI/SConscript | 2 | ||||
-rw-r--r-- | Swift/QtUI/SwiftUpdateFeeds.h | 29 |
15 files changed, 411 insertions, 16 deletions
diff --git a/SwifTools/AutoUpdater/AutoUpdater.h b/SwifTools/AutoUpdater/AutoUpdater.h index ed53e11..274bf50 100644 --- a/SwifTools/AutoUpdater/AutoUpdater.h +++ b/SwifTools/AutoUpdater/AutoUpdater.h @@ -1,27 +1,30 @@ /* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <string> + #include <boost/signals2.hpp> namespace Swift { class AutoUpdater { public: virtual ~AutoUpdater(); + virtual void setAppcastFeed(const std::string& appcastFeed) = 0; virtual void checkForUpdates() = 0; virtual bool recommendRestartToUpdate() = 0; public: /** * Emit this signal if a new version of the software has been downloaded * and the user needs to be notified so they can quit the app and start * the newer version. */ boost::signals2::signal<void()> onSuggestRestartToUserToUpdate; }; } diff --git a/SwifTools/AutoUpdater/SparkleAutoUpdater.h b/SwifTools/AutoUpdater/SparkleAutoUpdater.h index 41a25f0..dd22e73 100644 --- a/SwifTools/AutoUpdater/SparkleAutoUpdater.h +++ b/SwifTools/AutoUpdater/SparkleAutoUpdater.h @@ -1,33 +1,34 @@ /* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once #include <memory> #include <string> #include <SwifTools/AutoUpdater/AutoUpdater.h> namespace Swift { /** * @brief The SparkleAutoUpdater class provides integration with Sparkle. * This enables automatic silent background updates. If using this in Qt you * need to emit a NSApplicationWillTerminateNotification before you quit * the application. */ class SparkleAutoUpdater : public AutoUpdater { public: - SparkleAutoUpdater(const std::string& url); + SparkleAutoUpdater(const std::string& appcastFeed); ~SparkleAutoUpdater(); + void setAppcastFeed(const std::string& appcastFeed); void checkForUpdates(); bool recommendRestartToUpdate(); private: class Private; const std::unique_ptr<Private> d; }; } diff --git a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm index 6b27ba7..ed5f094 100644 --- a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm +++ b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm @@ -1,57 +1,62 @@ /* * Copyright (c) 2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <SwifTools/AutoUpdater/SparkleAutoUpdater.h> #include <Cocoa/Cocoa.h> #include <Sparkle/Sparkle.h> #include <SwifTools/AutoUpdater/SparkleAutoUpdaterDelegate.h> #include <SwifTools/Cocoa/CocoaUtil.h> namespace Swift { class SparkleAutoUpdater::Private { public: SUUpdater* updater; boost::intrusive_ptr<SparkleAutoUpdaterDelegate> delegate; bool restartToUpdate = false; }; -SparkleAutoUpdater::SparkleAutoUpdater(const std::string& url) : d(new Private()) { +SparkleAutoUpdater::SparkleAutoUpdater(const std::string& appcastFeed) : d(new Private()) { d->updater = [SUUpdater sharedUpdater]; [d->updater retain]; d->delegate = boost::intrusive_ptr<SparkleAutoUpdaterDelegate>([[SparkleAutoUpdaterDelegate alloc] init], false); [d->delegate.get() setUpdateDownloadFinished: [&](){ d->restartToUpdate = true; onSuggestRestartToUserToUpdate(); }]; [d->updater setDelegate: d->delegate.get()]; [d->updater setAutomaticallyChecksForUpdates: true]; // Automatically check for an update after a day. [d->updater setUpdateCheckInterval: 86400]; [d->updater setAutomaticallyDownloadsUpdates: true]; - NSURL* nsurl = [NSURL URLWithString: std2NSString(url)]; + NSURL* nsurl = [NSURL URLWithString: std2NSString(appcastFeed)]; [d->updater setFeedURL: nsurl]; } SparkleAutoUpdater::~SparkleAutoUpdater() { [d->updater release]; } +void SparkleAutoUpdater::setAppcastFeed(const std::string& appcastFeed) { + NSURL* nsurl = [NSURL URLWithString: std2NSString(appcastFeed)]; + [d->updater setFeedURL: nsurl]; +} + void SparkleAutoUpdater::checkForUpdates() { //[d->updater resetUpdateCycle]; // This is useful for testing to force a check ot start. [d->updater checkForUpdatesInBackground]; } bool SparkleAutoUpdater::recommendRestartToUpdate() { return d->restartToUpdate; } } diff --git a/Swift/QtUI/QtAboutWidget.cpp b/Swift/QtUI/QtAboutWidget.cpp index d90e35a..9047525 100644 --- a/Swift/QtUI/QtAboutWidget.cpp +++ b/Swift/QtUI/QtAboutWidget.cpp @@ -1,111 +1,163 @@ /* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swift/QtUI/QtAboutWidget.h> #include <QCoreApplication> #include <QFile> #include <QIcon> #include <QLabel> #include <QPushButton> #include <QTextEdit> #include <QTextStream> #include <QVBoxLayout> #include <QtGlobal> #include <Swiften/Base/Log.h> #include <Swiften/Base/Platform.h> #include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtUISettingConstants.h> +#include <Swift/QtUI/QtUpdateFeedSelectionDialog.h> +#include <Swift/QtUI/SwiftUpdateFeeds.h> namespace Swift { -QtAboutWidget::QtAboutWidget() : QDialog() { +QtAboutWidget::QtAboutWidget(SettingsProvider* settingsProvider) : QDialog(), settingsProvider_(settingsProvider) { #ifndef Q_OS_MAC setWindowTitle(QString(tr("About %1")).arg("Swift")); #endif setWindowIcon(QIcon(":/logo-icon-16.png")); resize(180, 240); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setAlignment(Qt::AlignHCenter); setLayout(mainLayout); QLabel* iconLabel = new QLabel(this); iconLabel->setPixmap(QIcon(":/logo-shaded-text.256.png").pixmap(90, 90)); iconLabel->setAlignment(Qt::AlignHCenter); mainLayout->addWidget(iconLabel); QLabel* appNameLabel = new QLabel("<center><font size='+1'><b>" + QCoreApplication::applicationName() + "</b></font></center>", this); mainLayout->addWidget(appNameLabel); QLabel* versionLabel = new QLabel((QString("<center><font size='-1'>") + tr("Version %1") + "</font></center><center><font size='-1'><br/>" + QString(tr("Built with Qt %2")) + QString("<br/>") + QString(tr("Running with Qt %3")) + "</font></center>").arg(QCoreApplication::applicationVersion()).arg(QT_VERSION_STR).arg(qVersion())); versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); mainLayout->addWidget(versionLabel); + settingsChangedConnection_ = settingsProvider_->onSettingChanged.connect([&](const std::string& path) { + if (path == QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL.getKey() || path == QtUISettingConstants::ENABLE_SOFTWARE_UPDATES.getKey()) { + updateUpdateInfoLabel(); + } + }); + + updateInfoLabel_ = new QLabel("", this); + updateInfoLabel_->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse); + connect(updateInfoLabel_, SIGNAL(linkActivated(const QString &)), this, SLOT(handleChangeUpdateChannelClicked())); + mainLayout->addWidget(updateInfoLabel_); + + updateUpdateInfoLabel(); + if (QCoreApplication::translate("TRANSLATION_INFO", "TRANSLATION_AUTHOR") != "TRANSLATION_AUTHOR") { mainLayout->addWidget(new QLabel(QString("<center><font size='-1'>") + QString(tr("Using the English translation by\n%1")).arg(QCoreApplication::translate("TRANSLATION_INFO", "TRANSLATION_AUTHOR")).replace("\n", "<br/>") + "</font></center>", this)); } QCoreApplication::translate("TRANSLATION_INFO", "TRANSLATION_LICENSE", "This string contains the license under which this translation is licensed. We ask you to license the translation under the BSD license. Please read http://www.opensource.org/licenses/bsd-license.php, and if you agree to release your translation under this license, use the following (untranslated) text: 'This translation is licensed under the BSD License. See http://www.opensource.org/licenses/bsd-license.php'"); #if defined(SWIFTEN_PLATFORM_WINDOWS) || defined(SWIFTEN_PLATFORM_MACOSX) QPushButton* licenseButton = new QPushButton(tr("View License"), this); mainLayout->addWidget(licenseButton); connect(licenseButton, SIGNAL(clicked()), this, SLOT(handleLicenseClicked())); QPushButton* changelogButton = new QPushButton(tr("View Changes"), this); mainLayout->addWidget(changelogButton); connect(changelogButton, SIGNAL(clicked()), this, SLOT(handleChangelogClicked())); #else // Some Linux desktops have dialog window decorations without close window buttons. // This code adds a dedicated button to close the about window dialog. QHBoxLayout* buttonLayout = new QHBoxLayout(); mainLayout->addLayout(buttonLayout); QPushButton* licenseButton = new QPushButton(tr("View License"), this); buttonLayout->addWidget(licenseButton); connect(licenseButton, SIGNAL(clicked()), this, SLOT(handleLicenseClicked())); QPushButton* changelogButton = new QPushButton(tr("View Changes"), this); buttonLayout->addWidget(changelogButton); connect(changelogButton, SIGNAL(clicked()), this, SLOT(handleChangelogClicked())); buttonLayout->addItem(new QSpacerItem(20,20)); QPushButton* closeButton = new QPushButton(tr("Close"), this); buttonLayout->addWidget(closeButton); connect(closeButton, SIGNAL(clicked()), this, SLOT(accept())); #endif setFixedSize(minimumSizeHint()); } void QtAboutWidget::handleLicenseClicked() { openPlainTextWindow(":/COPYING"); } void QtAboutWidget::handleChangelogClicked() { openPlainTextWindow(":/ChangeLog.md"); } +void QtAboutWidget::handleChangeUpdateChannelClicked() { + auto feedSelectionDialog = new QtUpdateFeedSelectionDialog(settingsProvider_); + feedSelectionDialog->show(); +} + void QtAboutWidget::openPlainTextWindow(const QString& path) { QTextEdit* text = new QTextEdit(); text->setAttribute(Qt::WA_DeleteOnClose); text->setReadOnly(true); QFile file(path); if (file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); text->setPlainText(in.readAll()); file.close(); text->resize(500, 600); text->show(); text->activateWindow(); } else { SWIFT_LOG(error) << "Failed to open " << Q2PSTRING(path) << "." << std::endl; } } +void QtAboutWidget::updateUpdateInfoLabel() { + if (settingsProvider_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES)) { + if (!settingsProvider_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL).empty()) { + QString updateFeedDescription; + auto addUpdateFeedDialogLink = false; + if (settingsProvider_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL) == UpdateFeeds::StableChannel) { + updateFeedDescription = tr("You are receiving updates from the Stable update channel."); + addUpdateFeedDialogLink = true; + } + else if (settingsProvider_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL) == UpdateFeeds::DevelopmentChannel) { + updateFeedDescription = tr("You are receiving updates from the Development update channel."); + addUpdateFeedDialogLink = true; + } + else if (settingsProvider_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL) == UpdateFeeds::TestingChannel) { + updateFeedDescription = tr("You are receiving updates from the Testing update channel."); + addUpdateFeedDialogLink = true; + } + auto updateFeedDialogLink = QString( addUpdateFeedDialogLink ? "<a href=\"#\">%1</a>" : "" ).arg(tr("Change the update channel.")); + updateInfoLabel_->setText(QString("<center><font size='-1'>%1<br/>%2</font></center>").arg(updateFeedDescription, updateFeedDialogLink)); + updateInfoLabel_->show(); + } + else { + updateInfoLabel_->hide(); + } + } + else { + updateInfoLabel_->hide(); + } + +} + } diff --git a/Swift/QtUI/QtAboutWidget.h b/Swift/QtUI/QtAboutWidget.h index c8b0356..fb54c6e 100644 --- a/Swift/QtUI/QtAboutWidget.h +++ b/Swift/QtUI/QtAboutWidget.h @@ -1,25 +1,38 @@ /* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <boost/signals2/connection.hpp> + #include <QDialog> +class QLabel; + namespace Swift { + class SettingsProvider; + class QtAboutWidget : public QDialog { Q_OBJECT public: - QtAboutWidget(); + QtAboutWidget(SettingsProvider* settings); private slots: void handleLicenseClicked(); void handleChangelogClicked(); + void handleChangeUpdateChannelClicked(); private: void openPlainTextWindow(const QString& path); + void updateUpdateInfoLabel(); + + private: + SettingsProvider* settingsProvider_; + QLabel* updateInfoLabel_ = nullptr; + boost::signals2::scoped_connection settingsChangedConnection_; }; } diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp index 6e9510d..d91f694 100644 --- a/Swift/QtUI/QtLoginWindow.cpp +++ b/Swift/QtUI/QtLoginWindow.cpp @@ -415,61 +415,61 @@ void QtLoginWindow::loginClicked() { } else { onCancelLoginRequest(); } } void QtLoginWindow::setLoginAutomatically(bool loginAutomatically) { loginAutomatically_->setChecked(loginAutomatically); } void QtLoginWindow::handleCertficateChecked(bool checked) { if (checked) { #ifdef HAVE_SCHANNEL certificateFile_ = P2QSTRING(selectCAPICertificate()); if (certificateFile_.isEmpty()) { certificateButton_->setChecked(false); } #else certificateFile_ = QFileDialog::getOpenFileName(this, tr("Select an authentication certificate"), QString(), tr("P12 files (*.cert *.p12 *.pfx);;All files (*.*)")); if (certificateFile_.isEmpty()) { certificateButton_->setChecked(false); } #endif } else { certificateFile_ = ""; } } void QtLoginWindow::handleAbout() { if (!aboutDialog_) { - aboutDialog_ = new QtAboutWidget(); + aboutDialog_ = new QtAboutWidget(settings_); aboutDialog_->show(); } else { aboutDialog_->show(); aboutDialog_->raise(); aboutDialog_->activateWindow(); } } void QtLoginWindow::handleShowXMLConsole() { uiEventStream_->send(std::make_shared<RequestXMLConsoleUIEvent>()); } void QtLoginWindow::handleShowFileTransferOverview() { uiEventStream_->send(std::make_shared<RequestFileTransferListUIEvent>()); } void QtLoginWindow::handleShowHighlightEditor() { uiEventStream_->send(std::make_shared<RequestHighlightEditorUIEvent>()); } void QtLoginWindow::handleToggleSounds(bool enabled) { settings_->storeSetting(SettingConstants::PLAY_SOUNDS, enabled); } void QtLoginWindow::handleToggleNotifications(bool enabled) { settings_->storeSetting(SettingConstants::SHOW_NOTIFICATIONS, enabled); } void QtLoginWindow::handleQuit() { diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 3aff999..3f6ce8e 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -24,150 +24,161 @@ #include <Swiften/Base/Platform.h> #include <Swiften/Client/Client.h> #include <Swiften/Elements/Presence.h> #include <Swiften/TLS/TLSContextFactory.h> #include <SwifTools/Application/PlatformApplicationPathProvider.h> #include <SwifTools/AutoUpdater/AutoUpdater.h> #include <SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h> #include <Swift/Controllers/ApplicationInfo.h> #include <Swift/Controllers/BuildVersion.h> #include <Swift/Controllers/MainController.h> #include <Swift/Controllers/SettingConstants.h> #include <Swift/Controllers/Settings/SettingsProviderHierachy.h> #include <Swift/Controllers/Settings/XMLSettingsProvider.h> #include <Swift/Controllers/StatusCache.h> #include <Swift/Controllers/Storages/CertificateFileStorageFactory.h> #include <Swift/Controllers/Storages/FileStoragesFactory.h> #include <Swift/QtUI/QtChatTabs.h> #include <Swift/QtUI/QtChatTabsBase.h> #include <Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h> #include <Swift/QtUI/QtChatWindowFactory.h> #include <Swift/QtUI/QtLoginWindow.h> #include <Swift/QtUI/QtSingleWindow.h> #include <Swift/QtUI/QtSoundPlayer.h> #include <Swift/QtUI/QtSwiftUtil.h> #include <Swift/QtUI/QtSystemTray.h> #include <Swift/QtUI/QtUIFactory.h> #include <Swift/QtUI/QtUISettingConstants.h> +#include <Swift/QtUI/SwiftUpdateFeeds.h> #if defined(SWIFTEN_PLATFORM_WINDOWS) #include <Swift/QtUI/WindowsNotifier.h> #elif defined(HAVE_GROWL) #include <SwifTools/Notifier/GrowlNotifier.h> #elif defined(SWIFTEN_PLATFORM_LINUX) #include <Swift/QtUI/FreeDesktopNotifier.h> #elif defined(SWIFTEN_PLATFORM_MACOSX) #include <SwifTools/Notifier/NotificationCenterNotifier.h> #else #include <SwifTools/Notifier/NullNotifier.h> #endif #if defined(SWIFTEN_PLATFORM_MACOSX) #include <SwifTools/Dock/MacOSXDock.h> #else #include <SwifTools/Dock/NullDock.h> #endif #if defined(SWIFTEN_PLATFORM_MACOSX) #include <Swift/QtUI/QtURIHandler.h> #elif defined(SWIFTEN_PLATFORM_WIN32) #include <SwifTools/URIHandler/NullURIHandler.h> #else #include <Swift/QtUI/QtDBUSURIHandler.h> #endif #if defined(SWIFTEN_PLATFORM_MACOSX) #include <Swift/QtUI/CocoaUIHelpers.h> #endif namespace Swift{ -#if defined(SWIFTEN_PLATFORM_MACOSX) -#define SWIFT_APPCAST_URL "https://swift.im/appcast/swift-mac-dev.xml" -#else -#define SWIFT_APPCAST_URL "" -#endif - po::options_description QtSwift::getOptionsDescription() { po::options_description result("Options"); result.add_options() ("debug", "Turn on debug logging") ("help", "Show this help message") ("version", "Show version information") ("netbook-mode", "Use netbook mode display (unsupported)") ("no-tabs", "Don't manage chat windows in tabs (unsupported)") ("latency-debug", "Use latency debugging (unsupported)") ("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)") ("start-minimized", "Don't show the login/roster window at startup") ("enable-jid-adhocs", "Enable AdHoc commands to custom JID's.") #if QT_VERSION >= 0x040800 ("language", po::value<std::string>(), "Use a specific language, instead of the system-wide one") #endif ; return result; } XMLSettingsProvider* QtSwift::loadSettingsFile(const QString& fileName) { QFile configFile(fileName); if (configFile.exists() && configFile.open(QIODevice::ReadOnly)) { QString xmlString; while (!configFile.atEnd()) { QByteArray line = configFile.readLine(); xmlString += line + "\n"; } return new XMLSettingsProvider(Q2PSTRING(xmlString)); } return new XMLSettingsProvider(""); } void QtSwift::loadEmoticonsFile(const QString& fileName, std::map<std::string, std::string>& emoticons) { QFile file(fileName); if (file.exists() && file.open(QIODevice::ReadOnly)) { while (!file.atEnd()) { QString line = file.readLine(); line.replace("\n", ""); line.replace("\r", ""); QStringList tokens = line.split(" "); if (tokens.size() == 2) { QString emoticonFile = tokens[1]; if (!emoticonFile.startsWith(":/") && !emoticonFile.startsWith("qrc:/")) { emoticonFile = "file://" + emoticonFile; } emoticons[Q2PSTRING(tokens[0])] = Q2PSTRING(emoticonFile); } } } } +const std::string& QtSwift::updateChannelToFeed(const std::string& channel) { + static const std::string invalidChannel; + if (channel == UpdateFeeds::StableChannel) { + return UpdateFeeds::StableAppcastFeed; + } + else if (channel == UpdateFeeds::TestingChannel) { + return UpdateFeeds::TestingAppcastFeed; + } + else if (channel == UpdateFeeds::DevelopmentChannel) { + return UpdateFeeds::DevelopmentAppcastFeed; + } + else { + return invalidChannel; + } +} + QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(nullptr), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) { QCoreApplication::setApplicationName(SWIFT_APPLICATION_NAME); QCoreApplication::setOrganizationName(SWIFT_ORGANIZATION_NAME); QCoreApplication::setOrganizationDomain(SWIFT_ORGANIZATION_DOMAIN); QCoreApplication::setApplicationVersion(buildVersion); qtSettings_ = new QtSettingsProvider(); xmlSettings_ = loadSettingsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "system-settings.xml"))); settingsHierachy_ = new SettingsProviderHierachy(); settingsHierachy_->addProviderToTopOfStack(xmlSettings_); settingsHierachy_->addProviderToTopOfStack(qtSettings_); networkFactories_.getTLSContextFactory()->setDisconnectOnCardRemoval(settingsHierachy_->getSetting(SettingConstants::DISCONNECT_ON_CARD_REMOVAL)); std::map<std::string, std::string> emoticons; loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons); loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons); if (options.count("netbook-mode")) { splitter_ = new QtSingleWindow(qtSettings_); } else { splitter_ = nullptr; } int numberOfAccounts = 1; try { numberOfAccounts = options["multi-account"].as<int>(); } catch (...) { /* This seems to fail on a Mac when the .app is launched directly (the usual path).*/ numberOfAccounts = 1; @@ -258,77 +269,85 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa } for (int i = 0; i < numberOfAccounts; i++) { if (i > 0) { // Don't add the first tray (see note above) systemTrays_.push_back(new QtSystemTray()); } QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, networkFactories_.getTimerFactory(), statusCache_, startMinimized, !emoticons.empty(), enableAdHocCommandOnJID); uiFactories_.push_back(uiFactory); MainController* mainController = new MainController( &clientMainThreadCaller_, &networkFactories_, uiFactory, settingsHierachy_, systemTrays_[i], soundPlayer_, storagesFactory_, certificateStorageFactory_, dock_, notifier_, uriHandler_, &idleDetector_, emoticons, options.count("latency-debug") > 0); mainControllers_.push_back(mainController); } connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(handleAboutToQuit())); PlatformAutoUpdaterFactory autoUpdaterFactory; - if (autoUpdaterFactory.isSupported() && settingsHierachy_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES)) { - autoUpdater_ = autoUpdaterFactory.createAutoUpdater(SWIFT_APPCAST_URL); + if (autoUpdaterFactory.isSupported() && settingsHierachy_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES) + && !settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL).empty()) { + autoUpdater_ = autoUpdaterFactory.createAutoUpdater(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL))); autoUpdater_->checkForUpdates(); autoUpdater_->onSuggestRestartToUserToUpdate.connect(boost::bind(&QtSwift::handleRecommendRestartToInstallUpdate, this)); + + settingsHierachy_->onSettingChanged.connect([&](const std::string& path) { + if (path == QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL.getKey()) { + autoUpdater_->setAppcastFeed(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL))); + autoUpdater_->checkForUpdates(); + } + }); } } QtSwift::~QtSwift() { delete autoUpdater_; for (auto* factory : uiFactories_) { delete factory; } for (auto* controller : mainControllers_) { delete controller; } delete notifier_; for (auto* tray : systemTrays_) { delete tray; } delete tabs_; delete splitter_; delete settingsHierachy_; delete qtSettings_; delete xmlSettings_; delete statusCache_; delete uriHandler_; delete dock_; delete soundPlayer_; delete chatWindowFactory_; delete certificateStorageFactory_; delete storagesFactory_; delete applicationPathProvider_; } void QtSwift::handleAboutToQuit() { #if defined(SWIFTEN_PLATFORM_MACOSX) // This is required so Sparkle knows about the application shutting down // and can update the application in background. CocoaUIHelpers::sendCocoaApplicationWillTerminateNotification(); #endif } void QtSwift::handleRecommendRestartToInstallUpdate() { - notifier_->showMessage(Notifier::SystemMessage, Q2PSTRING(tr("Swift Update Available")), Q2PSTRING(tr("Restart Swift now or later to update to the new Swift version")), "", [](){}); + notifier_->showMessage(Notifier::SystemMessage, Q2PSTRING(tr("Swift Update Available")), Q2PSTRING(tr("Restart Swift to update to the new Swift version.")), "", [](){}); } } diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h index 64b79b8..3ad5714 100644 --- a/Swift/QtUI/QtSwift.h +++ b/Swift/QtUI/QtSwift.h @@ -40,60 +40,61 @@ namespace Swift { class AvatarStorage; class CapsStorage; class MainController; class QtSystemTray; class QtChatTabsBase; class QtChatWindowFactory; class QtSoundPlayer; class QtMUCSearchWindowFactory; class QtUserSearchWindowFactory; class EventLoop; class URIHandler; class SettingsProviderHierachy; class XMLSettingsProvider; class StatusCache; class QtSingleWindow; class QtSwift : public QObject { Q_OBJECT public: QtSwift(const po::variables_map& options); static po::options_description getOptionsDescription(); ~QtSwift(); private slots: void handleAboutToQuit(); void handleRecommendRestartToInstallUpdate(); private: XMLSettingsProvider* loadSettingsFile(const QString& fileName); void loadEmoticonsFile(const QString& fileName, std::map<std::string, std::string>& emoticons); + static const std::string& updateChannelToFeed(const std::string& channel); private: QtEventLoop clientMainThreadCaller_; PlatformTLSFactories tlsFactories_; BoostNetworkFactories networkFactories_; QtChatWindowFactory* chatWindowFactory_; std::vector<MainController*> mainControllers_; std::vector<QtSystemTray*> systemTrays_; std::vector<QtUIFactory*> uiFactories_; QtSettingsProvider* qtSettings_; XMLSettingsProvider* xmlSettings_; SettingsProviderHierachy* settingsHierachy_; QtSingleWindow* splitter_; QtSoundPlayer* soundPlayer_; Dock* dock_; URIHandler* uriHandler_; QtChatTabsBase* tabs_; ApplicationPathProvider* applicationPathProvider_; StoragesFactory* storagesFactory_; CertificateStorageFactory* certificateStorageFactory_; AutoUpdater* autoUpdater_; Notifier* notifier_; StatusCache* statusCache_; PlatformIdleQuerier idleQuerier_; ActualIdleDetector idleDetector_; #if defined(SWIFTEN_PLATFORM_MACOSX) CocoaApplication cocoaApplication_; CocoaApplicationActivateHelper cocoaApplicationActivateHelper_; #endif }; diff --git a/Swift/QtUI/QtUISettingConstants.cpp b/Swift/QtUI/QtUISettingConstants.cpp index c81a234..24cc6dc 100644 --- a/Swift/QtUI/QtUISettingConstants.cpp +++ b/Swift/QtUI/QtUISettingConstants.cpp @@ -1,25 +1,29 @@ /* * Copyright (c) 2012-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swift/QtUI/QtUISettingConstants.h> +#include <Swift/QtUI/SwiftUpdateFeeds.h> + namespace Swift { const SettingsProvider::Setting<bool> QtUISettingConstants::COMPACT_ROSTER("compactRoster", false); const SettingsProvider::Setting<std::string> QtUISettingConstants::CLICKTHROUGH_BANNER("clickthroughBanner", ""); const SettingsProvider::Setting<int> QtUISettingConstants::CURRENT_ROSTER_TAB("currentRosterTab", 0); const SettingsProvider::Setting<bool> QtUISettingConstants::SHOW_NICK_IN_ROSTER_HEADER("showNickInRosterHeader", true); const SettingsProvider::Setting<int> QtUISettingConstants::CHATWINDOW_FONT_SIZE("chatWindowFontSize", 0); const SettingsProvider::Setting<int> QtUISettingConstants::HISTORYWINDOW_FONT_SIZE("historyWindowFontSize", 0); const SettingsProvider::Setting<bool> QtUISettingConstants::SHOW_EMOTICONS("showEmoticons", true); const SettingsProvider::Setting<bool> QtUISettingConstants::USE_PLAIN_CHATS("plainChats", false); const SettingsProvider::Setting<bool> QtUISettingConstants::USE_SCREENREADER("screenreader", false); const SettingsProvider::Setting<bool> QtUISettingConstants::SPELL_CHECKER("spellChecker", false); const SettingsProvider::Setting<std::string> QtUISettingConstants::SPELL_CHECKER_LANGUAGE("spellCheckerLanguage", "en_US"); const SettingsProvider::Setting<std::string> QtUISettingConstants::TRELLIS_GRID_SIZE("trellisGridSize", ""); const SettingsProvider::Setting<std::string> QtUISettingConstants::TRELLIS_GRID_POSITIONS("trellisGridPositions", ""); const SettingsProvider::Setting<bool> QtUISettingConstants::ENABLE_SOFTWARE_UPDATES("enableSoftwareUpdates", true); +const SettingsProvider::Setting<std::string> QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL("softwareUpdateChannel", UpdateFeeds::StableChannel); + } diff --git a/Swift/QtUI/QtUISettingConstants.h b/Swift/QtUI/QtUISettingConstants.h index 4616656..a569587 100644 --- a/Swift/QtUI/QtUISettingConstants.h +++ b/Swift/QtUI/QtUISettingConstants.h @@ -1,46 +1,53 @@ /* * Copyright (c) 2012-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <string> + #include <Swift/Controllers/Settings/SettingsProvider.h> namespace Swift { class QtUISettingConstants { public: static const SettingsProvider::Setting<bool> COMPACT_ROSTER; static const SettingsProvider::Setting<std::string> CLICKTHROUGH_BANNER; static const SettingsProvider::Setting<int> CURRENT_ROSTER_TAB; static const SettingsProvider::Setting<bool> SHOW_NICK_IN_ROSTER_HEADER; static const SettingsProvider::Setting<int> CHATWINDOW_FONT_SIZE; static const SettingsProvider::Setting<int> HISTORYWINDOW_FONT_SIZE; static const SettingsProvider::Setting<bool> SHOW_EMOTICONS; static const SettingsProvider::Setting<bool> USE_PLAIN_CHATS; static const SettingsProvider::Setting<bool> USE_SCREENREADER; static const SettingsProvider::Setting<bool> SPELL_CHECKER; static const SettingsProvider::Setting<std::string> SPELL_CHECKER_LANGUAGE; /** * The #TRELLIS_GRID_SIZE setting specifies the dimensions of the grid used for the trellis * layout. * * Its value is a Qt serialized representation. */ static const SettingsProvider::Setting<std::string> TRELLIS_GRID_SIZE; /** * The #TRELLIS_GRID_POSITIONS setting specifies where conversations to contacts or rooms go * in the trellis grid. * * Its value is a Qt serialized representation. */ static const SettingsProvider::Setting<std::string> TRELLIS_GRID_POSITIONS; /** - * The #ENABLE_SOFTWARE_UPDATES settings specifies, whether Swift + * The #ENABLE_SOFTWARE_UPDATES setting specifies, whether Swift * should automatically check for software updates in regular * intervals and install them automatically. */ static const SettingsProvider::Setting<bool> ENABLE_SOFTWARE_UPDATES; + /** + * The #SOFTWARE_UPDATE_CHANNEL setting defines what update channel + * Swift uses to check for, and receive, updates. + */ + static const SettingsProvider::Setting<std::string> SOFTWARE_UPDATE_CHANNEL; }; } diff --git a/Swift/QtUI/QtUpdateFeedSelectionDialog.cpp b/Swift/QtUI/QtUpdateFeedSelectionDialog.cpp new file mode 100644 index 0000000..1f4058a --- /dev/null +++ b/Swift/QtUI/QtUpdateFeedSelectionDialog.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swift/QtUI/QtUpdateFeedSelectionDialog.h> + +#include <QComboBox> + +#include <Swift/Controllers/Settings/SettingsProvider.h> + +#include <Swift/QtUI/QtUISettingConstants.h> +#include <Swift/QtUI/SwiftUpdateFeeds.h> + +namespace Swift { + +QtUpdateFeedSelectionDialog::QtUpdateFeedSelectionDialog(SettingsProvider* settingsProvider) : QDialog(), settings_(settingsProvider) { + ui.setupUi(this); + + connect(ui.currentChannelComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [&] (int newIndex) { + setDescriptionForIndex(newIndex); + }); + + auto updateChannel = settings_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL); + if (updateChannel == UpdateFeeds::StableChannel) { + ui.currentChannelComboBox->setCurrentIndex(0); + } + else if (updateChannel == UpdateFeeds::TestingChannel) { + ui.currentChannelComboBox->setCurrentIndex(1); + } + else if (updateChannel == UpdateFeeds::DevelopmentChannel) { + ui.currentChannelComboBox->setCurrentIndex(2); + } + + connect(this, &QDialog::accepted, [&]() { + auto newUpdateChannel = std::string(""); + switch (ui.currentChannelComboBox->currentIndex()) { + case 0: + newUpdateChannel = UpdateFeeds::StableChannel; + break; + case 1: + newUpdateChannel = UpdateFeeds::TestingChannel; + break; + case 2: + newUpdateChannel = UpdateFeeds::DevelopmentChannel; + break; + } + settings_->storeSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL, newUpdateChannel); + }); + + setAttribute(Qt::WA_DeleteOnClose); +} + +void QtUpdateFeedSelectionDialog::setDescriptionForIndex(int index) { + switch (index) { + case 0: + ui.stableDescriptionLabel->show(); + ui.testingDescriptionLabel->hide(); + ui.developmentDescriptionLabel->hide(); + break; + case 1: + ui.stableDescriptionLabel->hide(); + ui.testingDescriptionLabel->show(); + ui.developmentDescriptionLabel->hide(); + break; + case 2: + ui.stableDescriptionLabel->hide(); + ui.testingDescriptionLabel->hide(); + ui.developmentDescriptionLabel->show(); + break; + default: + ui.stableDescriptionLabel->hide(); + ui.testingDescriptionLabel->hide(); + ui.developmentDescriptionLabel->hide(); + break; + } + setFixedSize(sizeHint()); +} + + + +} diff --git a/Swift/QtUI/QtUpdateFeedSelectionDialog.h b/Swift/QtUI/QtUpdateFeedSelectionDialog.h new file mode 100644 index 0000000..80b986f --- /dev/null +++ b/Swift/QtUI/QtUpdateFeedSelectionDialog.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <QDialog> + +#include <Swift/QtUI/ui_QtUpdateFeedSelectionDialog.h> + +namespace Swift { + +class SettingsProvider; + +class QtUpdateFeedSelectionDialog : public QDialog { + Q_OBJECT + public: + QtUpdateFeedSelectionDialog(SettingsProvider* settingsProvider); + + private: + void setDescriptionForIndex(int index); + + private: + Ui::QtUpdateFeedSelectionDialog ui; + SettingsProvider* settings_ = nullptr; +}; + +} diff --git a/Swift/QtUI/QtUpdateFeedSelectionDialog.ui b/Swift/QtUI/QtUpdateFeedSelectionDialog.ui new file mode 100644 index 0000000..4107f3a --- /dev/null +++ b/Swift/QtUI/QtUpdateFeedSelectionDialog.ui @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QtUpdateFeedSelectionDialog</class> + <widget class="QDialog" name="QtUpdateFeedSelectionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>335</width> + <height>158</height> + </rect> + </property> + <property name="windowTitle"> + <string>Select Update Channel</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QComboBox" name="currentChannelComboBox"> + <property name="currentText"> + <string/> + </property> + <property name="currentIndex"> + <number>-1</number> + </property> + <item> + <property name="text"> + <string>Stable Channel</string> + </property> + <property name="icon"> + <iconset theme=":/icons/delivery-success.svg"/> + </property> + </item> + <item> + <property name="text"> + <string>Testing Channel</string> + </property> + <property name="icon"> + <iconset theme=":/icons/delivery-warning.svg"/> + </property> + </item> + <item> + <property name="text"> + <string>Development Channel</string> + </property> + <property name="icon"> + <iconset theme=":/icons/delivery-warning.svg"/> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="stableDescriptionLabel"> + <property name="text"> + <string>This release channel includes our stable releases. They went throught internal QA testing and had previous RC releases to find critical bugs.</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::NoTextInteraction</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="testingDescriptionLabel"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>This release channel includes our stable releases, beta releases and release candidates. They should be free from obvious bugs and are released for wider testing to find more obscure bugs.</string> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="developmentDescriptionLabel"> + <property name="text"> + <string>This release channel includes our stable releases, beta releases, release candidates and development releases. The development releases are not thoroughly tested and might contained bugs.</string> + </property> + <property name="alignment"> + <set>Qt::AlignJustify|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>QtUpdateFeedSelectionDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>QtUpdateFeedSelectionDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index fd47dd4..acfe7d0 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -172,60 +172,61 @@ sources = [ "MUCSearch/QtMUCSearchWindow.cpp", "UserSearch/ContactListDelegate.cpp", "UserSearch/ContactListModel.cpp", "UserSearch/QtContactListWidget.cpp", "UserSearch/QtSuggestingJIDInput.cpp", "UserSearch/QtUserSearchFirstPage.cpp", "UserSearch/QtUserSearchFirstMultiJIDPage.cpp", "UserSearch/QtUserSearchFieldsPage.cpp", "UserSearch/QtUserSearchResultsPage.cpp", "UserSearch/QtUserSearchDetailsPage.cpp", "UserSearch/QtUserSearchWindow.cpp", "UserSearch/UserSearchModel.cpp", "UserSearch/UserSearchDelegate.cpp", "Whiteboard/FreehandLineItem.cpp", "Whiteboard/GView.cpp", "Whiteboard/TextDialog.cpp", "Whiteboard/QtWhiteboardWindow.cpp", "Whiteboard/ColorWidget.cpp", "QtSubscriptionRequestWindow.cpp", "QtRosterHeader.cpp", "QtWebView.cpp", "qrc_DefaultTheme.cc", "qrc_Swift.cc", "QtChatWindowJSBridge.cpp", "QtMUCConfigurationWindow.cpp", "QtAffiliationEditor.cpp", "QtUISettingConstants.cpp", "QtURLValidator.cpp", "QtResourceHelper.cpp", "QtSpellCheckHighlighter.cpp", + "QtUpdateFeedSelectionDialog.cpp", "Trellis/QtDynamicGridLayout.cpp", "Trellis/QtDNDTabBar.cpp", "Trellis/QtGridSelectionDialog.cpp" ] if env["PLATFORM"] == "win32" : sources.extend(["qrc_SwiftWindows.cc"]) # QtVCardWidget sources.extend([ "QtVCardWidget/QtCloseButton.cpp", "QtVCardWidget/QtRemovableItemDelegate.cpp", "QtVCardWidget/QtResizableLineEdit.cpp", "QtVCardWidget/QtTagComboBox.cpp", "QtVCardWidget/QtVCardHomeWork.cpp", "QtVCardWidget/QtVCardAddressField.cpp", "QtVCardWidget/QtVCardAddressLabelField.cpp", "QtVCardWidget/QtVCardBirthdayField.cpp", "QtVCardWidget/QtVCardDescriptionField.cpp", "QtVCardWidget/QtVCardInternetEMailField.cpp", "QtVCardWidget/QtVCardJIDField.cpp", "QtVCardWidget/QtVCardOrganizationField.cpp", "QtVCardWidget/QtVCardPhotoAndNameFields.cpp", "QtVCardWidget/QtVCardRoleField.cpp", "QtVCardWidget/QtVCardTelephoneField.cpp", "QtVCardWidget/QtVCardTitleField.cpp", "QtVCardWidget/QtVCardURLField.cpp", "QtVCardWidget/QtVCardGeneralField.cpp", "QtVCardWidget/QtVCardWidget.cpp" ]) @@ -272,60 +273,61 @@ if env["PLATFORM"] == "posix" : if env["PLATFORM"] == "darwin" : sources += ["CocoaApplicationActivateHelper.mm"] sources += ["CocoaUIHelpers.mm"] if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" : swiftProgram = myenv.Program("Swift", sources) else : sources += ["QtCertificateViewerDialog.cpp"]; myenv.Uic4("QtCertificateViewerDialog.ui"); swiftProgram = myenv.Program("swift-im", sources) if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" : openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp") else : openURIProgram = [] myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui") myenv.Uic4("UserSearch/QtUserSearchWizard.ui") myenv.Uic4("UserSearch/QtUserSearchFirstPage.ui") myenv.Uic4("UserSearch/QtUserSearchFirstMultiJIDPage.ui") myenv.Uic4("UserSearch/QtUserSearchFieldsPage.ui") myenv.Uic4("UserSearch/QtUserSearchResultsPage.ui") myenv.Uic4("QtBookmarkDetailWindow.ui") myenv.Uic4("QtAffiliationEditor.ui") myenv.Uic4("QtJoinMUCWindow.ui") myenv.Uic4("QtHistoryWindow.ui") myenv.Uic4("QtConnectionSettings.ui") myenv.Uic4("QtHighlightEditor.ui") myenv.Uic4("QtBlockListEditorWindow.ui") myenv.Uic4("QtSpellCheckerWindow.ui") +myenv.Uic4("QtUpdateFeedSelectionDialog.ui") myenv.Qrc("DefaultTheme.qrc") myenv.Qrc("Swift.qrc") if env["PLATFORM"] == "win32" : myenv.Qrc("SwiftWindows.qrc") # Resources commonResources = { "": ["#/Swift/resources/sounds"] } myenv["TEXTFILESUFFIX"] = "" myenv.MyTextfile(target = "COPYING", source = [myenv.File("../../COPYING.gpl"), myenv.File("../../COPYING.thirdparty")], LINESEPARATOR = "\n\n========\n\n\n") ################################################################################ # Translation ################################################################################ # Collect available languages translation_languages = [] for file in os.listdir(Dir("#/Swift/Translations").abspath) : if file.startswith("swift_") and file.endswith(".ts") : translation_languages.append(file[6:-3]) # Generate translation modules translation_sources = [env.File("#/Swift/Translations/swift.ts").abspath] translation_modules = [] for lang in translation_languages : translation_resource = "#/Swift/resources/translations/swift_" + lang + ".qm" translation_source = "#/Swift/Translations/swift_" + lang + ".ts" diff --git a/Swift/QtUI/SwiftUpdateFeeds.h b/Swift/QtUI/SwiftUpdateFeeds.h new file mode 100644 index 0000000..a6476f5 --- /dev/null +++ b/Swift/QtUI/SwiftUpdateFeeds.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Platform.h> + +namespace Swift { + +namespace UpdateFeeds { + const std::string StableChannel = "stable"; + const std::string TestingChannel = "testing"; + const std::string DevelopmentChannel = "development"; + +#if defined(SWIFTEN_PLATFORM_MACOSX) + const std::string StableAppcastFeed = "https://swift.im/downloads/swift-stable-appcast-mac.xml"; + const std::string TestingAppcastFeed = "https://swift.im/downloads/swift-testing-appcast-mac.xml"; + const std::string DevelopmentAppcastFeed = "https://swift.im/downloads/swift-development-appcast-mac.xml"; +#else + const std::string StableAppcastFeed = ""; + const std::string TestingAppcastFeed = ""; + const std::string DevelopmentAppcastFeed = ""; +#endif +} + +} |