QNetwork Reply from QNetworkAccessManager - qt

The following code is from an example shows how to use QNetworkAccessManager to download things.
void Downloader::replyFinished (QNetworkReply *reply)
{
if(reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString();
qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
QFile *file = new QFile("C:/Qt/Dummy/downloaded.txt");
if(file->open(QFile::Append))
{
file->write(reply->readAll());
file->flush();
file->close();
}
delete file;
}
reply->deleteLater();
}
My question is do we have to call reply->deleteLater(); here? If we don't call it, when we perform QNetworkAccessManager::get() call the second time, will the QNetworkReply* in the slot be the same QNetworkReply* ?

If you don't call deleteLater(), the QNetworkReply object will be leaked and its memory not freed. A second get() call will create a new QNetworkReply object.

Related

How can I make my waitForBytesWritten call non blocking ?

I have this function :
bool TCPClient::sendPacket(Protocol::Packet &packet)
{
if(this->tcpSocket->state() == QAbstractSocket::ConnectedState)
{
std::cout << "writing ..." << std::endl;
std::cout << sizeof(BabelPacket) + packet.dataLength << std::endl;
this->tcpSocket->write((const char *)&packet, sizeof(Protocol::BabelPacket) + packet.dataLength);
return this->tcpSocket->waitForBytesWritten(-1);
}
else
{
std::cout << "socket close" << std::endl;
return false;
}
}
But when I called it, it blocks my GUI.
Have you got an idea how I can make this call non blocking, and still have the readyRead signal triggered ?
Thanks

Strange reply when uploading zip file to amazon S3 using REST ,QT and PUT request

iam trying to upload zip file to S3 amazon but i have problem.
i am using QT : sending request and receiving reply.
i am sending the URL with zip file here is the code :
QFile *file = new QFile(fileName);
QString fileSize = QString::number(file->size());
file->open(QIODevice::ReadOnly);
QByteArray data(file->readAll());
QNetworkRequest req;
QNetworkReply* rep;
req.setUrl(QUrl(url /*cant post the real URL*/));
req.setRawHeader(QString("Content-Length").toUtf8(), fileSize.toUtf8());
rep = m_manager->post(req, data);
connect(rep, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
CheckReply(rep);
and here is CheckReply function
bool CheckReply(QNetworkReply *reply)
{
if (reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
return false;
}
else
{
qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString();
qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
return true;
}
}
the problem is , CheckReply() shows this msg : "Error downloading -request URL-".
why this happens , it is upload NOT download.
thanks
OK i find the problem , in case any one face the same problem.
the bug was that i use QUrl(QSting) , to set the request url.
instead of that use this : QUrl::fromEncoded(QByteArray) or
QUrl::fromEncoded(/your QString/.toUtf8()).

QDialog show is does not happen immediately

I have a sever client application and in the beginning client loads data from server. I have a dialog showing status of getting data from server (has progress bar). But when I call the function the dialog appears with no contents in it with white background and suddenly changes to completed status.
void SystemScreen::loadServerData()
{
qDebug() << Q_FUNC_INFO << "Invoked";
if (NULL != mpDataManagerDlg)
{
qDebug() << Q_FUNC_INFO << "show progres screen";
mpDataManagerDlg->showScreen();
}
loadData();
qDebug() << Q_FUNC_INFO << "Exits";
}
void SystemScreen::loadData()
{
qDebug() << Q_FUNC_INFO << "Invoked";
if (NULL != mpDataManager)
{
mpDataManager->loadDataFromServer();
}
qDebug() << Q_FUNC_INFO << "Exits";
}
I feel that dialog is displayed only after loadData() function is completed. Is there any alternative to do this?
I used a timer to start
QTimer::singleShot(100, this, SLOT(loadData()));
But then I have some trouble in getting data. ie data is empty if I read suddenly.
EDIT:
void DataManagerDialog::setDefault()
{
qDebug() << Q_FUNC_INFO << "Invoked";
setProgressBar(0);
setProgressBarColor(false);
ui->deptFailButton->hide();
ui->deptOkButton->hide();
ui->deptLabel->setStyleSheet("color:gray");
ui->subGroupFailButton->hide();
ui->subGroupOkButton->hide();
ui->subGroupLabel->setStyleSheet("color:gray");
ui->itemFailButton->hide();
ui->itemOkButton->hide();
ui->itemLabel->setStyleSheet("color:gray");
ui->salesBtnFailButton->hide();
ui->salesBtnOkButton->hide();
ui->salesBtnLabel->setStyleSheet("color:gray");
qDebug() << Q_FUNC_INFO << "Exits";
}
void DataManagerDialog::alignCenter()
{
qDebug() << Q_FUNC_INFO << "Invoked";
QWidget *par = parentWidget();
if (par)
{
int x = width()/2;
int y = height()/2;
QPoint mid(mapToGlobal(QPoint(x, y)));
int px = par->width()/2;
int py = par->height()/2;
QPoint parMid(mapToGlobal(QPoint(px, py)));
move(parMid.x()-mid.x(), parMid.y()-mid.y());
}
qDebug() << Q_FUNC_INFO << "Exits";
}
void DataManagerDialog::showScreen()
{
setDefault();
alignCenter();
show();
}
You probably do not enter the event loop.
Try to call QCoreApplication::processEvents() from time to time in mpDataManager->loadDataFromServer() to update the GUI.
From the processEvents documentation :
You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).
Edit added after getting feedback from the comments
A better approach would be to send signals in your loadDataFromServer() method with the status information and have a slot listen to the signal and update the GUI.
Here a prototype illustrating the idea :
void mpDataManagerDlg::loadDataFromServer() {
while(true) {
// do some work
int progress = // some value
emit updateDialogSignal(progress);
}
}
// in your dialog class
public slots:
void DataManagerDialog::updateDialog(int progress) {
// update gui
}
More about signals and slots can be found here.

qt: unable to read image from url

I have two list of images to be downloaded from network. I use qnetworkaccessmanager to get image from url. But on the reply slot there is no image data with the reply. :( I am not able to figure out where am I going wrong.. If someone is able to figure out, it would be helpful :)
void SyncDialog::getImages()
{
qDebug() << Q_FUNC_INFO << "Invoked";
int groupMasterCount = mSyncMasterData.groupMasterList.count();
qDebug() << Q_FUNC_INFO << "groupmastercout" << groupMasterCount;
for (int i = 0 ; i < groupMasterCount; ++i)
{
GroupMaster groupItem = mSyncMasterData.groupMasterList.at(i);
QNetworkReply *reply =
mImageGetNwMgr.get(QNetworkRequest(QUrl(groupItem.image)));
reply->setProperty("name", QVariant("G_" + groupItem.groupCode));
connect(reply, SIGNAL(readyRead()), this, SLOT(saveImage()));
qDebug() << Q_FUNC_INFO << "get call reply" << reply->readAll();
qDebug() << Q_FUNC_INFO << "get url" << groupItem.image;
mSyncMasterData.groupMasterList[i].image.clear();
#ifdef Q_OS_WIN
mSyncMasterData.groupMasterList[i].image = "C:/POS/Images/G_"
+groupItem.groupCode;
#else
mSyncMasterData.groupMasterList[i].image = "/mnt/sdcard/POS/Images/G_"
+groupItem.groupCode;
#endif
}
int itemMasterCount = mSyncMasterData.itemMasterList.count();
qDebug() << Q_FUNC_INFO << "itemmastercout" << itemMasterCount;
for (int i = 0 ; i < itemMasterCount; ++i)
{
ItemMaster item = mSyncMasterData.itemMasterList.at(i);
QNetworkReply *reply =
mImageGetNwMgr.get(QNetworkRequest(QUrl(item.imagePath)));
reply->setProperty("name", QVariant("I_" + item.itemCode));
connect(reply, SIGNAL(readyRead()), this, SLOT(saveImage()));
qDebug() << Q_FUNC_INFO << "get call reply" << reply->readAll();
qDebug() << Q_FUNC_INFO << "get url" << item.imagePath;
mSyncMasterData.itemMasterList[i].imagePath.clear();
#ifdef Q_OS_WIN
mSyncMasterData.itemMasterList[i].imagePath = "C:/POS/Images/I_"
+item.itemCode;
#else
mSyncMasterData.itemMasterList[i].imagePath = "/mnt/sdcard/POS/Images/G_"
+item.itemCode;
#endif
}
qDebug() << Q_FUNC_INFO << "Exits";
}
In my slot I save images , but in reply->readAll gives me ""
void SyncDialog::saveImage()
{
qDebug() << Q_FUNC_INFO << "Invoked";
QObject *senderObj = sender();
QNetworkReply *reply = qobject_cast<QNetworkReply*>(senderObj);
QImage* img2 = new QImage();
img2->loadFromData(reply->readAll());
qDebug() << Q_FUNC_INFO << "image nw reply" << reply->readAll();
QString imageName = reply->property("name").toString();
qDebug() << Q_FUNC_INFO << "imageName" << imageName;
if(img2->isNull())
{
qDebug() << Q_FUNC_INFO << "image is null";
return;
}
#ifdef Q_OS_WIN
img2->save("C:/POS/Images/" + imageName);
#else
img2->save("/mnt/sdcard/POS/Images/" + imageName);
#endif
qDebug() << Q_FUNC_INFO << "Exits";
}
Also I see in logs "libpng error: Read Error" and the slot is invoked multiple times...
Thanks all,
I resolved the issue with few changes :)
connect(reply, SIGNAL(finished()), this, SLOT(saveImage()));
finished() makes sure complete image data is received from n/w.
QByteArray imageData = reply->readAll();
QImage *image = new QImage();
image->loadFromData(imageData);
reply->readAll() should be saved as first call clears the data after returning it.
image->save("C:/POS/Images/" + imageName + ".png"
don't forget to specify image format (either in filename or as parameter)

QXmlQuery and XSLT20: Resultant Output String is empty everytime, works well on shell(xmlpattern)

I am writing a class to parse Itunes Libray File using QXmlQuery and QT-XSLT.
Here's my sample code:
ItunesLibParser::ItunesLibParser()
{
pathToLib = QString("/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml");
}
void ItunesLibParser::createXSLFile(QFile &inFile)
{
if (inFile.exists()) {
inFile.remove();
}
inFile.open(QIODevice::WriteOnly);
QTextStream out(&inFile);
out << QString("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out << QString("<xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">");
out << QString("<xsl:output method=\"text\" />");
out << QString("<xsl:template name=\"playlistNames\">");
out << QString("<xsl:value-of select=\"child::integer[preceding-sibling::key[1]='Playlist ID']\"/>");
out << QString("<xsl:text>
</xsl:text>");
out << QString("<xsl:value-of select=\"child::string[preceding-sibling::key[1]='Name']\"/>");
out << QString("<xsl:text>
</xsl:text>");
out << QString("</xsl:template>");
out << QString("<xsl:template match=\"/\">");
out << QString("<xsl:for-each select=\"plist/dict/array/dict\">");
out << QString("<xsl:call-template name=\"playlistNames\"/>");
out << QString("</xsl:for-each>");
out << QString("</xsl:template>");
out << QString("</xsl:stylesheet>");
inFile.close();
return;
}
void ItunesLibParser::dumpPlayList()
{
QXmlQuery query(QXmlQuery::XSLT20);
query.setFocus(QUrl(pathToLib));
QFile xslFile("plist.xsl");
createXSLFile(xslFile);
query.setQuery(QUrl("plist.xsl"));
QStringList* outDump = new QStringList();
query.evaluateTo(outDump);
if(outDump != NULL) {
QStringList::iterator iter = (*outDump).begin();
for (; iter != (*outDump).end();
++iter)
//code flow doesn't come here. It means being() == end()
std::cout << (*iter).toLocal8Bit().constData() << std::endl;
}
return;
}
OutDump here doesn't contain data. While in Shell (xmlpatterns-4.7 mystlye.xsl itunes_music_library.xml ), If I run my Query I get proper output.
Is there anything, wrong I am doing while calling it programatically? I checked out plist.xsl is created properly, but my doubt is whether "/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml" this is getting loaded or not? Or there might be another reasons, I am confused. Is there any experts to throw some light onto problem, I will be glad.
Intead from reading from the file, I read the file into buffer and converted that int string as passed to setquery. That solved the problem.
Here's sample code for those who could face similar problem in future.
void ITunesMlibParser::parsePlayListItemXml(int plistId)
{
QXmlQuery xQuery(QXmlQuery::XSLT20);
QFile inFile("/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml");
if (!inFile.open(QIODevice::ReadOnly)) {
return;
}
QByteArray bArray;
while (!inFile.atEnd()) {
bArray += inFile.readLine();
}
QBuffer xOriginalContent(&bArray);
xOriginalContent.open(QBuffer::ReadWrite);
xOriginalContent.reset();
if (xQuery.setFocus(&xOriginalContent))
std::cout << "File Loaded" << std::endl;
//..
//..
}
Thanks
Rakesh

Resources