1 | /** @file
|
---|
2 | *
|
---|
3 | * VBox frontends: Qt4 GUI ("VirtualBox"):
|
---|
4 | * VBoxUpdateDlg class implementation
|
---|
5 | */
|
---|
6 |
|
---|
7 | /*
|
---|
8 | * Copyright (C) 2006-2010 Oracle Corporation
|
---|
9 | *
|
---|
10 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
11 | * available from http://www.virtualbox.org. This file is free software;
|
---|
12 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
13 | * General Public License (GPL) as published by the Free Software
|
---|
14 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
15 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
16 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
17 | */
|
---|
18 |
|
---|
19 | #ifdef VBOX_WITH_PRECOMPILED_HEADERS
|
---|
20 | #include "precomp.h"
|
---|
21 | #else /* !VBOX_WITH_PRECOMPILED_HEADERS */
|
---|
22 | /* Global includes */
|
---|
23 | #include <QTimer>
|
---|
24 | /* Local includes */
|
---|
25 | #include "QIHttp.h"
|
---|
26 | #include "VBoxGlobal.h"
|
---|
27 | #include "VBoxProblemReporter.h"
|
---|
28 | #include "VBoxUpdateDlg.h"
|
---|
29 | #include "UIIconPool.h"
|
---|
30 | #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
|
---|
31 |
|
---|
32 | /* VBoxVersion stuff */
|
---|
33 | class VBoxVersion
|
---|
34 | {
|
---|
35 | public:
|
---|
36 |
|
---|
37 | VBoxVersion (const QString &aVersion)
|
---|
38 | : x (0), y (0), z (0)
|
---|
39 | {
|
---|
40 | QStringList versionStack = aVersion.split ('.');
|
---|
41 | if (versionStack.size() > 0)
|
---|
42 | x = versionStack [0].toInt();
|
---|
43 | if (versionStack.size() > 1)
|
---|
44 | y = versionStack [1].toInt();
|
---|
45 | if (versionStack.size() > 2)
|
---|
46 | z = versionStack [2].toInt();
|
---|
47 | }
|
---|
48 |
|
---|
49 | bool operator< (const VBoxVersion &aOther) const
|
---|
50 | {
|
---|
51 | return (x < aOther.x) ||
|
---|
52 | (x == aOther.x && y < aOther.y) ||
|
---|
53 | (x == aOther.x && y == aOther.y && z < aOther.z);
|
---|
54 | }
|
---|
55 |
|
---|
56 | QString toString() const
|
---|
57 | {
|
---|
58 | return QString ("%1.%2.%3").arg (x).arg (y).arg (z);
|
---|
59 | }
|
---|
60 |
|
---|
61 | private:
|
---|
62 |
|
---|
63 | int x;
|
---|
64 | int y;
|
---|
65 | int z;
|
---|
66 | };
|
---|
67 |
|
---|
68 | /* VBoxUpdateData stuff */
|
---|
69 | QList <UpdateDay> VBoxUpdateData::mDayList = QList <UpdateDay>();
|
---|
70 |
|
---|
71 | void VBoxUpdateData::populate()
|
---|
72 | {
|
---|
73 | mDayList.clear();
|
---|
74 |
|
---|
75 | /* To avoid re-translation complexity all
|
---|
76 | * have to be retranslated separately. */
|
---|
77 |
|
---|
78 | /* Separately retranslate each day */
|
---|
79 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("1 day"), "1 d");
|
---|
80 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("2 days"), "2 d");
|
---|
81 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("3 days"), "3 d");
|
---|
82 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("4 days"), "4 d");
|
---|
83 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("5 days"), "5 d");
|
---|
84 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("6 days"), "6 d");
|
---|
85 |
|
---|
86 | /* Separately retranslate each week */
|
---|
87 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("1 week"), "1 w");
|
---|
88 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("2 weeks"), "2 w");
|
---|
89 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("3 weeks"), "3 w");
|
---|
90 |
|
---|
91 | /* Separately retranslate each month */
|
---|
92 | mDayList << UpdateDay (VBoxUpdateDlg::tr ("1 month"), "1 m");
|
---|
93 | }
|
---|
94 |
|
---|
95 | QStringList VBoxUpdateData::list()
|
---|
96 | {
|
---|
97 | QStringList result;
|
---|
98 | for (int i = 0; i < mDayList.size(); ++ i)
|
---|
99 | result << mDayList [i].val;
|
---|
100 | return result;
|
---|
101 | }
|
---|
102 |
|
---|
103 | VBoxUpdateData::VBoxUpdateData (const QString &aData)
|
---|
104 | : mData (aData)
|
---|
105 | , mPeriodIndex (Period1Day)
|
---|
106 | , mBranchIndex (BranchStable)
|
---|
107 | {
|
---|
108 | decode();
|
---|
109 | }
|
---|
110 |
|
---|
111 | VBoxUpdateData::VBoxUpdateData (PeriodType aPeriodIndex, BranchType aBranchIndex)
|
---|
112 | : mData (QString::null)
|
---|
113 | , mPeriodIndex (aPeriodIndex)
|
---|
114 | , mBranchIndex (aBranchIndex)
|
---|
115 | {
|
---|
116 | encode();
|
---|
117 | }
|
---|
118 |
|
---|
119 | bool VBoxUpdateData::isNecessary()
|
---|
120 | {
|
---|
121 | return mPeriodIndex != PeriodNever && QDate::currentDate() >= mDate;
|
---|
122 | }
|
---|
123 |
|
---|
124 | bool VBoxUpdateData::isNoNeedToCheck()
|
---|
125 | {
|
---|
126 | return mPeriodIndex == PeriodNever;
|
---|
127 | }
|
---|
128 |
|
---|
129 | QString VBoxUpdateData::data() const
|
---|
130 | {
|
---|
131 | return mData;
|
---|
132 | }
|
---|
133 |
|
---|
134 | VBoxUpdateData::PeriodType VBoxUpdateData::periodIndex() const
|
---|
135 | {
|
---|
136 | return mPeriodIndex;
|
---|
137 | }
|
---|
138 |
|
---|
139 | QString VBoxUpdateData::date() const
|
---|
140 | {
|
---|
141 | return mPeriodIndex == PeriodNever ? VBoxUpdateDlg::tr ("Never") :
|
---|
142 | mDate.toString (Qt::LocaleDate);
|
---|
143 | }
|
---|
144 |
|
---|
145 | VBoxUpdateData::BranchType VBoxUpdateData::branchIndex() const
|
---|
146 | {
|
---|
147 | return mBranchIndex;
|
---|
148 | }
|
---|
149 |
|
---|
150 | QString VBoxUpdateData::branchName() const
|
---|
151 | {
|
---|
152 | switch (mBranchIndex)
|
---|
153 | {
|
---|
154 | case BranchStable:
|
---|
155 | return "stable";
|
---|
156 | case BranchAllRelease:
|
---|
157 | return "allrelease";
|
---|
158 | case BranchWithBetas:
|
---|
159 | return "withbetas";
|
---|
160 | }
|
---|
161 | return QString::null;
|
---|
162 | }
|
---|
163 |
|
---|
164 | void VBoxUpdateData::decode()
|
---|
165 | {
|
---|
166 | /* Parse standard values */
|
---|
167 | if (mData == "never")
|
---|
168 | mPeriodIndex = PeriodNever;
|
---|
169 | /* Parse other values */
|
---|
170 | else
|
---|
171 | {
|
---|
172 | QStringList parser (mData.split (", ", QString::SkipEmptyParts));
|
---|
173 |
|
---|
174 | /* Parse 'period' value */
|
---|
175 | if (parser.size() > 0)
|
---|
176 | {
|
---|
177 | if (mDayList.isEmpty())
|
---|
178 | populate();
|
---|
179 | PeriodType index = (PeriodType) mDayList.indexOf (UpdateDay (QString::null, parser [0]));
|
---|
180 | mPeriodIndex = index == PeriodUndefined ? Period1Day : index;
|
---|
181 | }
|
---|
182 |
|
---|
183 | /* Parse 'date' value */
|
---|
184 | if (parser.size() > 1)
|
---|
185 | {
|
---|
186 | QDate date = QDate::fromString (parser [1], Qt::ISODate);
|
---|
187 | mDate = date.isValid() ? date : QDate::currentDate();
|
---|
188 | }
|
---|
189 |
|
---|
190 | /* Parse 'branch' value */
|
---|
191 | if (parser.size() > 2)
|
---|
192 | {
|
---|
193 | QString branch (parser [2]);
|
---|
194 | mBranchIndex = branch == "withbetas" ? BranchWithBetas :
|
---|
195 | branch == "allrelease" ? BranchAllRelease : BranchStable;
|
---|
196 | }
|
---|
197 | }
|
---|
198 | }
|
---|
199 |
|
---|
200 | void VBoxUpdateData::encode()
|
---|
201 | {
|
---|
202 | /* Encode standard values */
|
---|
203 | if (mPeriodIndex == PeriodNever)
|
---|
204 | mData = "never";
|
---|
205 | /* Encode other values */
|
---|
206 | else
|
---|
207 | {
|
---|
208 | /* Encode 'period' value */
|
---|
209 | if (mDayList.isEmpty())
|
---|
210 | populate();
|
---|
211 | QString remindPeriod = mDayList [mPeriodIndex].key;
|
---|
212 |
|
---|
213 | /* Encode 'date' value */
|
---|
214 | mDate = QDate::currentDate();
|
---|
215 | QStringList parser (remindPeriod.split (' '));
|
---|
216 | if (parser [1] == "d")
|
---|
217 | mDate = mDate.addDays (parser [0].toInt());
|
---|
218 | else if (parser [1] == "w")
|
---|
219 | mDate = mDate.addDays (parser [0].toInt() * 7);
|
---|
220 | else if (parser [1] == "m")
|
---|
221 | mDate = mDate.addMonths (parser [0].toInt());
|
---|
222 | QString remindDate = mDate.toString (Qt::ISODate);
|
---|
223 |
|
---|
224 | /* Encode 'branch' value */
|
---|
225 | QString branchValue = mBranchIndex == BranchWithBetas ? "withbetas" :
|
---|
226 | mBranchIndex == BranchAllRelease ? "allrelease" : "stable";
|
---|
227 |
|
---|
228 | /* Composite mData */
|
---|
229 | mData = QString ("%1, %2, %3").arg (remindPeriod, remindDate, branchValue);
|
---|
230 | }
|
---|
231 | }
|
---|
232 |
|
---|
233 | /* VBoxUpdateDlg stuff */
|
---|
234 | bool VBoxUpdateDlg::isNecessary()
|
---|
235 | {
|
---|
236 | VBoxUpdateData data (vboxGlobal().virtualBox().
|
---|
237 | GetExtraData (VBoxDefs::GUI_UpdateDate));
|
---|
238 |
|
---|
239 | return data.isNecessary();
|
---|
240 | }
|
---|
241 |
|
---|
242 | VBoxUpdateDlg::VBoxUpdateDlg (VBoxUpdateDlg **aSelf, bool aForceRun, QWidget *aParent)
|
---|
243 | : QIWithRetranslateUI <QDialog> (aParent)
|
---|
244 | , mSelf (aSelf)
|
---|
245 | , mUrl ("http://update.virtualbox.org/query.php")
|
---|
246 | , mHttp (new QIHttp (this, mUrl.host()))
|
---|
247 | , mForceRun (aForceRun)
|
---|
248 | {
|
---|
249 | /* Store external pointer to this dialog. */
|
---|
250 | *mSelf = this;
|
---|
251 |
|
---|
252 | /* Apply UI decorations */
|
---|
253 | Ui::VBoxUpdateDlg::setupUi (this);
|
---|
254 |
|
---|
255 | /* Apply window icons */
|
---|
256 | setWindowIcon(UIIconPool::iconSetFull(QSize (32, 32), QSize (16, 16),
|
---|
257 | ":/refresh_32px.png", ":/refresh_16px.png"));
|
---|
258 |
|
---|
259 | /* Setup other connections */
|
---|
260 | connect (mBtnCheck, SIGNAL (clicked()), this, SLOT (search()));
|
---|
261 |
|
---|
262 | /* Setup initial condition */
|
---|
263 | mPbCheck->setMinimumWidth (mLogoUpdate->width() + mLogoUpdate->frameWidth() * 2);
|
---|
264 | mPbCheck->hide();
|
---|
265 | mTextSuccessInfo->hide();
|
---|
266 | mTextFailureInfo->hide();
|
---|
267 | mTextNotFoundInfo->hide();
|
---|
268 |
|
---|
269 | /* Retranslate string constants */
|
---|
270 | retranslateUi();
|
---|
271 | }
|
---|
272 |
|
---|
273 | VBoxUpdateDlg::~VBoxUpdateDlg()
|
---|
274 | {
|
---|
275 | /* Erase dialog handle in config file. */
|
---|
276 | vboxGlobal().virtualBox().SetExtraData (VBoxDefs::GUI_UpdateDlgWinID, QString::null);
|
---|
277 |
|
---|
278 | /* Erase external pointer to this dialog. */
|
---|
279 | *mSelf = 0;
|
---|
280 | }
|
---|
281 |
|
---|
282 | void VBoxUpdateDlg::retranslateUi()
|
---|
283 | {
|
---|
284 | /* Translate uic generated strings */
|
---|
285 | Ui::VBoxUpdateDlg::retranslateUi (this);
|
---|
286 |
|
---|
287 | #if 0 /* All the text constants */
|
---|
288 | setWindowTitle (tr ("VirtualBox Update Wizard"));
|
---|
289 |
|
---|
290 | mPageUpdateHdr->setText (tr ("Check for Updates"));
|
---|
291 | mBtnCheck->setText (tr ("Chec&k"));
|
---|
292 | mBtnCancel->setText (tr ("Cancel"));
|
---|
293 |
|
---|
294 | mPageFinishHdr->setText (tr ("Summary"));
|
---|
295 | mBtnFinish->setText (tr ("&Close"));
|
---|
296 |
|
---|
297 | mTextUpdateInfo->setText (tr ("<p>This wizard will connect to the VirtualBox "
|
---|
298 | "web-site and check if a newer version of "
|
---|
299 | "VirtualBox is available.</p><p>Use the "
|
---|
300 | "<b>Check</b> button to check for a new version "
|
---|
301 | "now or the <b>Cancel</b> button if you do not "
|
---|
302 | "want to perform this check.</p><p>You can run "
|
---|
303 | "this wizard at any time by choosing <b>Check "
|
---|
304 | "for Updates...</b> from the <b>Help</b> menu.</p>"));
|
---|
305 |
|
---|
306 | mTextSuccessInfo->setText (tr ("<p>A new version of VirtualBox has been released! "
|
---|
307 | "Version <b>%1</b> is available at "
|
---|
308 | "<a href=\"http://www.virtualbox.org/\">virtualbox.org</a>.</p>"
|
---|
309 | "<p>You can download this version using the link:</p>"
|
---|
310 | "<p><a href=%2>%3</a></p>"));
|
---|
311 |
|
---|
312 | mTextFailureInfo->setText (tr ("<p>Unable to obtain the new version information "
|
---|
313 | "due to the following network error:</p><p><b>%1</b></p>"));
|
---|
314 |
|
---|
315 | mTextNotFoundInfo->setText (tr ("You are already running the most recent version of VirtualBox."));
|
---|
316 | #endif
|
---|
317 | }
|
---|
318 |
|
---|
319 | void VBoxUpdateDlg::accept()
|
---|
320 | {
|
---|
321 | /* Recalculate new update data */
|
---|
322 | VBoxUpdateData oldData (vboxGlobal().virtualBox().
|
---|
323 | GetExtraData (VBoxDefs::GUI_UpdateDate));
|
---|
324 | VBoxUpdateData newData (oldData.periodIndex(), oldData.branchIndex());
|
---|
325 | vboxGlobal().virtualBox().SetExtraData (VBoxDefs::GUI_UpdateDate,
|
---|
326 | newData.data());
|
---|
327 |
|
---|
328 | QDialog::accept();
|
---|
329 | }
|
---|
330 |
|
---|
331 | void VBoxUpdateDlg::search()
|
---|
332 | {
|
---|
333 | /* Calculate the count of checks left */
|
---|
334 | int count = 1;
|
---|
335 | QString sc = vboxGlobal().virtualBox().GetExtraData (VBoxDefs::GUI_UpdateCheckCount);
|
---|
336 | if (!sc.isEmpty())
|
---|
337 | {
|
---|
338 | bool ok = false;
|
---|
339 | int c = sc.toLongLong (&ok);
|
---|
340 | if (ok) count = c;
|
---|
341 | }
|
---|
342 |
|
---|
343 | /* Compose query */
|
---|
344 | QUrl url (mUrl);
|
---|
345 | url.addQueryItem ("platform", vboxGlobal().virtualBox().GetPackageType());
|
---|
346 | /* Branding: Check whether we have a local branding file which tells us our version suffix "FOO"
|
---|
347 | (e.g. 3.06.54321_FOO) to identify this installation */
|
---|
348 | if (vboxGlobal().brandingIsActive())
|
---|
349 | {
|
---|
350 | url.addQueryItem ("version", QString ("%1_%2_%3").arg (vboxGlobal().virtualBox().GetVersion())
|
---|
351 | .arg (vboxGlobal().virtualBox().GetRevision())
|
---|
352 | .arg (vboxGlobal().brandingGetKey("VerSuffix")));
|
---|
353 | }
|
---|
354 | else
|
---|
355 | {
|
---|
356 | /* Use hard coded version set by VBOX_VERSION_STRING */
|
---|
357 | url.addQueryItem ("version", QString ("%1_%2").arg (vboxGlobal().virtualBox().GetVersion())
|
---|
358 | .arg (vboxGlobal().virtualBox().GetRevision()));
|
---|
359 | }
|
---|
360 | url.addQueryItem ("count", QString::number (count));
|
---|
361 | url.addQueryItem ("branch", VBoxUpdateData (vboxGlobal().virtualBox().
|
---|
362 | GetExtraData (VBoxDefs::GUI_UpdateDate)).branchName());
|
---|
363 | QString userAgent (QString ("VirtualBox %1 <%2>")
|
---|
364 | .arg (vboxGlobal().virtualBox().GetVersion())
|
---|
365 | .arg (vboxGlobal().platformInfo()));
|
---|
366 |
|
---|
367 | /* Show progress bar */
|
---|
368 | mPbCheck->show();
|
---|
369 |
|
---|
370 | /* Send composed information */
|
---|
371 | QHttpRequestHeader header ("POST", url.toEncoded());
|
---|
372 | header.setValue ("Host", url.host());
|
---|
373 | header.setValue ("User-Agent", userAgent);
|
---|
374 | mHttp->disconnect (this);
|
---|
375 | connect (mHttp, SIGNAL (allIsDone (bool)), this, SLOT (searchResponse (bool)));
|
---|
376 | mHttp->request (header);
|
---|
377 | }
|
---|
378 |
|
---|
379 | void VBoxUpdateDlg::searchResponse (bool aError)
|
---|
380 | {
|
---|
381 | /* Block all the other incoming signals */
|
---|
382 | mHttp->disconnect (this);
|
---|
383 |
|
---|
384 | /* Process error if present */
|
---|
385 | if (aError)
|
---|
386 | return abortRequest (mHttp->errorString());
|
---|
387 |
|
---|
388 | /* Hide progress bar */
|
---|
389 | mPbCheck->hide();
|
---|
390 |
|
---|
391 | /* Parse incoming data */
|
---|
392 | QString responseData (mHttp->readAll());
|
---|
393 |
|
---|
394 | if (responseData.indexOf (QRegExp ("^\\d+\\.\\d+\\.\\d+ \\S+$")) == 0)
|
---|
395 | {
|
---|
396 | /* Newer version of necessary package found */
|
---|
397 | QStringList response = responseData.split (" ", QString::SkipEmptyParts);
|
---|
398 |
|
---|
399 | if (isHidden())
|
---|
400 | {
|
---|
401 | /* For background update */
|
---|
402 | vboxProblem().showUpdateSuccess (vboxGlobal().mainWindow(),
|
---|
403 | response [0], response [1]);
|
---|
404 | QTimer::singleShot (0, this, SLOT (accept()));
|
---|
405 | }
|
---|
406 | else
|
---|
407 | {
|
---|
408 | /* For wizard update */
|
---|
409 | mTextSuccessInfo->setText (mTextSuccessInfo->text()
|
---|
410 | .arg (response [0], response [1], response [1]));
|
---|
411 | mTextSuccessInfo->show();
|
---|
412 | mPageStack->setCurrentIndex (1);
|
---|
413 | }
|
---|
414 | }
|
---|
415 | else /* if (responseData == "UPTODATE") */
|
---|
416 | {
|
---|
417 | /* No newer version of necessary package found */
|
---|
418 | if (isHidden())
|
---|
419 | {
|
---|
420 | /* For background update */
|
---|
421 | if (mForceRun)
|
---|
422 | vboxProblem().showUpdateNotFound (vboxGlobal().mainWindow());
|
---|
423 | QTimer::singleShot (0, this, SLOT (accept()));
|
---|
424 | }
|
---|
425 | else
|
---|
426 | {
|
---|
427 | /* For wizard update */
|
---|
428 | mTextNotFoundInfo->show();
|
---|
429 | mPageStack->setCurrentIndex (1);
|
---|
430 | }
|
---|
431 | }
|
---|
432 |
|
---|
433 | /* Save left count of checks */
|
---|
434 | int count = 1;
|
---|
435 | bool ok = false;
|
---|
436 | QString sc = vboxGlobal().virtualBox().GetExtraData (VBoxDefs::GUI_UpdateCheckCount);
|
---|
437 | if (!sc.isEmpty())
|
---|
438 | count = sc.toLongLong (&ok);
|
---|
439 | vboxGlobal().virtualBox().SetExtraData (VBoxDefs::GUI_UpdateCheckCount,
|
---|
440 | QString ("%1").arg ((qulonglong) count + 1));
|
---|
441 | }
|
---|
442 |
|
---|
443 | void VBoxUpdateDlg::abortRequest (const QString &aReason)
|
---|
444 | {
|
---|
445 | /* Hide progress bar */
|
---|
446 | mPbCheck->hide();
|
---|
447 |
|
---|
448 | if (isHidden())
|
---|
449 | {
|
---|
450 | /* For background update */
|
---|
451 | if (mForceRun)
|
---|
452 | vboxProblem().showUpdateFailure (vboxGlobal().mainWindow(), aReason);
|
---|
453 | QTimer::singleShot (0, this, SLOT (accept()));
|
---|
454 | }
|
---|
455 | else
|
---|
456 | {
|
---|
457 | /* For wizard update */
|
---|
458 | mTextFailureInfo->setText (mTextFailureInfo->text().arg (aReason));
|
---|
459 | mTextFailureInfo->show();
|
---|
460 | mPageStack->setCurrentIndex (1);
|
---|
461 | }
|
---|
462 | }
|
---|
463 |
|
---|