1 /************************************************************************
\r
3 ** Copyright (C) 2010 Strahinja Markovic
\r
5 ** This file is part of FlightCrew.
\r
7 ** FlightCrew is free software: you can redistribute it and/or modify
\r
8 ** it under the terms of the GNU Lesser General Public License as published
\r
9 ** by the Free Software Foundation, either version 3 of the License, or
\r
10 ** (at your option) any later version.
\r
12 ** FlightCrew is distributed in the hope that it will be useful,
\r
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 ** GNU Lesser General Public License for more details.
\r
17 ** You should have received a copy of the GNU Lesser General Public License
\r
18 ** along with FlightCrew. If not, see <http://www.gnu.org/licenses/>.
\r
20 *************************************************************************/
\r
23 #include <QSettings>
\r
24 #include <QNetworkAccessManager>
\r
25 #include <QNetworkRequest>
\r
26 #include <QNetworkReply>
\r
27 #include <QDateTime>
\r
28 #include <QMessageBox>
\r
29 #include <QDesktopServices>
\r
30 #include <QXmlStreamReader>
\r
31 #include <QTextStream>
\r
32 #include "UpdateChecker.h"
\r
34 static const QString DOWNLOAD_PAGE_LOCATION = "http://code.google.com/p/flightcrew/downloads/list";
\r
35 static const QString UPDATE_XML_LOCATION = "http://flightcrew.googlecode.com/git/version.xml";
\r
36 static const QString XML_VERSION_ELEMENT = "current-version";
\r
37 static const QString LAST_ONLINE_VERSION_KEY = "last_online_version";
\r
38 static const QString LAST_CHECK_TIME_KEY = "last_check_time";
\r
39 static const QString SETTINGS_GROUP = "updatechecker";
\r
40 static const QString VERSION_NUMBERS = "(\\d+)\\.(\\d+)\\.(\\d+)";
\r
41 static const QString FLIGHTCREW_VERSION = QString( FLIGHTCREW_FULL_VERSION );
\r
43 // Delta is six hours
\r
44 static const int SECONDS_BETWEEN_CHECKS = 60 * 60 * 6 ;
\r
47 UpdateChecker::UpdateChecker( QObject *parent )
\r
50 m_NetworkManager( new QNetworkAccessManager( this ) )
\r
52 connect( m_NetworkManager, SIGNAL( finished( QNetworkReply* ) ),
\r
53 this, SLOT( ReplyRecieved( QNetworkReply* ) )
\r
58 void UpdateChecker::CheckForUpdate()
\r
61 settings.beginGroup( SETTINGS_GROUP );
\r
63 // The default time is one always longer than the check interval
\r
64 QDateTime default_time = QDateTime::currentDateTime().addSecs( - SECONDS_BETWEEN_CHECKS - 1 );
\r
65 QDateTime last_check_time = settings.value( LAST_CHECK_TIME_KEY, default_time ).toDateTime();
\r
67 // We want to check for a new version
\r
68 // no sooner than every six hours
\r
69 if ( last_check_time.secsTo( QDateTime::currentDateTime() ) > SECONDS_BETWEEN_CHECKS )
\r
71 settings.setValue( LAST_CHECK_TIME_KEY, QDateTime::currentDateTime() );
\r
73 m_NetworkManager->get( QNetworkRequest( QUrl( UPDATE_XML_LOCATION ) ) );
\r
78 void UpdateChecker::ReplyRecieved( QNetworkReply* reply )
\r
81 settings.beginGroup( SETTINGS_GROUP );
\r
83 QString last_online_version = settings.value( LAST_ONLINE_VERSION_KEY, QString() ).toString();
\r
84 QString current_online_version = ReadOnlineVersion( TextInReply( reply ) );
\r
86 bool is_newer = IsOnlineVersionNewer( FLIGHTCREW_VERSION, current_online_version );
\r
88 // The message box is displayed only if the online version is newer
\r
89 // and only if the user hasn't been informed about this release before
\r
90 if ( is_newer && ( current_online_version != last_online_version ) )
\r
92 QMessageBox::StandardButton button_clicked;
\r
94 button_clicked = QMessageBox::question( 0,
\r
95 QObject::tr( "FlightCrew" ),
\r
96 QObject::tr( "<p>A newer version of FlightCrew is available, version <b>%1</b>.<br/>"
\r
97 "The ChangeLog can be seen <a href='http://flightcrew.googlecode.com/git/ChangeLog.txt'>here</a>.</p>"
\r
98 "<p>Would you like to go to the download page?</p>" )
\r
99 .arg( current_online_version ),
\r
100 QMessageBox::Yes | QMessageBox::No,
\r
101 QMessageBox::Yes );
\r
103 if ( button_clicked == QMessageBox::Yes )
\r
105 QDesktopServices::openUrl( QUrl( DOWNLOAD_PAGE_LOCATION ) );
\r
109 // Store the current online version as the last one checked
\r
110 settings.setValue( LAST_ONLINE_VERSION_KEY, current_online_version );
\r
112 // Schedule this object for deletion.
\r
113 // There is no point for its existence
\r
114 // after it has received and processed the net reply.
\r
119 QString UpdateChecker::TextInReply( QNetworkReply* reply ) const
\r
121 if ( !reply->open( QIODevice::ReadOnly | QIODevice::Text ) )
\r
126 QTextStream in( reply );
\r
128 // Input should be UTF-8
\r
129 in.setCodec( "UTF-8" );
\r
131 // This will automatically switch reading from
\r
132 // UTF-8 to UTF-16 if a BOM is detected
\r
133 in.setAutoDetectUnicode( true );
\r
135 return in.readAll();
\r
139 QString UpdateChecker::ReadOnlineVersion( const QString &online_version_xml ) const
\r
141 if ( online_version_xml.isEmpty() )
\r
145 QXmlStreamReader version_reader( online_version_xml );
\r
147 while ( !version_reader.atEnd() )
\r
149 // Get the next token from the stream
\r
150 if ( ( version_reader.readNext() == QXmlStreamReader::StartElement ) &&
\r
151 ( version_reader.name() == XML_VERSION_ELEMENT )
\r
154 return version_reader.readElementText();
\r
162 bool UpdateChecker::IsOnlineVersionNewer( const QString ¤t_version_string,
\r
163 const QString &online_version_string ) const
\r
165 if ( current_version_string.isEmpty() || online_version_string.isEmpty() )
\r
169 QRegExp current_version_numbers( VERSION_NUMBERS );
\r
170 QString( current_version_string ).indexOf( current_version_numbers );
\r
172 QRegExp online_version_numbers( VERSION_NUMBERS );
\r
173 QString( online_version_string ).indexOf( online_version_numbers );
\r
175 // This code assumes three digits per field,
\r
176 // which should be way more than enough
\r
177 int current_version = current_version_numbers.cap( 1 ).toInt() * 1000000 +
\r
178 current_version_numbers.cap( 2 ).toInt() * 1000 +
\r
179 current_version_numbers.cap( 3 ).toInt();
\r
181 int online_version = online_version_numbers.cap( 1 ).toInt() * 1000000 +
\r
182 online_version_numbers.cap( 2 ).toInt() * 1000 +
\r
183 online_version_numbers.cap( 3 ).toInt();
\r
185 return online_version > current_version;
\r