How to clear QFuture results in QFutureWatcher - qt

I tried to block multiple file at once, then copy them to another location.
Both source and destination files should be blocked simultaneously. Therefore I can't use static QFile::copy() function.
To hold and move files I use QSharedPointer< QFile > due to QFile is neither copyable nor moveable.
To perform whole the operation entirely I use QtConcurrent framework. Namely: QtConcurrent::mappedReduced and QFutureWatcher.
To open all pairs of files I use map functor, then to sequentially copy them I use reduce functor.
using PFile = QSharedPointer< QFile >;
using PFileList = QList< PFile >;
template< typename Result, typename Functor >
struct FunctorWithResultType
: std::decay_t< Functor >
{
using result_type = Result;
FunctorWithResultType(Functor & functor)
: std::decay_t< Functor >{std::forward< Functor >(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultType< Result, Functor >
addResultType(Functor && functor)
{
return {functor};
}
class Test
{
public :
QDir currentDirectory;
QFutureWatcher< PFileList > fileCopyFutureWatcher;
// ...
};
// ...
Test::Test()
{
auto onFilesCopied = [&]
{
PFileList copiedFiles = fileCopyFutureWatcher.result();
qCInfo(usbDevice) << "Files copy operation from drive finished.";
qCInfo(usbDevice) << copiedFiles.size();
for (PFile const & file : copiedFiles) {
//file->close(); // I want copiedFiles to be closed automatically at the end of current scope
}
};
connect(&fileCopyFutureWatcher, &fileCopyFutureWatcher.finished, onFilesCopied);
}
// ...
void Test::onDeviceAdded(QString deviceName)
{
qCInfo(usbDevice) << "USB device" << deviceName << "is added.";
if (!fileCopyFutureWatcher.isFinished()) {
return;
}
QDir sourceDirectory{deviceName};
if (!sourceDirectory.cd("dir")) {
qCInfo(usbDevice) << "Drive" << deviceName << "does not contain dir subdirectory.";
return;
}
auto destinationDirectory = currentDirectory;
if (!destinationDirectory.mkpath("fileCache")) {
qCCritical(usbDevice) << "Can't create fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
if (!destinationDirectory.cd("fileCache")) {
qCCritical(usbDevice) << "Can't change directory to fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
struct PFilePair
{
PFile source, destination;
};
auto openSourceAndDestinationFiles = [&, destinationDirectory] (QFileInfo const & fileInfo) -> PFilePair
{
auto source = PFile::create(fileInfo.absoluteFilePath());
QFile & sourceFile = *source;
if (!sourceFile.open(QFile::ReadOnly)) {
qCCritical(usbDevice) << "Can't open file" << sourceFile.fileName()
<< "to read:" << sourceFile.errorString();
return {};
}
auto destination = PFile::create(destinationDirectory.absoluteFilePath(fileInfo.fileName()));
QFile & destinationFile = *destination;;
if (!destinationFile.open(QFile::ReadWrite | QFile::Truncate)) {
qCCritical(usbDevice) << "Can't open file" << destinationFile.fileName()
<< "to write:" << destinationFile.errorString();
return {};
}
return {qMove(source), qMove(destination)};
};
auto copyFiles = [&] (PFileList & files, PFilePair const & filePair)
{
if (filePair.source.isNull() || filePair.destination.isNull()) {
return;
}
QFile & sourceFile = *filePair.source;
QFile & destinationFile = *filePair.destination;
qCInfo(usbDevice) << sourceFile.fileName() << "->" << destinationFile.fileName();
constexpr int size = (1 << 20); // 1MiB
QByteArray buffer{size, 0};
char * const data = buffer.data();
while (!sourceFile.atEnd()) {
auto bytesRead = sourceFile.read(data, size);
if (bytesRead < 0) {
qCCritical(usbDevice) << "Can't read file" << sourceFile.fileName()
<< ":" << sourceFile.errorString();
return;
}
auto bytesWritten = destinationFile.write(data, bytesRead);
while (bytesWritten < bytesRead) {
auto sizeWritten = destinationFile.write(data + bytesWritten, bytesRead - bytesWritten);
if (sizeWritten < 0) {
qCCritical(usbDevice) << "Can't write file" << destinationFile.fileName()
<< ":" << destinationFile.errorString();
return;
}
bytesWritten += sizeWritten;
}
Q_ASSERT(bytesWritten == bytesRead);
}
Q_ASSERT(sourceFile.size() == destinationFile.size());
destinationFile.flush();
files.append(filePair.destination);
};
QStringList nameFilters;
nameFilters << "file.dat";
// many other entries
auto entryInfoList = sourceDirectory.entryInfoList(nameFilters, (QDir::Readable | QDir::Files));
fileCopyFutureWatcher.setFuture(QtConcurrent::mappedReduced< PFileList >(qMove(entryInfoList), addResultType< PFilePair >(openSourceAndDestinationFiles), copyFiles));
}
// ...
After reading result in QFutureWatcher::finished event all the destination files are still opened and blocked by my application. Therefore I can conclude that copies of QSharedPointer< QFile > are still exists. I suspect that they leave in QFuture inside QFutureWatcher. How can I clear all of them (i.e. how to cause QFile::~QFile() to close all files) without calling QFutureWatcher::setFuture with fake QFuture instance?
To achieve this I need to steal result from QFuture, not to copy.

My workaround looks like following:
using PFile = QSharedPointer< QFile >;
using PFileList = QList< PFile >;
template< typename Result, typename Functor >
struct FunctorWithResultType
: std::decay_t< Functor >
{
using result_type = Result;
FunctorWithResultType(Functor & functor)
: std::decay_t< Functor >{std::forward< Functor >(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultType< Result, Functor >
addResultType(Functor && functor)
{
return {functor};
}
class Test
{
public :
QDir currentDirectory;
// ...
};
// ...
void Test::onDeviceAdded(QString deviceName)
{
qCInfo(usbDevice) << "USB device" << deviceName << "is added.";
QDir sourceDirectory{deviceName};
if (!sourceDirectory.cd("dir")) {
qCInfo(usbDevice) << "Drive" << deviceName << "does not contain dir subdirectory.";
return;
}
auto destinationDirectory = currentDirectory;
if (!destinationDirectory.mkpath("fileCache")) {
qCCritical(usbDevice) << "Can't create fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
if (!destinationDirectory.cd("fileCache")) {
qCCritical(usbDevice) << "Can't change directory to fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
struct PFilePair
{
PFile source, destination;
};
auto openSourceAndDestinationFiles = [&, destinationDirectory] (QFileInfo const & fileInfo) -> PFilePair
{
auto source = PFile::create(fileInfo.absoluteFilePath());
QFile & sourceFile = *source;
if (!sourceFile.open(QFile::ReadOnly)) {
qCCritical(usbDevice) << "Can't open file" << sourceFile.fileName()
<< "to read:" << sourceFile.errorString();
return {};
}
auto destination = PFile::create(destinationDirectory.absoluteFilePath(fileInfo.fileName()));
QFile & destinationFile = *destination;;
if (!destinationFile.open(QFile::ReadWrite | QFile::Truncate)) {
qCCritical(usbDevice) << "Can't open file" << destinationFile.fileName()
<< "to write:" << destinationFile.errorString();
return {};
}
return {qMove(source), qMove(destination)};
};
auto copyFiles = [&] (PFileList & files, PFilePair const & filePair)
{
if (filePair.source.isNull() || filePair.destination.isNull()) {
return;
}
QFile & sourceFile = *filePair.source;
QFile & destinationFile = *filePair.destination;
qCInfo(usbDevice) << sourceFile.fileName() << "->" << destinationFile.fileName();
constexpr int size = (1 << 20); // 1MiB
QByteArray buffer{size, 0};
char * const data = buffer.data();
while (!sourceFile.atEnd()) {
auto bytesRead = sourceFile.read(data, size);
if (bytesRead < 0) {
qCCritical(usbDevice) << "Can't read file" << sourceFile.fileName()
<< ":" << sourceFile.errorString();
return;
}
auto bytesWritten = destinationFile.write(data, bytesRead);
while (bytesWritten < bytesRead) {
auto sizeWritten = destinationFile.write(data + bytesWritten, bytesRead - bytesWritten);
if (sizeWritten < 0) {
qCCritical(usbDevice) << "Can't write file" << destinationFile.fileName()
<< ":" << destinationFile.errorString();
return;
}
bytesWritten += sizeWritten;
}
Q_ASSERT(bytesWritten == bytesRead);
}
Q_ASSERT(sourceFile.size() == destinationFile.size());
destinationFile.flush();
files.append(filePair.destination);
};
auto & fileCopyFutureWatcher = *new QFutureWatcher< PFileList >{this};
auto onFilesCopied = [&]
{
fileCopyFutureWatcher.deleteLater();
PFileList copiedFiles = fileCopyFutureWatcher.result();
qCInfo(usbDevice) << "Files copy operation from drive finished.";
qCInfo(usbDevice) << copiedFiles.size();
for (PFile const & file : copiedFiles) {
// ...
}
};
connect(&fileCopyFutureWatcher, &fileCopyFutureWatcher.finished, onFilesCopied);
QStringList nameFilters;
nameFilters << "*.dat";
auto entryInfoList = sourceDirectory.entryInfoList(nameFilters, (QDir::Readable | QDir::Files));
fileCopyFutureWatcher.setFuture(QtConcurrent::mappedReduced< PFileList >(qMove(entryInfoList), addResultType< PFilePair >(openSourceAndDestinationFiles), copyFiles));
}
// ...
I almost sure, that fileCopyFutureWatcher instance will be deleted reliably.

Related

Qt - Cannot read descriptor of the characteristic - BLE

I have a problem with reading characteristic using Bluetooth Low Energy Qt api. The device I'm communicating with is a Decawave DWM1001 module. I was following the tutorial from the documentation. I managed to connect to the device, read and creates it's service successfully. The device has "network node service" with UUID: 680c21d9-c946-4c1f-9c11-baa1c21329e7, which I'm trying to read characteristics from. I call QLowEnergyController::connectToDevice() method, it finds the service and I create a QLowEnergyService object for it, named nodeService.
void BluetoothConnector::serviceDiscovered(const QBluetoothUuid &newService)
{
qDebug() << "Service discovered: " << newService.toString();
if (newService == QBluetoothUuid(nodeServiceUUID)) {
nodeService = controller->createServiceObject(QBluetoothUuid(nodeServiceUUID), this);
if (nodeService) {
qDebug() << "Node service created";
connect(nodeService, &QLowEnergyService::stateChanged, this, &BluetoothConnector::serviceStateChanged);
connect(nodeService, &QLowEnergyService::characteristicChanged, this, &BluetoothConnector::updateCharacteristic);
//connect(nodeService, &QLowEnergyService::descriptorWritten, this, &BLTest::confirmedDescriptorWrite);
nodeService->discoverDetails();
} else {
qDebug() << "Node service not found.";
}
}
}
nodeService is created successfully (I get "Node service created" log), then I connect the signals and slots for the service and then call discoverDetails() on nodeService. The serviceStateChanged() slot looks like this:
void BluetoothConnector::serviceStateChanged(QLowEnergyService::ServiceState newState)
{
if (newState == QLowEnergyService::DiscoveringServices) {
qDebug() << "Discovering services";
} else if (newState == QLowEnergyService::ServiceDiscovered) {
qDebug() << "Service discovered";
const QLowEnergyCharacteristic networkIdChar = nodeService->characteristic(QBluetoothUuid(networkIdUUID));
const QLowEnergyCharacteristic dataModeChar = nodeService->characteristic(QBluetoothUuid(dataModeUUID));
const QLowEnergyCharacteristic locationChar = nodeService->characteristic(QBluetoothUuid(locationUUID));
if (networkIdChar.isValid() && dataModeChar.isValid() && locationChar.isValid()) {
auto idValue = networkIdChar.value();
auto modeValue = dataModeChar.value();
auto locValue = locationChar.value();
qDebug() << "Network ID: " << idValue;
qDebug() << "Mode: " << modeValue;
qDebug() << "Location: " << locValue;
auto notificationDesc = locationChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDesc.isValid()) {
qDebug() << "Notification desc valid";
nodeService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
}
} else {
qDebug() << "Characteristic invalid";
}
}
}
I get the "Discovering services" log and after that the app hangs for a bit and then I get:
"Cannot read descriptor (onDescReadFinished 3): \"{00002902-0000-1000-8000-00805f9b34fb}\" \"{3f0afd88-7770-46b0-b5e7-9fc099598964}\" \"org.freedesktop.DBus.Error.NoReply\" \"Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.\""
"LowEnergy controller disconnected"
"Aborting onCharReadFinished due to disconnect"
It can't read the 00002902-0000-1000-8000-00805f9b34fb which is CCCD descriptor for the 3f0afd88-7770-46b0-b5e7-9fc099598964 characteristic (vendor specific).
Can't figure out what's wrong and why it can't read characteristics from the device. Do I need to do something else to make it work?
Thanks.
---UPDATE---
BluetoothConnector class:
#include "bluetoothconnector.h"
#include <QTimer>
BluetoothConnector::BluetoothConnector(QObject *parent) : QObject(parent)
{
configureDiscoveryAgent();
}
void BluetoothConnector::scan()
{
agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
}
void BluetoothConnector::connectToDevice(QString &addr)
{
auto it = std::find_if(devices.begin(), devices.end(),
[&] (const QBluetoothDeviceInfo& d) { return d.address().toString() == addr; });
if (it == devices.end())
return;
device = *it;
controller = QLowEnergyController::createCentral(device, this);
connect(controller, &QLowEnergyController::serviceDiscovered, this, &BluetoothConnector::serviceDiscovered);
connect(controller, &QLowEnergyController::discoveryFinished, this, &BluetoothConnector::serviceScanDone);
connect(controller, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this, [this](QLowEnergyController::Error error) {
Q_UNUSED(error);
qDebug() << "Controller error: " << error;
emit controllerError();
});
connect(controller, &QLowEnergyController::connected, this, [this]() {
qDebug() << "Controller connected. Search services...";
controller->discoverServices();
});
connect(controller, &QLowEnergyController::disconnected, this, [this]() {
qDebug() << "LowEnergy controller disconnected";
});
controller->connectToDevice();
}
void BluetoothConnector::configureDiscoveryAgent()
{
agent = new QBluetoothDeviceDiscoveryAgent(this);
agent->setLowEnergyDiscoveryTimeout(5000);
connect(agent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothConnector::addDevice);
connect(agent, static_cast<void (QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)>(&QBluetoothDeviceDiscoveryAgent::error),
this, &BluetoothConnector::scanError);
connect(agent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothConnector::scanFinished);
connect(agent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &BluetoothConnector::scanFinished);
}
void BluetoothConnector::addDevice(const QBluetoothDeviceInfo &info)
{
if (!devices.contains(info)) {
qDebug() << "Found device: " << info.name();
devices.append(info);
emit deviceFound(info);
}
}
void BluetoothConnector::scanError(QBluetoothDeviceDiscoveryAgent::Error error)
{
qDebug() << "Scan error: " << error;
}
void BluetoothConnector::scanFinished()
{
emit scanFinishedSignal();
}
void BluetoothConnector::serviceDiscovered(const QBluetoothUuid &newService)
{
qDebug() << "Service discovered: " << newService.toString();
if (newService == QBluetoothUuid(nodeServiceUUID)) {
nodeService = controller->createServiceObject(QBluetoothUuid(nodeServiceUUID), this);
qDebug() << "State: " << nodeService->state();
if (nodeService) {
qDebug() << "Node service created";
connect(nodeService, &QLowEnergyService::stateChanged, this, &BluetoothConnector::serviceStateChanged);
connect(nodeService, &QLowEnergyService::characteristicChanged, this, &BluetoothConnector::updateCharacteristic);
connect(nodeService, &QLowEnergyService::characteristicWritten, this, &BluetoothConnector::characteristicWritten);
connect(nodeService, QOverload<QLowEnergyService::ServiceError>::of(&QLowEnergyService::error),
[=](QLowEnergyService::ServiceError newError){ qDebug() << newError; });
//connect(nodeService, &QLowEnergyService::descriptorWritten, this, &BLTest::confirmedDescriptorWrite);
nodeService->discoverDetails();
} else {
qDebug() << "Node service not found.";
}
}
}
void BluetoothConnector::serviceScanDone()
{
qDebug() << "Services scan done";
}
void BluetoothConnector::characteristicWritten(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
qDebug() << "Characteristic written: " << info.name();
}
void BluetoothConnector::serviceStateChanged(QLowEnergyService::ServiceState newState)
{
qDebug() << "State changed: " << newState;
if (newState == QLowEnergyService::ServiceDiscovered) {
qDebug() << "Service discovered";
const QLowEnergyCharacteristic networkIdChar = nodeService->characteristic(QBluetoothUuid(networkIdUUID));
const QLowEnergyCharacteristic dataModeChar = nodeService->characteristic(QBluetoothUuid(dataModeUUID));
const QLowEnergyCharacteristic locationChar = nodeService->characteristic(QBluetoothUuid(locationUUID));
if (networkIdChar.isValid() && dataModeChar.isValid() && locationChar.isValid()) {
auto idValue = networkIdChar.value();
auto modeValue = dataModeChar.value();
auto locValue = locationChar.value();
qDebug() << "Network ID: " << idValue;
qDebug() << "Mode: " << modeValue;
qDebug() << "Location: " << locValue;
auto notificationDesc = locationChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDesc.isValid()) {
qDebug() << "Notification desc valid";
nodeService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
}
} else {
qDebug() << "Characteristic invalid";
}
}
}
void BluetoothConnector::updateCharacteristic(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
if (info.uuid() == QBluetoothUuid(networkIdUUID)) {
qDebug() << "Update ID: " << value;
} else if (info.uuid() == QBluetoothUuid(dataModeUUID)) {
qDebug() << "Update mode: " << value;
} else if (info.uuid() == QBluetoothUuid(locationUUID)) {
qDebug() << "Update location: " << value;
}
}
I think, the problem is located on the remote side (your GATT server).
Check the QLowEnergyService::error() and QLowEnergyService::charcteristicWritten() signal and see if you get any response.
What kind of Bluetooth stack you are use on the remote side?
Might be, you don't have the rights to change the CCCD due to a implementation failure. Please check the implementation on the remote side.

QUdpSocket::writeDatagram, wait for buffer free

I'm using method QUdpSocket::writeDatagram and sending a lot of data. When the socket is full, the method return -1. Is it possible to do somethind like select() with a QUdpSocket?
while(!counterList.empty())
{
CounterValuePtr value = counterList.dequeue();
if (mUdpSocket->bytesToWrite() <= 1<<13)
{
const QByteArray datagram = toDatagram(*value);
qint64 sentBytes = 0;
try
{
sentBytes = mUdpSocket->writeDatagram(datagram, QHostAddress(mSettings->getConnectionIp()), mSettings->getConnectionPort());
}
catch(...)
{
emit dataLost();
qWarning() << "Exception";
throw;
}
qDebug() << datagram;
if(sentBytes == -1)
{
QString errorMsg = getErrorMsg(WSAGetLastError());
qWarning() << "SocketError (" << mUdpSocket->error() << ") : " << mUdpSocket->errorString() << ". " << errorMsg;
emit dataLost();
}
else if(sentBytes < datagram.size())
{
qWarning() << "Not all data sent";
emit dataLost();
}
else
{
qDebug() << "Counter "<< value->getName() << " sent";
datasent = true;
emit dataSent();
}
}
else
{
qWarning() << "Socket write buffer full. Dropping data.";
emit dataLost();
}
}
Some times, writeDatagram returns -1. When I print the last error with WSAGetLastError it prints the buffer is full.

Linker Issues with QString?

I'm having trouble compiling a qt project using msvc2012. For some reason, it says that there is an unresolved symbol that equates to a QString function, which I can't understand.
Here's my .pro file ( this program is commandline only, only using qt for convenience
QT += core gui widgets
TARGET = klc2abuspro
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
key.cpp \
klayout.cpp \
deadkey.cpp
HEADERS += \
key.h \
klayout.h \
deadkey.h
OTHER_FILES +=
and here is where the linker issue refers to:
{
QString file;
if(argc < 2)
{
qDebug() << "No file specified. Defaulting to russian.klc";
file = "russian.klc";
}
else
file = argv[1];
QFile input(file);
if(!input.open(QIODevice::ReadOnly | QIODevice::Text))
qDebug() << "File could not be opened";
QTextStream in(&input);
QString str;
KLayout * layout = new KLayout(file.split(".", QString::SkipEmptyParts)[0]);
while(!in.atEnd() && !(str = in.readLine()).contains("LAYOUT"));
in.readLine(); in.readLine(); in.readLine();in.readLine();
bool currChunk = true;
while(currChunk)
{
str = in.readLine();
if(str == "")
{
currChunk = false;
break;
}
QStringList parts = str.split("\t",QString::SkipEmptyParts );
layout->addKey(new Key(parts[0].toUInt(0,16),parts[3], parts[4]));
}
input.close();
//Starting deadkey finder
if(!input.open(QIODevice::ReadOnly | QIODevice::Text))
return -1;
QTextStream pass(&input);
while(!pass.atEnd() && !(str = pass.readLine()).contains("KEYNAME_DEAD"));
pass.readLine();
DeadKey * dkeys[10];
int i = 0;
while((str = pass.readLine()) != "") {
//qDebug() << "Line: " << str;
QStringList parts = str.split("\t",QString::SkipEmptyParts );
//1 is the name, 0 is the unicode value of the character
layout->addDeadKey(dkeys[i] = new DeadKey(parts[1], parts[0]));
i++;
}
//qDebug() << layout->printDeadKeys();
input.close();
// Find deadkey modifiers
bool cont = true;
i = 0;
input.open(QIODevice::ReadOnly | QIODevice::Text);
do {
while(!pass.atEnd() && !(str = pass.readLine()).contains("DEADKEY") && !(str.contains("KEYNAME")));
if(str.contains("KEYNAME")) {
cont = false;
break;
}
pass.readLine();
while((str = pass.readLine()) != "") {
//qDebug() << "Line: " << str;
QStringList parts = str.split("\t",QString::SkipEmptyParts );
//1 is the name, 0 is the unicode value of the character
//qDebug() << "Key to modify: " << parts[0] << "key result: " << parts[1];
dkeys[i]->addModifier(QChar(parts[0].toUInt(0,16)), QChar(parts[1].toUInt(0,16)));
}
i++;
}while(cont);
layout->implementModifiers();
//qDebug() <<layout->printMods();
layout->exportToQML(file.replace(".klc",".qml"));
return 0;
}
The linker error
main.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: class QString & __cdecl QString::operator=(class QString &&)" (__imp_??4QString##QEAAAEAV0#$$QEAV0##Z) referenced in function main
It seems that i also met this problem when I build the project with Qtcreator. but when i use the vs2012 to open the ".pro" project and build it. this error will disappear. Maybe you can try this method.

QFile,QFile::open: File access not specified, Opening file failed

Simple problem, I just can't open/create a file. It's supposed to save some settings in an xml-file to a given path.
I call the method like this:
xmlwriter->write_settings("./settings.xml");
int XmlWriter::write_settings(QString path)
{
qDebug() << "Path is: " + path;
QDomDocument document;
QDomElement root = document.createElement("settings");
document.appendChild(root);
QDomElement node;
node.setAttribute("name", "Its me!");
node.setAttribute("series", "25");
node.setAttribute("PMT", "200");
root.appendChild(node);
QFile file(path);
if(!file.open(QIODevice::ReadWrite, QIODevice::Text))
{
qDebug() << "Opening file failed!";
return 1;
}
else
{
QTextStream stream(&file);
stream << document.toString();
file.close();
qDebug() << "wrote file to " + path;
return 0;
}
}
You don't pass parameters correctly, so you probably invoke a polymorphic version of QFile::open
Try this:
QFile file(path);
if(!file.open(QIODevice::ReadWrite | QIODevice::Text))
{
qDebug() << "Opening file failed!";
return 1;
}
else
{
QTextStream stream(&file);
stream << document.toString();
file.close();
qDebug() << "wrote file to " + path;
return 0;
}

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