Changeset 4432 in vbox for trunk/src/VBox
- Timestamp:
- Aug 30, 2007 8:28:11 AM (17 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r4398 r4432 138 138 src/VBoxDownloaderWgt.cpp \ 139 139 src/VBoxVMListBox.cpp \ 140 src/VBoxFrameBuffer.cpp 140 src/VBoxFrameBuffer.cpp \ 141 src/HappyHttp.cpp 141 142 142 143 VirtualBox_SOURCES.win += \ … … 154 155 src/darwin/VBoxAquaStyle.cpp \ 155 156 src/darwin/VBoxUtils-darwin.cpp 157 158 src/HappyHttp.cpp_CXXFLAGS += -fexceptions 159 src/VBoxDownloaderWgt.cpp_CXXFLAGS += -fexceptions 156 160 157 161 ## @todo how to detect what tool is used? -
trunk/src/VBox/Frontends/VirtualBox/include/VBoxDownloaderWgt.h
r4071 r4432 20 20 #define __VBoxDownloaderWgt_h__ 21 21 22 #include "HappyHttp.h" 22 23 #include "qwidget.h" 23 24 #include "qurl.h" 25 #include "qmutex.h" 24 26 class QStatusBar; 25 27 class QAction; 26 class QHttpResponseHeader;27 class QHttp;28 28 class QProgressBar; 29 29 class QToolButton; 30 class QThread; 31 class QTimer; 32 typedef happyhttp::Connection HConnect; 30 33 31 34 /** class VBoxDownloaderWgt … … 47 50 void languageChange(); 48 51 52 bool isCheckingPresence() { return mIsChecking; } 53 49 54 private slots: 50 51 /* This slot is used to handle the progress of the file-downloading52 * procedure. It also checks the downloading status for the file53 * presence verifying purposes. */54 void processProgress (int aRead, int aTotal);55 56 /* This slot is used to handle the finish signal of every operation's57 * response. It is used to display the errors occurred during the download58 * operation and for the received-buffer serialization procedure. */59 void processFinished (int, bool aError);60 61 /* This slot is used to handle the header responses about the62 * requested operations. Watches for the header's status-code. */63 void processResponse (const QHttpResponseHeader &aHeader);64 55 65 56 /* This slot is used to control the connection timeout. */ … … 75 66 76 67 private: 68 69 /* Used to process all the widget events */ 70 bool event (QEvent *aEvent); 77 71 78 72 /* This function is used to make a request to get a file */ … … 90 84 void abortDownload (const QString &aReason = QString::null); 91 85 92 QStatusBar *mStatusBar; 86 void abortConnection(); 87 93 88 QUrl mUrl; 94 89 QString mTarget; 95 Q Http *mHttp;96 bool mIsChecking;90 QStatusBar *mStatusBar; 91 QAction *mAction; 97 92 QProgressBar *mProgressBar; 98 93 QToolButton *mCancelButton; 99 QAction *mAction; 100 int mStatus; 101 bool mConnectDone; 94 bool mIsChecking; 102 95 bool mSuicide; 96 HConnect *mConn; 97 QThread *mRequestThread; 98 QMutex mMutex; 99 QByteArray mDataArray; 100 QDataStream mDataStream; 101 QTimer *mTimeout; 103 102 }; 104 103 -
trunk/src/VBox/Frontends/VirtualBox/src/VBoxDownloaderWgt.cpp
r4397 r4432 26 26 #include "qtoolbutton.h" 27 27 #include "qlayout.h" 28 #include "qhttp.h"29 28 #include "qstatusbar.h" 30 29 #include "qdir.h" 31 30 #include "qtimer.h" 32 31 32 /* These notifications are used to notify the GUI thread about different 33 * downloading events: Downloading Started, Downloading in Progress, 34 * Downloading Finished. */ 35 enum 36 { 37 StartDownloadEventType = QEvent::User + 100, 38 ProcessDownloadEventType, 39 FinishDownloadEventType, 40 ErrorDownloadEventType 41 }; 42 43 class StartDownloadEvent : public QEvent 44 { 45 public: 46 StartDownloadEvent (int aStatus, long aSize) 47 : QEvent ((QEvent::Type) StartDownloadEventType) 48 , mStatus (aStatus), mSize (aSize) {} 49 50 int mStatus; 51 long mSize; 52 }; 53 54 class ProcessDownloadEvent : public QEvent 55 { 56 public: 57 ProcessDownloadEvent (const char *aData, ulong aSize) 58 : QEvent ((QEvent::Type) ProcessDownloadEventType) 59 , mData (QByteArray().duplicate (aData, aSize)) {} 60 61 QByteArray mData; 62 }; 63 64 class FinishDownloadEvent : public QEvent 65 { 66 public: 67 FinishDownloadEvent() 68 : QEvent ((QEvent::Type) FinishDownloadEventType) {} 69 }; 70 71 class ErrorDownloadEvent : public QEvent 72 { 73 public: 74 ErrorDownloadEvent (const QString &aInfo) 75 : QEvent ((QEvent::Type) ErrorDownloadEventType) 76 , mInfo (aInfo) {} 77 78 QString mInfo; 79 }; 80 81 /* This callback is used to handle the file-downloading procedure 82 * beginning. It checks the downloading status for the file 83 * presence verifying purposes. */ 84 void OnBegin (const happyhttp::Response *aResponse, void *aUserdata) 85 { 86 VBoxDownloaderWgt *loader = static_cast<VBoxDownloaderWgt*> (aUserdata); 87 if (loader->isCheckingPresence()) 88 { 89 int status = aResponse->getstatus(); 90 QString contentLength = aResponse->getheader ("Content-length"); 91 92 QApplication::postEvent (loader, 93 new StartDownloadEvent (status, contentLength.toLong())); 94 } 95 } 96 97 /* This callback is used to handle the progress of the file-downloading 98 * procedure. It also checks the downloading status for the file 99 * presence verifying purposes. */ 100 void OnData (const happyhttp::Response*, void *aUserdata, 101 const unsigned char *aData, int aSize) 102 { 103 VBoxDownloaderWgt *loader = static_cast<VBoxDownloaderWgt*> (aUserdata); 104 if (!loader->isCheckingPresence()) 105 { 106 QApplication::postEvent (loader, 107 new ProcessDownloadEvent ((const char*)aData, aSize)); 108 } 109 } 110 111 /* This callback is used to handle the finish signal of every operation's 112 * response. It is used to display the errors occurred during the download 113 * operation and for the received-buffer serialization procedure. */ 114 void OnComplete (const happyhttp::Response*, void *aUserdata) 115 { 116 VBoxDownloaderWgt *loader = static_cast<VBoxDownloaderWgt*> (aUserdata); 117 if (!loader->isCheckingPresence()) 118 QApplication::postEvent (loader, 119 new FinishDownloadEvent()); 120 } 121 33 122 VBoxDownloaderWgt::VBoxDownloaderWgt (QStatusBar *aStatusBar, QAction *aAction, 34 123 const QString &aUrl, const QString &aTarget) 35 124 : QWidget (0, "VBoxDownloaderWgt") 36 , mStatusBar (aStatusBar)37 125 , mUrl (aUrl), mTarget (aTarget) 38 , m Http (0), mIsChecking (true)126 , mStatusBar (aStatusBar), mAction (aAction) 39 127 , mProgressBar (0), mCancelButton (0) 40 , mAction (aAction), mStatus (0) 41 , mConnectDone (false), mSuicide (false) 128 , mIsChecking (true), mSuicide (false) 129 , mConn (new HConnect (mUrl.host(), 80)) 130 , mRequestThread (0) 131 , mDataStream (mDataArray, IO_WriteOnly) 132 , mTimeout (new QTimer (this)) 42 133 { 43 134 /* Disable the associated action */ 44 135 mAction->setEnabled (false); 136 connect (mTimeout, SIGNAL (timeout()), 137 this, SLOT (processTimeout())); 45 138 46 139 /* Drawing itself */ … … 55 148 mCancelButton->setAutoRaise (true); 56 149 mCancelButton->setFocusPolicy (TabFocus); 57 QSpacerItem *spacer = new QSpacerItem (0, 0, QSizePolicy::Expanding,58 QSizePolicy::Fixed);150 connect (mCancelButton, SIGNAL (clicked()), 151 this, SLOT (processAbort())); 59 152 60 153 QHBoxLayout *mainLayout = new QHBoxLayout (this); 61 154 mainLayout->addWidget (mProgressBar); 62 155 mainLayout->addWidget (mCancelButton); 63 mainLayout->addItem (spacer); 156 mainLayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, 157 QSizePolicy::Fixed)); 64 158 65 159 /* Select the product version */ 66 160 QString version = vboxGlobal().virtualBox().GetVersion(); 67 161 68 #if !defined(VBOX_WITHOUT_QHTTP) 69 /* Initialize url operator */ 70 mHttp = new QHttp (this, "mHttp"); 71 mHttp->setHost (mUrl.host()); 72 73 /* Setup connections */ 74 connect (mHttp, SIGNAL (dataReadProgress (int, int)), 75 this, SLOT (processProgress (int, int))); 76 connect (mHttp, SIGNAL (requestFinished (int, bool)), 77 this, SLOT (processFinished (int, bool))); 78 connect (mHttp, SIGNAL (responseHeaderReceived (const QHttpResponseHeader&)), 79 this, SLOT (processResponse (const QHttpResponseHeader&))); 80 #endif /* !VBOX_WITHOUT_QHTTP */ 81 connect (mCancelButton, SIGNAL (clicked()), 82 this, SLOT (processAbort())); 162 /* Prepare the connection */ 163 mConn->setcallbacks (OnBegin, OnData, OnComplete, this); 83 164 84 165 languageChange(); … … 101 182 } 102 183 103 /* This slot is used to handle the progress of the file-downloading104 * procedure. It also checks the downloading status for the file105 * presence verifying purposes. */106 void VBoxDownloaderWgt::processProgress (int aRead, int aTotal)107 {108 mConnectDone = true;109 if (aTotal != -1)110 {111 if (mIsChecking)112 {113 #if !defined(VBOX_WITHOUT_QHTTP)114 mHttp->abort();115 #endif116 if (mStatus == 404)117 abortDownload (tr ("Could not locate the file on "118 "the server (response: %1).")119 .arg (mStatus));120 else121 processFile (aTotal);122 }123 else124 mProgressBar->setProgress (aRead, aTotal);125 }126 else127 abortDownload (tr ("Could not determine the file size."));128 }129 130 /* This slot is used to handle the finish signal of every operation's131 * response. It is used to display the errors occurred during the download132 * operation and for the received-buffer serialization procedure. */133 void VBoxDownloaderWgt::processFinished (int, bool aError)134 {135 #if !defined(VBOX_WITHOUT_QHTTP)136 if (aError && mHttp->error() != QHttp::Aborted)137 {138 mConnectDone = true;139 QString reason = mIsChecking ?140 tr ("Could not connect to the server (%1).") :141 tr ("Could not download the file (%1).");142 abortDownload (reason.arg (mHttp->errorString()));143 }144 else if (!aError && !mIsChecking)145 {146 mHttp->abort();147 /* Serialize the incoming buffer into the .iso image. */148 while (true)149 {150 QFile file (mTarget);151 if (file.open (IO_WriteOnly))152 {153 file.writeBlock (mHttp->readAll());154 file.close();155 /// @todo the below action is not part of the generic156 // VBoxDownloaderWgt functionality, so this class should just157 // emit a signal when it is done saving the downloaded file158 // (succeeded or failed).159 int rc = vboxProblem().confirmMountAdditions (mUrl.toString(),160 QDir::convertSeparators (mTarget));161 if (rc == QIMessageBox::Yes)162 vboxGlobal().consoleWnd().installGuestAdditionsFrom (mTarget);163 QTimer::singleShot (0, this, SLOT (suicide()));164 return;165 }166 else167 {168 vboxProblem().message (mStatusBar->topLevelWidget(),169 VBoxProblemReporter::Error,170 tr ("<p>Failed to save the downloaded file as "171 "<nobr><b>%1</b>.</nobr></p>")172 .arg (QDir::convertSeparators (mTarget)));173 }174 175 /// @todo read the todo above (probably should just parametrize176 /// the title)177 QString target = vboxGlobal().getExistingDirectory (178 QFileInfo (mTarget).dirPath(), this, "selectSaveDir",179 tr ("Select folder to save Guest Additions image to"), true);180 if (target.isNull())181 {182 QTimer::singleShot (0, this, SLOT (suicide()));183 return;184 }185 else186 mTarget = QDir (target).absFilePath (QFileInfo (mTarget).fileName());187 };188 }189 #else /* VBOX_WITHOUT_QHTTP */190 NOREF (aError);191 #endif /* VBOX_WITHOUT_QHTTP */192 }193 194 /* This slot is used to handle the header responses about the195 * requested operations. Watches for the header's status-code. */196 void VBoxDownloaderWgt::processResponse (const QHttpResponseHeader &aHeader)197 {198 #if !defined(VBOX_WITHOUT_QHTTP)199 mStatus = aHeader.statusCode();200 #endif201 }202 203 184 /* This slot is used to control the connection timeout. */ 204 185 void VBoxDownloaderWgt::processTimeout() 205 186 { 206 if (mConnectDone)207 return;208 #if !defined(VBOX_WITHOUT_QHTTP)209 mHttp->abort();210 187 abortDownload (tr ("Connection timed out.")); 211 #endif212 188 } 213 189 … … 215 191 void VBoxDownloaderWgt::processAbort() 216 192 { 217 #if !defined(VBOX_WITHOUT_QHTTP)218 mConnectDone = true;219 mHttp->abort();220 193 abortDownload (tr ("The download process has been cancelled " 221 194 "by the user.")); 222 #endif223 195 } 224 196 … … 228 200 void VBoxDownloaderWgt::suicide() 229 201 { 202 delete mRequestThread; 203 delete mConn; 204 230 205 mAction->setEnabled (true); 231 206 mStatusBar->removeWidget (this); … … 233 208 } 234 209 210 /* Used to process all the widget events */ 211 bool VBoxDownloaderWgt::event (QEvent *aEvent) 212 { 213 switch (aEvent->type()) 214 { 215 case StartDownloadEventType: 216 { 217 StartDownloadEvent *e = static_cast<StartDownloadEvent*> (aEvent); 218 219 mTimeout->stop(); 220 if (e->mStatus == 404) 221 abortDownload (tr ("Could not locate the file on " 222 "the server (response: %1).").arg (e->mStatus)); 223 else 224 processFile (e->mSize); 225 226 return true; 227 } 228 case ProcessDownloadEventType: 229 { 230 ProcessDownloadEvent *e = static_cast<ProcessDownloadEvent*> (aEvent); 231 232 mTimeout->start (20000, true); 233 mProgressBar->setProgress (mProgressBar->progress() + e->mData.size()); 234 mDataStream.writeRawBytes (e->mData.data(), e->mData.size()); 235 236 return true; 237 } 238 case FinishDownloadEventType: 239 { 240 mTimeout->stop(); 241 242 /* Serialize the incoming buffer into the .iso image. */ 243 while (true) 244 { 245 QFile file (mTarget); 246 if (file.open (IO_WriteOnly)) 247 { 248 file.writeBlock (mDataArray); 249 file.close(); 250 /// @todo the below action is not part of the generic 251 // VBoxDownloaderWgt functionality, so this class should just 252 // emit a signal when it is done saving the downloaded file 253 // (succeeded or failed). 254 int rc = vboxProblem().confirmMountAdditions (mUrl.toString(), 255 QDir::convertSeparators (mTarget)); 256 if (rc == QIMessageBox::Yes) 257 vboxGlobal().consoleWnd().installGuestAdditionsFrom (mTarget); 258 QTimer::singleShot (0, this, SLOT (suicide())); 259 break; 260 } 261 else 262 { 263 vboxProblem().message (mStatusBar->topLevelWidget(), 264 VBoxProblemReporter::Error, 265 tr ("<p>Failed to save the downloaded file as " 266 "<nobr><b>%1</b>.</nobr></p>") 267 .arg (QDir::convertSeparators (mTarget))); 268 } 269 270 /// @todo read the todo above (probably should just parametrize 271 /// the title) 272 QString target = vboxGlobal().getExistingDirectory ( 273 QFileInfo (mTarget).dirPath(), this, "selectSaveDir", 274 tr ("Select folder to save Guest Additions image to"), true); 275 if (target.isNull()) 276 QTimer::singleShot (0, this, SLOT (suicide())); 277 else 278 mTarget = QDir (target).absFilePath (QFileInfo (mTarget).fileName()); 279 } 280 281 return true; 282 } 283 case ErrorDownloadEventType: 284 { 285 ErrorDownloadEvent *e = static_cast<ErrorDownloadEvent*> (aEvent); 286 287 abortDownload (e->mInfo); 288 289 return true; 290 } 291 default: 292 break; 293 } 294 295 return QWidget::event (aEvent); 296 } 297 235 298 /* This function is used to make a request to get a file */ 236 299 void VBoxDownloaderWgt::getFile() 237 300 { 238 mConnectDone = false; 239 #if !defined(VBOX_WITHOUT_QHTTP) 240 mHttp->get (mUrl.path()); 241 #endif 242 QTimer::singleShot (5000, this, SLOT (processTimeout())); 301 /* Http request thread class */ 302 class Thread : public QThread 303 { 304 public: 305 306 Thread (VBoxDownloaderWgt *aParent, HConnect *aConn, 307 const QString &aPath, QMutex *aMutex) 308 : mParent (aParent), mConn (aConn) 309 , mPath (aPath), mMutex (aMutex) {} 310 311 virtual void run() 312 { 313 try 314 { 315 mConn->request ("GET", mPath); 316 while (mConn->outstanding()) 317 { 318 QMutexLocker locker (mMutex); 319 mConn->pump(); 320 } 321 } 322 catch (happyhttp::Wobbly &ex) 323 { 324 QApplication::postEvent (mParent, 325 new ErrorDownloadEvent (ex.what())); 326 } 327 } 328 329 private: 330 331 VBoxDownloaderWgt *mParent; 332 HConnect *mConn; 333 QString mPath; 334 QMutex *mMutex; 335 }; 336 337 if (!mRequestThread) 338 mRequestThread = new Thread (this, mConn, mUrl.path(), &mMutex); 339 mRequestThread->start(); 340 mTimeout->start (20000, true); 243 341 } 244 342 … … 248 346 void VBoxDownloaderWgt::processFile (int aSize) 249 347 { 348 abortConnection(); 349 250 350 /// @todo the below action is not part of the generic 251 351 // VBoxDownloaderWgt functionality, so this class should just … … 253 353 254 354 /* Ask user about GA image downloading */ 255 int rc = vboxProblem(). 256 confirmDownloadAdditions (mUrl.toString(), aSize); 355 int rc = vboxProblem().confirmDownloadAdditions (mUrl.toString(), aSize); 257 356 if (rc == QIMessageBox::Yes) 258 357 { 259 358 mIsChecking = false; 359 mProgressBar->setTotalSteps (aSize); 260 360 getFile(); 261 361 } … … 264 364 } 265 365 266 /* This wrapper displays an error message box (unless @aReason is366 /* This wrapper displays an error message box (unless aReason is 267 367 * QString::null) with the cause of the download procedure 268 368 * termination. After the message box is dismissed, the downloader signals … … 270 370 void VBoxDownloaderWgt::abortDownload (const QString &aReason) 271 371 { 372 abortConnection(); 373 272 374 /* Protect against double kill request. */ 273 375 if (mSuicide) … … 286 388 } 287 389 390 void VBoxDownloaderWgt::abortConnection() 391 { 392 mMutex.lock(); 393 mConn->close(); 394 mMutex.unlock(); 395 } 396
Note:
See TracChangeset
for help on using the changeset viewer.