QSettings: Copy, modify but avoid changing underlying .ini file - qt

I read some QSettings from an .ini file:
QSettings* settingsDocRoot=new QSettings(_settingsFile ,QSettings::IniFormat, parent);
This is passed to some object. However, I then do a copy QSettings* s2= new QSettings(settingsDocRoot); and modify one particular value s2->setValue("path", whateverNewPath);
Basically I want to pass a slightly modified QSettings object to another object. But how do I avoid that the original ini file is updated with the changed value (s2->setValue)?
One idea was, simply to set the path to "". However, according to QSettings - where is the location of the ini file? then a default location will be assumed (OK, original file will not be changed, but unnecessary file will be written).

QSettings is entirely designed for persistence. If you don't want your copy to write to disk, you'd probably be better off copying all the values into a QHash and passing that to your other object:
QHash<QString, QVariant> hash;
const QStringList keys = settings->allKeys();
Q_FOREACH(QString key, keys) {
hash[key] = settings->value(key());
}

I am currently doing the following:
QSettings* settingsWsNaviGraph = new QSettings(settingsDocRoot);
// avoid writing to file
settingsWsNaviGraph->setPath(QSettings::InvalidFormat, QSettings::UserScope, "");
This dirty hack seems to avoid writing, at least my original file remains unchanged and I do not see any unwanted file yet (will report if I do find one).
If this here does not work, I'll try to register my own format with bogus read/write methods. See here

Related

Why I can't store QVariantMap in QSettings?

Why it was possible in Qt 5.2 and previously and stored data in following format:
key=#Variant(\0\0\0\b\0\0\0)
but have problem now in Qt 5.11?! Following code
QVariantMap projectsMap;
for (auto project : projects)
projectsMap.insert(key, value);
settings->setValue("Group/projects", projectsMap);
executes correctly however stores nothing to ini file.
qRegisterMetaTypeStreamOperators<QVariantMap>("QVariantMap");
does not help as well. How to store this, what is the problem here?
Don’t store QSettings: it’s not meant to be used that way. You should use a fresh instance of QSettings every time you change the settings. Your destructor should look as follows:
MyClass::~MyClass() {
QSettings s;
s.setValue(kFoo, this->m_bar);
…
}
QSettings is an ephemeral handle to the settings system, its instantiation is cheap. You leak it because QPointer does not destroy anything: it’s not an owning pointer.

Using the same File Output Stream in GUIs

I need to continue writing to the same file using a file output stream, However I'm implementing the program using a javafx GUI from different windows. but:
Since you can not access a global variable without intializing the stream as final I have to make it final however,
Since I have to wrap the the Stream in a try catch, the variable is not recognised as initialised.
I was previously intialising in method like this
eW = outputFactory .createXMLEventWriter(new FileOutputStream("File.txt"));
However, that obivously overwrites the same file when you write the same statement again.
So essentially my question is, how can you set a final variable that needs to be surrounded in a try catch?
final File file = new File("File.txt");
final FileOutputStream fileOS = new FileOutputStream(file);
You don't need to initialize a variable as final to access it from different threads or objects. There are other ways to do it.
You can use a helper class, or even a helper thread. The second option is better in (the most common) case where you have more than 1 thread in your project. You can then use a normal try-catch block that has a (almost infinite) while loop inside, that checks a write queue and writes something when needed.
If you only use 1 thread and only append to a file, you may want to do just that - open the file to append, rather than overwrite. There's a boolean flag in the constructor.
You can take a look at the FileOutputStream(File file, boolean append) constructor, which would allow you to append to the end of the file rather than overwrite each time.
I do not know how you implemented it, but if you are writing to the same file from multiple windows, it might be easier to have a helper class which exclusively handles writing to file. This would allow you to centralize your File output code to one place making it easier to debug and maintain.

How might I use QSettings to load different setups

I have a Qt application that requires the ability to load from several settings files to behave in a distinct way. For example lets say my app can support several variations, VAR1, VAR2, VAR3, ... One of my menu entries allows me to load settings. Currently, I do this using a QSettings object and it works fine. But now I want to implement a different variation. Instead of manually setting 20 or more settings, I would like to load from a preconfigured settings file.
QSettings does not allow me to change source, as far as I can tell. I looked at the static method QSettings::setPath but that can only be done once prior to instantiating the QSettings object.
My hope is to create ways to:
1 - Load factory defaults
2 - Save a user settings file with a user specified name
3 - Recall a user settings file by name.
I would prefer not to have to rewrite QSettings to meet my needs if at all possible.
One of the QSettings constructors takes a file name:
QSettings::QSettings (const QString& fileName,
Format format,
QObject *parent = 0);
Just use that to make as many QSettings instances as you need:
QSettings s1("path1.ini", QSettings::IniFormat);
QSettings s2("path2.ini", QSettings::IniFormat);
If you needed to copy between them you could look through QSettings::allKeys() and get the values.
Have you tried to access QSettings like an INI file ? It allows you to set up the location of the INI file
QSettings settings("/home/petra/misc/myapp.ini",
QSettings::IniFormat);

In Qt, how to setCodecForCStrings globally (in header)?

I'm developing a bunch of Qt applications in C++ and they all use some modules (translation units) for common functionality that use Qt as well.
Whenever I convert a C string (implicit conversion) or C++ string object (fromStdString()) to a QString object, I expect the original data to be UTF-8 encoded and vice versa (toStdString()).
Since the default is Latin-1, I have to set the codec "manually" (in the init procedure of every one of my programs) to UTF-8:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf8"));
Not all of my modules have an init procedure. The ones containing a class do (I can put this line in the class constructor), but some modules just contain a namespace with lots of functions. So there's no place for setCodecForCStrings(). Whenever I convert from/to a QString implicitly (from within one of my modules), I rely on the codec being already set by the init procedure of the main program, which seems to be a rather bad solution.
Is there a reliable way to set the codec to UTF-8 in my modules, or will I just have to be very careful not to use implicit conversions at all (in my modules at least) and write something like std::string(q.toUtf8().constData()) instead of q.toStdString()?
This can be done using a class definition for an automatically instantiated singleton-similar class having some init code in its constructor:
class ModuleInit {
static ModuleInit *instance;
public:
ModuleInit() {
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf8"));
}
};
ModuleInit * ModuleInit::instance = new ModuleInit(); // put this line in .cpp!
Putting this code anywhere into any project will set the text codec to UTF-8. You can, however, overwrite the text codec in the main() method, since the code above is executed even before the main() method.
With "anywhere" I of course mean places where it is syntactically allowed to. Put the class definition in some header file, and the instantiation in the appropriate .cpp file.
You can even put the whole code in one .cpp file, say moduleinit.cpp which you compile and link, but never explicitly use (there is no header file you could include...). This will also avoid accidental instantiations except the very first one and you will not have any problems with duplicate class names.
Note that you can't set the codec for C-strings in one particular file. Setting the codec using QTextCodec::setCodecForCString will set it application-wide!

FileReference.save() duplicates ByteArray

I've encountered a memory problem using FileReference.save(). My Flash application generates of a lot of data in real-time and needs to save this data to a local file. As I understand, Flash 10 (as opposed to AIR) does not support streaming to a file. But, what's even worse is that FileReference.save() duplicates all the data before saving it. I was looking for a workaround to this doubled memory usage and thought about the following approach:
What if I pass a custom subclass of ByteArray as an argument to FileReference.save(), where this ByteArray subclass would override all read*() methods. The overridden read*() methods would wait for a piece of data to be generated by my application, return this piece of data and immediately remove it from the memory. I know how much data will be generated, so I could also override length/bytesAvailable methods.
Would it be possible? Could you give me some hint how to do it? I've created a subclass of ByteArray, registered an alias for it, passed an instance of this subclass to FileReference.save(), but somehow FileReference.save() seems to treat it just as it was a ByteArray instance and doesn't call any of my overridden methods...
Thanks a lot for any help!
It's not something I've tried before, but can you try sending the data out to a php application that would handle saving the ByteArray to the server, much like saving an image to the server, so then you'd use URLLoader.data instead, using something like this:
http://www.zedia.net/2008/sending-bytearray-and-variables-to-server-side-script-at-the-same-time/
It's an interesting idea. Perhaps to start you should just add traces in your extended ByteArray to see how the FileReference#save() functions internally.
If it has some kind of
while( originalByteArray.bytesAvailable )
writeToSaveBuffer( originalByteArray.readByte() );
functionality the overrides could just truncate the original buffer on every read like you say, something like:
override function readByte() : uint {
var b : uint = super.readByte();
// Truncate the bytes (assuming bytesAvailable = length - removedBytes)
length = length - bytesAvailable;
return b;
}
On the other hand, if this now works I guess the original byte array would not be available afterwards in the application anymore.
(i havn't tested this myself, truncating might require more work than the example)

Resources