I have a problem with reading custom metatype data from QSetting. I have a class:
class MusicOwner
{
public:
MusicOwner() :
songs_count(0),
id(0)
{}
explicit MusicOwner(const Song &owner_radio);
Song toOwnerRadio() const;
static QList<MusicOwner> parseMusicOwnerList(const QVariant &request_result);
private:
friend QDataStream &operator <<(QDataStream &stream, const VkService::MusicOwner &val);
friend QDataStream &operator >>(QDataStream &stream, VkService::MusicOwner &val);
friend QDebug operator<< (QDebug d, const MusicOwner &owner);
int songs_count;
int id;
QString name;
QString screen_name;
QUrl photo;
};
Q_DECLARE_METATYPE(VkService::MusicOwner)
with overloaded:
QDataStream &operator <<(QDataStream &stream, const VkService::MusicOwner &val)
{
stream << val.id;
stream << val.name;
stream << val.songs_count;
stream << val.screen_name;
return stream;
}
QDataStream &operator >>(QDataStream &stream, VkService::MusicOwner &val)
{
stream >> val.id;
stream >> val.name;
stream >> val.songs_count;
stream >> val.screen_name;
return stream;
}
QDebug operator <<(QDebug d, const VkService::MusicOwner &owner)
{
d << "MusicOwner("
<< owner.id << ","
<< owner.name << ","
<< owner.songs_count << ","
<< owner.screen_name << ")";
return d;
}
and somewhere at program's start I call:
qRegisterMetaTypeStreamOperators<MusicOwner>("MusicOwner");
To read and write I use two functions: Saving works fine, all data that I saving appearing in settings file.
void VkService::SaveBookmarks()
{
TRACE;
QSettings s;
s.beginGroup(kSettingGroup);
s.beginWriteArray("bookmarks");
int index = 0;
for (int i = 0; i < root_item_->rowCount(); ++i){
auto item = root_item_->child(i);
if (item->data(InternetModel::Role_Type).toInt() == Type_Bookmark){
Song song = item->data(InternetModel::Role_SongMetadata).value<Song>();
s.setArrayIndex(index);
MusicOwner owner(song);
qLog(Info) << "Save" << index << ":" << owner;
s.setValue("owner", QVariant::fromValue(owner));
++index;
}
}
s.endArray();
}
Problems with this function, It's load count correctly, but it's loading empty default constructed items.
void VkService::LoadBookmarks()
{
QSettings s;
s.beginGroup(kSettingGroup);
int max = s.beginReadArray("bookmarks");
for (int i = 0; i < max; ++i){
s.setArrayIndex(i);
MusicOwner owner = s.value("owner").value<MusicOwner>();
qLog(Info) << "Load" << i << ":" << owner;
AppendBookmarkFromRadio(root_item_, owner.toOwnerRadio());
}
s.endArray();
}
I rewrote it to new project for testing, but it works FINE. I spend two hour to find out, why this variant reading data correctly but first variant not. Owner in first variant converting correctly. Even data in settings file in both variants the same.
#include <QCoreApplication>
#include <QDataStream>
#include <QDebug>
#include <QUrl>
#include <QSettings>
#include <QVariant>
class MusicOwner
{
public:
MusicOwner() :
songs_count(0),
id(0)
{}
private:
friend QDataStream &operator <<(QDataStream &stream, const MusicOwner &val);
friend QDataStream &operator >>(QDataStream &stream, MusicOwner &val);
friend QDebug operator<< (QDebug d, const MusicOwner &owner);
public:
int songs_count;
int id;
QString name;
QString screen_name;
QUrl photo;
};
QDataStream &operator <<(QDataStream &stream, const MusicOwner &val)
{
stream << val.id;
stream << val.name;
stream << val.songs_count;
stream << val.screen_name;
return stream;
}
QDataStream &operator >>(QDataStream &stream, MusicOwner &val)
{
stream >> val.id;
stream >> val.name;
stream >> val.songs_count;
stream >> val.screen_name;
return stream;
}
QDebug operator <<(QDebug d, const MusicOwner &owner)
{
d << "MusicOwner("
<< owner.id << ","
<< owner.name << ","
<< owner.songs_count << ","
<< owner.screen_name << ")";
return d;
}
Q_DECLARE_METATYPE(MusicOwner)
const QString kSettingGroup = "Group";
void Save() {
QSettings s;
s.beginGroup(kSettingGroup);
s.beginWriteArray("bookmarks");
int index = 0;
for (int i = 0; i < 100; ++i){
if (random() % 5 == 0) {
s.setArrayIndex(index);
MusicOwner owner;
owner.id = i;
owner.name ="Hello world";
owner.songs_count = i * 2;
owner.screen_name = "hello_world";
s.setValue("owner", QVariant::fromValue(owner));
qDebug() << "Saved" << i << ":" << owner;
++index;
}
}
s.endArray();
qDebug() << "Saved" << index << "elements";
}
void Load() {
QSettings s;
s.beginGroup(kSettingGroup);
int max = s.beginReadArray("bookmarks");
qDebug() << "To load" << max << "elements";
for (int i = 0; i < max; ++i){
s.setArrayIndex(i);
MusicOwner owner = s.value("owner").value<MusicOwner>();
qDebug() << "\tLoaded" << i << ":" << owner;
}
s.endArray();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaTypeStreamOperators<MusicOwner>("MusicOwner");
QSettings s;
Load();
Save();
return a.exec();
}
Maybe you can find difference in work with QSettings in this variants?