# # # delete "src/util/SignalWaiter.cpp" # # delete "src/util/SignalWaiter.h" # # patch "NEWS" # from [d695681e168b4be74c9d423c5fbd1f2743fb9975] # to [09aa8102c6720729211af155002349be28690a97] # # patch "guitone.pro" # from [fa8a9b837bc6c3f23089fa2c7c960eb43c3954a0] # to [a84bcaf4e5e125fed275b7d70c4d8dc030108c58] # # patch "res/forms/application_update.ui" # from [7d2b3993e719ba0fea62c815d0cee25d6fd48562] # to [5258144de27b682d19ea5cf5e9edf2a506cf419c] # # patch "src/Guitone.cpp" # from [7d7e4e26247c3ecee04de41553e97715699ae723] # to [a8876c05a77ca3e2a69cb7dc5b80745de0a0fad9] # # patch "src/util/Settings.cpp" # from [1605f183154e84e6dcf6afd3e7505afc7d8aad53] # to [7fe33df35ead425818ac4cbd35444dbb82de072f] # # patch "src/util/Settings.h" # from [c270582aa028c7a903405c024cabd2e6ed0cb965] # to [19b198d8e78259744a90bb47f052b0699a668913] # # patch "src/view/dialogs/ApplicationUpdate.cpp" # from [1877bdbdb1b60402d2b30335a9312c1a7b9dfbec] # to [c9c4629c72bbc2c0eaad7a16c5eed07a1cce7fe5] # # patch "src/view/dialogs/ApplicationUpdate.h" # from [15d58d7ed4e847db2d4669c24fbe4bd894786722] # to [3c09b46adc9dd244f503df8ad9a27ada57813483] # # patch "src/vocab.h" # from [7f21cf44b67083fb6101067d98ae4be51b44fea9] # to [b4b58ec186846eedc156ee5bf76f3b6d757a58d0] # ============================================================ --- NEWS d695681e168b4be74c9d423c5fbd1f2743fb9975 +++ NEWS 09aa8102c6720729211af155002349be28690a97 @@ -8,8 +8,9 @@ and changeset browser and open the diff dialog for these files - new: support for viewing the complete changeset for merge revisions in the changeset browser - - new: a panel to view and edit database variables + - new: a panel to view and edit database variables (open it via View > Panels > Database Variables) + - new: possibility to skip a new program version in the native dialog - improved: startup dialog slightly changed - now contains the possibility to edit the preferences, open recent databases and workspaces. Removed this functionality from the initialization phase of the application which was @@ -20,9 +21,12 @@ huge workloads (f.e. big chunks of inventory output) - improved: starting with mtn 0.39 incremental workspace loading is enabled by default + - bugfix: if a not supported mtn version is found and the user hits cancel + in the preferences dialog, guitone is now closed properly and does not + sit in the background doing nothing - bugfix: if guitone is closed too fast (f.e. before the internal mtn thread could be started), the application wasn't closed properly, but only removed - all open windows. + all open windows 2008-01-16 (0.7) - new: possibility to display the history of a single file in chronological ============================================================ --- guitone.pro fa8a9b837bc6c3f23089fa2c7c960eb43c3954a0 +++ guitone.pro a84bcaf4e5e125fed275b7d70c4d8dc030108c58 @@ -87,7 +87,6 @@ HEADERS = src/view/TreeView.h \ src/util/BasicIOWriter.h \ src/util/Settings.h \ src/util/DiffParser.h \ - src/util/SignalWaiter.h \ src/util/Platform.h \ src/util/TreeBuilder.h \ src/util/DebugLog.h \ @@ -160,7 +159,6 @@ SOURCES += src/view/TreeView.cpp \ src/util/BasicIOWriter.cpp \ src/util/Settings.cpp \ src/util/DiffParser.cpp \ - src/util/SignalWaiter.cpp \ src/util/Platform.cpp \ src/util/TreeBuilder.cpp \ src/util/DebugLog.cpp \ ============================================================ --- res/forms/application_update.ui 7d2b3993e719ba0fea62c815d0cee25d6fd48562 +++ res/forms/application_update.ui 5258144de27b682d19ea5cf5e9edf2a506cf419c @@ -16,32 +16,66 @@ :/icons/guitone.png - + + 6 + + 9 - - 6 + + 9 + + 9 + + + 9 + - + + 6 + + 0 - - 6 + + 0 + + 0 + + + 0 + - + + 6 + + 0 - - 6 + + 0 + + 0 + + + 0 + + + + Skip this version + + + + Visit website ============================================================ --- src/Guitone.cpp 7d7e4e26247c3ecee04de41553e97715699ae723 +++ src/Guitone.cpp a8876c05a77ca3e2a69cb7dc5b80745de0a0fad9 @@ -112,6 +112,7 @@ void Guitone::setMonotoneBinaryPath() // the user has rejected the dialog, i.e. made no new settings if (dialog.exec() == QDialog::Rejected) { + quit(); return; } } @@ -367,21 +368,7 @@ void Guitone::checkForApplicationUpdates updateDialog = new ApplicationUpdate(NULL); } - if (!updateDialog->updateAvailable()) - { - if (!silent) - { - QMessageBox::information( - NULL, - tr("No updates available"), - tr("Your version of guitone (%1) is already up-to-date.") - .arg(GUITONE_VERSION), - QMessageBox::Ok - ); - } - return; - } - updateDialog->show(); + updateDialog->checkForUpdates(silent); #endif } ============================================================ --- src/util/Settings.cpp 1605f183154e84e6dcf6afd3e7505afc7d8aad53 +++ src/util/Settings.cpp 7fe33df35ead425818ac4cbd35444dbb82de072f @@ -52,6 +52,18 @@ bool Settings::getBool(const QString & n return singleton()->value(name, defaultVal).toBool(); } +void Settings::setString(const QString & name, const QString & value) +{ + I(!name.isEmpty()); + singleton()->setValue(name, value); +} + +QString Settings::getString(const QString & name, const QString & defaultVal) +{ + I(!name.isEmpty()); + return singleton()->value(name, defaultVal).toString(); +} + void Settings::setWindowGeometry(const QString & windowClass, const QByteArray & data) { I(!windowClass.isEmpty()); @@ -74,7 +86,7 @@ QString Settings::getMtnBinaryPath() return singleton()->value("MtnExePath", "mtn").toString(); } -void Settings::setMtnBinaryPath(QString path) +void Settings::setMtnBinaryPath(const QString & path) { singleton()->setValue("MtnExePath", path); } @@ -110,7 +122,7 @@ void Settings::setLogLevel(int verbosity singleton()->setValue("LogLevel", verbosity); } -void Settings::saveHeaderViewState(QHeaderView *view, QString name) +void Settings::saveHeaderViewState(QHeaderView * view, const QString & name) { I(!name.isEmpty()); QStringList cols; @@ -126,7 +138,7 @@ void Settings::saveHeaderViewState(QHead settings->setValue(name, cols.join(",")); } -void Settings::restoreHeaderViewState(QHeaderView *view, QString name) +void Settings::restoreHeaderViewState(QHeaderView * view, const QString & name) { I(!name.isEmpty()); QString colConfig(singleton()->value(name).toString()); @@ -148,13 +160,13 @@ void Settings::restoreHeaderViewState(QH } } -QByteArray Settings::getSplitterState(QString name) +QByteArray Settings::getSplitterState(const QString & name) { I(!name.isEmpty()); return singleton()->value(name).toByteArray(); } -void Settings::setSplitterState(const QByteArray & byteArray, QString name) +void Settings::setSplitterState(const QByteArray & byteArray, const QString & name) { I(!name.isEmpty()); Settings *settings = singleton(); ============================================================ --- src/util/Settings.h c270582aa028c7a903405c024cabd2e6ed0cb965 +++ src/util/Settings.h 19b198d8e78259744a90bb47f052b0699a668913 @@ -30,16 +30,19 @@ public: static void setBool(const QString &, bool); static bool getBool(const QString &, bool); + static void setString(const QString &, const QString &); + static QString getString(const QString &, const QString &); + static void setWindowGeometry(const QString &, const QByteArray &); static QByteArray getWindowGeometry(const QString &); static QStringList getItemList(const QString &); static void setItemList(const QString &, const QStringList &); - static void addItemToList(const QString&, const QString &, int); + static void addItemToList(const QString &, const QString &, int); static void removeItemFromList(const QString &, const QString &); static QString getMtnBinaryPath(); - static void setMtnBinaryPath(QString); + static void setMtnBinaryPath(const QString &); static bool getConsoleLogEnabled(); static void setConsoleLogEnabled(bool); @@ -48,19 +51,19 @@ public: static int getLogLevel(); static void setLogLevel(int); - static void saveHeaderViewState(QHeaderView *, QString); - static void restoreHeaderViewState(QHeaderView *, QString); + static void saveHeaderViewState(QHeaderView *, const QString &); + static void restoreHeaderViewState(QHeaderView *, const QString &); - static QByteArray getSplitterState(QString); - static void setSplitterState(const QByteArray &, QString); + static QByteArray getSplitterState(const QString &); + static void setSplitterState(const QByteArray &, const QString &); static void sync(); private: Settings(); ~Settings(void); - static Settings* singleton(); - static Settings* instance; + static Settings * singleton(); + static Settings * instance; }; ============================================================ --- src/view/dialogs/ApplicationUpdate.cpp 1877bdbdb1b60402d2b30335a9312c1a7b9dfbec +++ src/view/dialogs/ApplicationUpdate.cpp c9c4629c72bbc2c0eaad7a16c5eed07a1cce7fe5 @@ -17,39 +17,115 @@ ***************************************************************************/ #include "ApplicationUpdate.h" -#include "SignalWaiter.h" #include "MonotoneManager.h" #include "Platform.h" +#include "Settings.h" -#include #include +#include ApplicationUpdate::ApplicationUpdate(QWidget * parent) - : Dialog(parent), update_available(false) + : Dialog(parent) { setupUi(this); Dialog::init(); + setWindowModality(Qt::ApplicationModal); + connect( visitWebsite, SIGNAL(clicked()), this, SLOT(openWebsite()) ); - QHttp http; - http.setHost("guitone.thomaskeller.biz"); - http.get("/web/appcast.xml"); + connect( + skipVersion, SIGNAL(clicked()), + this, SLOT(skipThisVersion()) + ); - SignalWaiter waiter(&http, SIGNAL(done(bool))); + httpConnection = new QHttp(); + connect( + httpConnection, SIGNAL(done(bool)), + this, SLOT(processHttpResult(bool)) + ); +} - // TODO: we definitely should display some status window here - // while waiting for a response on slow connections - waiter.wait(); +ApplicationUpdate::~ApplicationUpdate() +{ + delete httpConnection; +} +/** + * If the we check for a new application version silently, the user + * is not nagged with error messages like f.e. that there is no new version + * available or that the check failed. However, if there is a new version + * available, the dialog is shown to the user. + * Now if he clicks on "SkipThisVersion" in the dialog, he is not remembered + * again on the next application start that there is a new version, BUT + * only unless he triggers the version check by hand from the "File" menu + * which calls checkForUpdates without the silent flag set to false. In + * this case the "Skip this version" button is also made invisible since it + * has no functionality here. + */ +void ApplicationUpdate::checkForUpdates(bool silent) +{ + if (httpConnection->hasPendingRequests()) + { + C("HTTP connection has pending requests... aborting"); + return; + } + + silentCheck = silent; + + httpConnection->setHost("guitone.thomaskeller.biz"); + httpConnection->get("/web/appcast.xml"); + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void ApplicationUpdate::processHttpResult(bool error) +{ + QApplication::restoreOverrideCursor(); + + if (error) + { + QString errStr = httpConnection->errorString(); + + C(QString("unable to fetch update information: %1").arg(errStr)); + + if (!silentCheck) + { + QMessageBox::critical( + this, + tr("Error"), + tr("Unable to fetch update information:\n%1").arg(errStr), + QMessageBox::Ok, 0, 0 + ); + } + return; + } + + int statusCode = httpConnection->lastResponse().statusCode(); + if (statusCode != 200) + { + C(QString("status code was: %1").arg(statusCode)); + + if (!silentCheck) + { + QMessageBox::critical( + this, + tr("Error"), + tr("Unable to fetch update information (error %1).").arg(statusCode), + QMessageBox::Ok, 0, 0 + ); + } + return; + } + QDomDocument doc; QString err; int line, col; - if (!doc.setContent(http.readAll(), true, &err, &line, &col)) + if (!doc.setContent(httpConnection->readAll(), true, &err, &line, &col)) { W(QString("Cannot parse document: %1 (line %2, col %3)") .arg(err).arg(line).arg(col)); @@ -61,7 +137,8 @@ ApplicationUpdate::ApplicationUpdate(QWi QDomNodeList items = channel.elementsByTagName("item"); - QPair latest(GUITONE_VERSION, ""); + latestVersion = GUITONE_VERSION; + QString versionDescription; for (int i=0, j=items.size(); i 0) + if (MonotoneManager::versionCompare(version, latestVersion) > 0) { - latest.first = version; + latestVersion = version; QDomNodeList descs = item.elementsByTagName("description"); I(descs.size() == 1); QDomElement desc = descs.item(0).toElement(); I(!desc.isNull()); - latest.second = desc.text(); + versionDescription = desc.text(); } } } - if (latest.first != GUITONE_VERSION) + if (latestVersion != GUITONE_VERSION) { - textBrowser->setHtml(latest.second); - update_available = true; + QString versionToSkip = Settings::getString("SkipGuitoneVersion", ""); + + if (silentCheck && !versionToSkip.isEmpty() && + MonotoneManager::versionCompare(latestVersion, versionToSkip) <= 0) + { + L(QString("skipping %1 per user request").arg(latestVersion)); + return; + } + + textBrowser->setHtml(versionDescription); + if (!silentCheck) + { + skipVersion->setVisible(false); + } + + show(); } + else + { + if (!silentCheck) + { + QMessageBox::information( + NULL, + tr("No updates available"), + tr("Your version of guitone (%1) is already up-to-date.") + .arg(GUITONE_VERSION), + QMessageBox::Ok + ); + } + } } -ApplicationUpdate::~ApplicationUpdate() {} - void ApplicationUpdate::openWebsite() { Platform::openFile("http://guitone.thomaskeller.biz"); accept(); } +void ApplicationUpdate::skipThisVersion() +{ + Settings::setString("SkipGuitoneVersion", latestVersion); + accept(); +} + + ============================================================ --- src/view/dialogs/ApplicationUpdate.h 15d58d7ed4e847db2d4669c24fbe4bd894786722 +++ src/view/dialogs/ApplicationUpdate.h 3c09b46adc9dd244f503df8ad9a27ada57813483 @@ -22,19 +22,25 @@ #include "ui_application_update.h" #include "Dialog.h" +#include + class ApplicationUpdate : public Dialog, private Ui::ApplicationUpdateDialog { Q_OBJECT public: ApplicationUpdate(QWidget *); ~ApplicationUpdate(); - inline bool updateAvailable() { return update_available; }; + void checkForUpdates(bool); private: - bool update_available; + QHttp * httpConnection; + bool silentCheck; + QString latestVersion; private slots: + void processHttpResult(bool); void openWebsite(); + void skipThisVersion(); }; #endif ============================================================ --- src/vocab.h 7f21cf44b67083fb6101067d98ae4be51b44fea9 +++ src/vocab.h b4b58ec186846eedc156ee5bf76f3b6d757a58d0 @@ -5,10 +5,8 @@ // global macros and defines // -// if you use any of those two, you also have to include Guitone.h class Guitone; -#define APP reinterpret_cast(qApp) -#define MTN(arg) APP->getMonotoneInstance(arg) +#define APP reinterpret_cast(qApp) #include "DebugLog.h" #ifdef QT_NO_DEBUG @@ -96,10 +94,11 @@ typedef QList StanzaList; typedef QList Stanza; typedef QList StanzaList; +// FIXME: just a few stupid typedefs which should be expanded later on +// to more "intelligent" objects typedef QString GuitoneException; - -// TODO: maybe we can load workspace normalization into this typedef QString WorkspacePath; typedef QString DatabaseFile; #endif +