2. Checking for update
In the header file we need to set up a few variables and function declarations:
class GUI : public QMainWindow{ Q_OBJECT public: QString VERSION = "0.5.0"; // Current version // Self Update QBuffer xmldata; int getRequestId; int filedownloaded; QString latest_version; vector<QString> filelist; // The list of files to be downloaded QFile *file; QHttp *http; QHttp *dhttp; ... private slots: // Self Update void self_update(); void self_update_parse(int requestId, bool error); void self_update_download(int i); void self_update_complete(int requestId, bool error); ... };
While you set up the GUI, remember to connect the variable to the slot.
void GUI::GUI(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags){ ... // Self update http = new QHttp(this); dhttp = new QHttp(this); connect(http, SIGNAL(requestFinished(int,bool)),this, SLOT(self_update_parse(int, bool))); connect(dhttp, SIGNAL(requestFinished(int,bool)),this, SLOT(self_update_complete(int, bool))); ... } void GUI::setupMenu(){ ... QMenu *helpmenu = new QMenu(tr("Help"), this); ... menuBar()->addMenu(helpmenu); a = new QAction(tr("Check for Update"), this); connect(a, SIGNAL(triggered()), this, SLOT(self_update())); helpmenu->addAction(a); }
Let’s go through the functions. The function self_update is the first to be triggered when user click on “Check for Update” option from the menu.
void GUI::self_update(){ QUrl url("http://address_to_the_file/latest.xml"); http->setHost(url.host()); xmldata.open(QBuffer::ReadWrite); getRequestId = http->get(url.path(), &xmldata); }
Upon the HTTP call’s completion, the function self_update_parse is triggered
void GUI::self_update_parse(int requestId, bool error){ // If the requests don't match, exit if(requestId != getRequestId) { return; } // Read & parse the data xmldata.seek(0); xmldata.readAll(); // Check file type QDomDocument doc( "XML" ); if (!doc.setContent(xmldata.buffer(), true)) { return; } QDomElement root = doc.documentElement(); if( root.tagName() != "appname" ){ return; } // Loop over main nodes latest_version.clear(); filelist.clear(); QDomNode mainnode = root.firstChild(); while( !mainnode.isNull() ){ QDomNode subnode = mainnode.firstChild(); if( !subnode.isNull() ) { // Loop over each elements in subnodes while(! subnode.isNull()){ QDomElement e = subnode.toElement(); if(!e.isNull()){ // Start parsing, finally if( e.tagName() == "version" ){ latest_version = e.attribute("value",""); } else if( e.tagName() == "file" ){ filelist.push_back(e.attribute("value","")); } } subnode = subnode.nextSibling(); } } mainnode = mainnode.nextSibling(); } // Compare current version with the one on the server if(this->VERSION < latest_version){ std::string htmlText = "<html>" "<b>New Version of App Is Available:</b> " + latest_version.toStdString() + "<br><br>" "Would you like to download the following updated files:" "<br><br>"; // Add the list of files to download list for(int i=0; i<filelist.size(); i++){ htmlText += "- " + filelist[i].right(filelist[i].length() - filelist[i].lastIndexOf(tr("/")) - 1).toStdString() + "<br><br>"; } htmlText += "<br></html>"; // Check if user wants to download if (QMessageBox::question(this, tr("New Version Available"), tr(htmlText.c_str()), QMessageBox::Yes, QMessageBox::No) == QMessageBox::No){ return; } // Start Download filedownloaded = 0; self_update_download(0); } else{ // Update success dialog QMessageBox::information(this, tr("Update"), tr("You are using the latest version.")); } }
2 Responses to “Implement an auto update system”
April 29th, 2009 at 3:15 AM
Hi Roland, I like the article, I have a small concern i am a C # developer, so i was looking at the code not very througly, I could not understand a part ,
I understood that we created a temp folder and downloaded latest files in them, we also copied all current files to a new folder for backup how can i rename the current files to .old extension these files are already in use and also how i am going to tell my icon for instance to load from temp folder where new files are present.
thanks
April 29th, 2009 at 10:01 AM
Hi Kaleem,
I’m not too familiar with C#, but I will try my best to answer your question.
Files which are in use cannot be deleted, but they can be renamed. In the example above, there is a vector filelist that stores a list of files to be updated. So just loop through it to and rename all the existing files in it.
As far as I know, there is a function in C# is good for this purpose: System.IO.File.Move(@”C:\From.txt”, @”C:\TO.txt”);. Use it to add “.old” to all the existing files.
After that, you can copy the newly downloaded files into the working folder since there is no file overwriting issue.
In order for the new files to take effect, the program MUST be restarted. And in your main loop, before anything else take place, check if the working folder has any “.old” file, if so, delete them all.
I hope that answers your question.