Re: [Development] QConfig update.
Thiago Macieira schreef op 15-10-2014 17:34: I'm not sure you got my meaning. How is a config editor tool in Qt Creator going to read write those files? Why would you need a tool like that for such a format? How is the code generator going to read the QTypedSettings source header to genete the equivalent .cpp? Exactly the same way moc already parses header files now? My idea was to explore if it were possible to build on what moc already can do. You might have noticed that this idea looks exactly like how you create Q_PROPERTY declarations. I think they should basically _be_ Q_PROPERTY declarations, though the options would be extended with keywords such as SETTING and DEFAULT. Note that I would really like it if it were possible at all to not only generate .cpp, but also generate a bit of .h that gets included into the class declaration in some way, so that there would be real functions to call for all settings. That's what I really miss with the Q_PROPERTY using the MEMBER keyword. André ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Thursday 16 October 2014 08:51:52 André Somers wrote: Exactly the same way moc already parses header files now? My idea was to explore if it were possible to build on what moc already can do. You might have noticed that this idea looks exactly like how you create Q_PROPERTY declarations. I think they should basically _be_ Q_PROPERTY declarations, though the options would be extended with keywords such as SETTING and DEFAULT. That's abusing moc for something it wasn't intended. Moc creates a meta object information for an existing object. That implies: * the class is a QObject, which this needs not be * there are no extra methods present in the class, which this needs We need a code generator that generates a header and possibly a .cpp that can be #included for use elsewhere, like uic. That's not moc. The syntax you proposed does not accomplish that: class AppSettings: public QTypedConfig { Q_SETTINGS(); // Q_OBJECT, but perhaps with some extra's like the ability to include generated function declarations for getters and setters Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter public: AppSettings(QObject* parent = 0); MyCustomType myValue() const; void setMyValue(const MyCustomType value); Q_SIGNAL void myValueChanged(const MyCustomValue value); }; Given this header, there's no way the preprocessor can turn the Q_SETTING macro into a useful declaration. So you can be absolutely sure that the above will not be the way to write the setting declarations. The schema will not be a C++ source or header file. Given the above statement, we have two choices: 1) invent our new schema format 2) adopt a format based on something we can read with QtCore Option 2 implies either XML or JSON. Note that I would really like it if it were possible at all to not only generate .cpp, but also generate a bit of .h that gets included into the class declaration in some way, so that there would be real functions to call for all settings. That's what I really miss with the Q_PROPERTY using the MEMBER keyword. Just as I said. -- Thiago Macieira - thiago.macieira (AT) intel.com Software Architect - Intel Open Source Technology Center ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
Am 14.10.2014 um 18:44 schrieb Tomaz Canabrava: On Tue, Oct 14, 2014 at 1:35 PM, Milian Wolff milian.wo...@kdab.com mailto:milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do I can imagine use cases where I'd like to have this flexibility. The best default value for an unspecified setting very much can depend on the context. Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. I very much agree. Since I wanted to add schema-validation on the low level stuff, this wouldn't be an issue, 'value couldn't be read' would cause an assert. but I can postpone this for later. I don't think it is wise to unconditionally crash programs for things that just during normal usage. With this string based API those settings schema and the actually accessing code are only losely coupled. So it will just happen that applications built for version A of the settings schema will access a configuration written with version B of the schema in mind. Because of program upgrades. Because the user has two versions of the same program installed. Because of human mistakes. Such situations must be handled gracefully: Users just don't like their programs crashing and maybe never starting again (without deleting various files). What's your graceful error handling plan for schema mismatches? Ciao, Mathias ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
Thiago Macieira schreef op 16-10-2014 09:17: On Thursday 16 October 2014 08:51:52 André Somers wrote: Exactly the same way moc already parses header files now? My idea was to explore if it were possible to build on what moc already can do. You might have noticed that this idea looks exactly like how you create Q_PROPERTY declarations. I think they should basically _be_ Q_PROPERTY declarations, though the options would be extended with keywords such as SETTING and DEFAULT. That's abusing moc for something it wasn't intended. Moc creates a meta object information for an existing object. That implies: * the class is a QObject, which this needs not be It is exactly what I was proposing though. Note that this is *not* QConfig/QConfigGroup. I do happen to think that being a QObject for a (central) settings object is a very useful quality. For instance, in order to signal changes to values. I know of course that moc was not intended for this. However, you were asking how such a format could be parsed, and I was pointing out that Qt has been doing exactly that for ages. * there are no extra methods present in the class, which this needs What do you mean by that? We need a code generator that generates a header and possibly a .cpp that can be #included for use elsewhere, like uic. That's not moc. The syntax you proposed does not accomplish that: class AppSettings: public QTypedConfig { Q_SETTINGS(); // Q_OBJECT, but perhaps with some extra's like the ability to include generated function declarations for getters and setters Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter public: AppSettings(QObject* parent = 0); MyCustomType myValue() const; void setMyValue(const MyCustomType value); Q_SIGNAL void myValueChanged(const MyCustomValue value); }; Given this header, there's no way the preprocessor can turn the Q_SETTING macro into a useful declaration. So you can be absolutely sure that the above will not be the way to write the setting declarations. The schema will not be a C++ source or header file. Given that you know a lot more that I do about what can and what cannot be done here... What is blocking doing this _exactly_? Would there be any feasible workaround for that? Would it be possible to do if you were required to #include the generated .h file inside the class itself for instance? Something like this perhaps? class AppSettings: public QTypedConfig { Q_SETTINGS(AppSettings); // Q_OBJECT, but perhaps with some extra's #include(appsettings_inc.h) //include generated definitions Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter (...) } where the contents of appsettings_inc.h would be generated by the generator, to yield something like: //generated for setting property width int width() const; //Q_PROPERTY READ function void setWidth(int width); // Q_PROPERTY WRITE function void widthChanged(int width); // Q_PROPERTY SIGNAL function void resetWidth(); //revert to set default value; Q_PROPERTY RESET function I don't think it is stretching what moc is already doing conceptually all _that_ much. It basically creates properties that are persistent in some kind of store for configuration, instead of them depending on variables in the object itself. And again: I'd find this (or similar) fuctionality also very useful for the Q_PROPERTY MEMBER keyword that we already have. André ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
Please do not assert on the library, you're going to make everyone's program crasheable by just editing a file by hand. On Tue, Oct 14, 2014 at 7:06 PM, Milian Wolff milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:44:30 Tomaz Canabrava wrote: On Tue, Oct 14, 2014 at 1:35 PM, Milian Wolff milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: People, I'v read everything on the other two e-mails and I'v changed quite a few things here and again I ask for some advice. What I'v done: QConfig / QConfigGroup / QConfigWatcher combo classes, to be used from the user QConfigIniBackend, to be used internally. QConfig: uses a 'global' QHashQString, QConfigIniBackend for different files in a way that we don't destruct the info when the object is destroyed, but reuses the JSON information stored, and parse it to the config object. it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value Why the global state? A QConfig should be valid for a single file and constructed on-demand. If you want to share stuff and keep it open, adding something like a KSharedConfig might be a good idea. But again, that is something that could/should be built on-top of QConfig (imo). so I don't need to open a config file and parse it every time the user created a QConfig object. Then provide a QSharedConfig or let the user store the QConfig himself, if it turns out to be a performance-bottleneck for him. If you add global state to QConfig, you'll need synchronization or otherwise you are doomed in a multithreaded application. Also: If you add a cheap JSON cache, is it really worth to optimize at all? Furthermore: If you keep the QConfig in memory all the time, you'll probably end up duplicating the stuff as soon as you add the fancy high-level interface on-top. QConfig will operate on JSON after all and you'll incur a conversion penalty whenever you read a value from it. The high-level interface should (hopefully) read the values once and store it internally in the proper type. If you don't do this and always read from QConfig, you'll end up with issues in this pattern: void HighLevelConfig::setFoo(quint64 foo) { if (foo == m_foo) { return; } m_foo = foo; emit fooChanged(foo); } If this would read from QConfig, instead of directly comparing to the quint64 m_foo member, you'll get rounding errors etc. pp. This, the more I think about it, is actually a big issue with a JSON cache in general. .ini does not have that issue as the byte-array gets interpreted based on the type you pass along (a kind of duck-typing). It might mean that you'll have to store everything as a string in JSON to prevent a loss of data when storing e.g. std::limitsquint64::max() (note: JSON only knows double). But storing everything as a string looses the difference between foo=1 and foo=1 Afaik this issue has not yet been discussed, has it? QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); And how do you check whether window-width was read or not? What do you return on error? A default-constructed value? What type does the value have for that matter? Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. Without the ability to provide a default value, one can never figure out whether `c.value(some-int) == 0` means the value could not be read and a default should be used, or whether the value is 0. Since I wanted to add schema-validation on the low level stuff, this wouldn't be an issue, 'value couldn't be read' would cause an assert. but I can postpone this for later. Most applications, (all KDE applications btw), would then assert. Initially, no configuration file is available after all. And again: Please do not overdesign QConfig. KISS! Add fancy schema-validation and stuff on-top of that. Don't remove something as essential as reading a setting with a default value fallback mechanism! Bye -- Milian Wolff | milian.wo...@kdab.com | Software Engineer KDAB (Deutschland) GmbHCo KG, a KDAB Group company Tel. Germany +49-30-521325470, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions ___
Re: [Development] QConfig update.
On 14/10/2014 19:06, Milian Wolff wrote: It might mean that you'll have to store everything as a string in JSON to prevent a loss of data when storing e.g. std::limitsquint64::max() (note: JSON only knows double). To be more precise : JSON itself does not assume anything about number precision. JavaScript, as well as QJsonValue, do assume that any number is a double precision, but nothing in RFC 4627 says that. libjson (at least) assumes that number values in JSON can be signed int64. This specific issue may be better handled in QJsonValue than in a QConfig class. Regards, Julien Blanc ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
Milian Wolff schreef op 14-10-2014 18:35: QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); And how do you check whether window-width was read or not? What do you return on error? A default-constructed value? What type does the value have for that matter? Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. Without the ability to provide a default value, one can never figure out whether `c.value(some-int) == 0` means the value could not be read and a default should be used, or whether the value is 0. Indeed. I think default values are vital, even if the issue you (Tomaz) point out is valid like I argued yesterday. That is why we only use QSettings anymore from within our own type-safe settings class. I plan to set the defaults via a schema-based file ( could be the KConfigXt based, but I dislike having to edit XML by hand, so something more similar to QML would be best ). Any tougths on that? If you store JSON, maybe use JSON? The mapping will give you the default value and from there you get a type. { foo : 1, bar : { lala: string } } XML hand-editing is of course not needed. If XML would be used (like it is for .ui files and .rcc files in Qt), an editor for this type can be added to Creator. That would get rid of the need to hand-edit XML files. JSON could also work of course. Perhaps it is important however to first have a clear goal on use cases the schema has to solve, before going into a file format for it. To me, some requirements would be: 1) Easy generation of type-save settings class 2) Management of default values 3) Capable of handling custom types, including enums 4) Makes it easy to avoid writing boilerplate getters and setters, but possible to do so if needed 5) Also generates changed signals Furthermore, I'd like to have the ability to have more than one of these. That is: we are in a large project with several libraries. These libraries need to access part of the settings. The overall application needs to access the whole settings structure of course (for instance for showing a settings dialog), preferably in some nice unified way. I think settings resemble properties to a very large extend. Perhaps it would, as an alternative to the XML or JSON schemes already suggested, but possible to build on the Qt property system instead for this. It is familiar to developers, does not require a special editor, and allows for using your own code instead of generated boilerplate quite naturally (point 4 above). Perhaps something like: class AppSettings: public QTypedConfig { Q_SETTINGS(); // Q_OBJECT, but perhaps with some extra's like the ability to include generated function declarations for getters and setters Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter public: AppSettings(QObject* parent = 0); MyCustomType myValue() const; void setMyValue(const MyCustomType value); Q_SIGNAL void myValueChanged(const MyCustomValue value); } André ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Tue, Oct 14, 2014 at 07:06:30PM +0200, Milian Wolff wrote: On Tuesday 14 October 2014 13:44:30 Tomaz Canabrava wrote: On Tue, Oct 14, 2014 at 1:35 PM, Milian Wolff milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value Why the global state? A QConfig should be valid for a single file and constructed on-demand. If you want to share stuff and keep it open, adding something like a KSharedConfig might be a good idea. But again, that is something that could/should be built on-top of QConfig (imo). so I don't need to open a config file and parse it every time the user created a QConfig object. Then provide a QSharedConfig or let the user store the QConfig himself, if it turns out to be a performance-bottleneck for him. as i previously pointed out, this is one of the things i consider *bad* about kconfig. i wouldn't necessarily make a real cache, but the objects should be automatically shared in the background. that's what happens when you natively use the windows registry anyway. If you add global state to QConfig, you'll need synchronization or otherwise you are doomed in a multithreaded application. yes. so what? Furthermore: If you keep the QConfig in memory all the time, you'll probably end up duplicating the stuff as soon as you add the fancy high-level interface on-top. QConfig will operate on JSON after all and you'll incur a conversion penalty whenever you read a value from it. The high-level interface should (hopefully) read the values once and store it internally in the proper type. you are right with that (that's why i don't think using the json classes as anything else than backend storage and having an abstraction layer on top makes sense), but i don't see how that correlates with the config objects being shared+cached. ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Tuesday 14 October 2014 13:44:30 Tomaz Canabrava wrote: so I don't need to open a config file and parse it every time the user created a QConfig object. I quite frankly don't see this as a problem. I think this syntax of using QSettings is just plain weird: QSettings settings; if (settings.contains(foo)) doSomething(); Applications should just keep a global singleton of theirs for their config. Clearly, QConfigGroup would need to be thread-safe. -- Thiago Macieira - thiago.macieira (AT) intel.com Software Architect - Intel Open Source Technology Center ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Wednesday 15 October 2014 10:02:59 André Somers wrote: snip I think settings resemble properties to a very large extend. Perhaps it would, as an alternative to the XML or JSON schemes already suggested, but possible to build on the Qt property system instead for this. It is familiar to developers, does not require a special editor, and allows for using your own code instead of generated boilerplate quite naturally (point 4 above). Perhaps something like: class AppSettings: public QTypedConfig { Q_SETTINGS(); // Q_OBJECT, but perhaps with some extra's like the ability to include generated function declarations for getters and setters Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter public: AppSettings(QObject* parent = 0); MyCustomType myValue() const; void setMyValue(const MyCustomType value); Q_SIGNAL void myValueChanged(const MyCustomValue value); } I like the idea! Bye -- Milian Wolff | milian.wo...@kdab.com | Software Engineer KDAB (Deutschland) GmbHCo KG, a KDAB Group company Tel. Germany +49-30-521325470, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Wed, Oct 15, 2014 at 10:02:59AM +0200, André Somers wrote: snip XML hand-editing is of course not needed. If XML would be used (like it is for .ui files and .rcc files in Qt), an editor for this type can be added to Creator. That would get rid of the need to hand-edit XML files. No! Not everyone uses Creator or whatever tool. I strongly dislike the idea of having to depend on a specific toolset. What is productive to some can be counter-productive to others. We need to KISS and use a human-readable format that offers the possibility to be manually edited if desired. And for that XML is a huge PITA IMHO. Please, please don't go down that road. -- Rafael Roquetto | rafael.roque...@kdab.com | Software Engineer Klarälvdalens Datakonsult AB, a KDAB Group company Tel. Sweden (HQ) +46-563-540090, USA +1-866-777-KDAB(5322) KDAB - Qt Experts - Platform-independent software solutions smime.p7s Description: S/MIME cryptographic signature ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Wed, Oct 15, 2014 at 12:22:32PM +0200, Milian Wolff wrote: On Wednesday 15 October 2014 10:02:59 André Somers wrote: snip I think settings resemble properties to a very large extend. Perhaps it would, as an alternative to the XML or JSON schemes already suggested, but possible to build on the Qt property system instead for this. It is familiar to developers, does not require a special editor, and allows for using your own code instead of generated boilerplate quite naturally (point 4 above). Perhaps something like: class AppSettings: public QTypedConfig { Q_SETTINGS(); // Q_OBJECT, but perhaps with some extra's like the ability to include generated function declarations for getters and setters Q_SETTING(int width SETTING dialog/window-width DEFAULT 800); //use generated getter, setter and notify Q_SETTING(MyCustomType myValue READ myValue WRITE setMyValue NOTIFY myValueChanged); //use custom getter and setter public: AppSettings(QObject* parent = 0); MyCustomType myValue() const; void setMyValue(const MyCustomType value); Q_SIGNAL void myValueChanged(const MyCustomValue value); } I like the idea! +1 -- Rafael Roquetto | rafael.roque...@kdab.com | Software Engineer Klarälvdalens Datakonsult AB, a KDAB Group company Tel. Sweden (HQ) +46-563-540090, USA +1-866-777-KDAB(5322) KDAB - Qt Experts - Platform-independent software solutions smime.p7s Description: S/MIME cryptographic signature ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Wed, Oct 15, 2014 at 02:36:51PM +0200, Thiago Macieira wrote: On Wednesday 15 October 2014 08:39:27 Rafael Roquetto wrote: No! Not everyone uses Creator or whatever tool. I strongly dislike the idea of having to depend on a specific toolset. What is productive to some can be counter-productive to others. We need to KISS and use a human-readable format that offers the possibility to be manually edited if desired. And for that XML is a huge PITA IMHO. Please, please don't go down that road. The only issue is that the more human-editable the source form is, the harder it is to write a parser and toolchain to configure. Of course, we need to find a compromise in between. In other words, KISS but no simpler. I am not suggesting something based on natural language, actually, I am just arguing against an approach which enforces the usage of an specific tool/editor as an alternative for a better designed textual format. Specially when it comes to settings or schemas. The suggested QTypedSettings class is an example of a human-editable source form which is easy to read (*arguably* easier than condensed XML *IMHO*) being at the same time tool agnostic (any editor will do) and parser/compiler friendly. -- Rafael Roquetto | rafael.roque...@kdab.com | Software Engineer Klarälvdalens Datakonsult AB, a KDAB Group company Tel. Sweden (HQ) +46-563-540090, USA +1-866-777-KDAB(5322) KDAB - Qt Experts - Platform-independent software solutions smime.p7s Description: S/MIME cryptographic signature ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Wednesday 15 October 2014 10:09:47 Rafael Roquetto wrote: On Wed, Oct 15, 2014 at 02:36:51PM +0200, Thiago Macieira wrote: On Wednesday 15 October 2014 08:39:27 Rafael Roquetto wrote: No! Not everyone uses Creator or whatever tool. I strongly dislike the idea of having to depend on a specific toolset. What is productive to some can be counter-productive to others. We need to KISS and use a human-readable format that offers the possibility to be manually edited if desired. And for that XML is a huge PITA IMHO. Please, please don't go down that road. The only issue is that the more human-editable the source form is, the harder it is to write a parser and toolchain to configure. Of course, we need to find a compromise in between. In other words, KISS but no simpler. I am not suggesting something based on natural language, actually, I am just arguing against an approach which enforces the usage of an specific tool/editor as an alternative for a better designed textual format. Specially when it comes to settings or schemas. The suggested QTypedSettings class is an example of a human-editable source form which is easy to read (*arguably* easier than condensed XML *IMHO*) being at the same time tool agnostic (any editor will do) and parser/compiler friendly. I'm not sure you got my meaning. How is a config editor tool in Qt Creator going to read write those files? How is the code generator going to read the QTypedSettings source header to genete the equivalent .cpp? -- Thiago Macieira - thiago.macieira (AT) intel.com Software Architect - Intel Open Source Technology Center ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
[Development] QConfig update.
People, I'v read everything on the other two e-mails and I'v changed quite a few things here and again I ask for some advice. What I'v done: QConfig / QConfigGroup / QConfigWatcher combo classes, to be used from the user QConfigIniBackend, to be used internally. QConfig: uses a 'global' QHashQString, QConfigIniBackend for different files in a way that we don't destruct the info when the object is destroyed, but reuses the JSON information stored, and parse it to the config object. it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); I plan to set the defaults via a schema-based file ( could be the KConfigXt based, but I dislike having to edit XML by hand, so something more similar to QML would be best ). Any tougths on that? QConfigWatcher: created automatically via the .watcher() method on QConfig and QConfigGroup Removed the need for pointers and references, implemented via DPointer and move-semantics. Example usage: QConfig config; QConfigGroup window = config.group(window); window.setValue(width, 800); window.setValue(height, 600); window.setValue(x, 100); window.setValue(y,100); window.setValue(opacity, 55); QConfigGroup font = config.group(fonts); font.setValue(family, san-serif); font.setValue(pointSize, 9); font.setValue(bold, true); font.setValue(italic, true); QConfigGroup plasmoids = config.group(plasmoids); for(int i = 0; i 5; i++){ QConfigGroup plasmoid = plasmoids.group(QString::number(i)); plasmoid.setValue(name, name_ + QString::number(i)); plasmoid.setValue(width, rand() % 100 + 100); plasmoid.setValue(value, rand() % 100 + 100); } connect(plasmoids.watcher(), SIGNAL(changed(QConfigGroup)), this, SLOT(plasmoidsChanged(QConfigGroup))); config.sync(); TODO, but only after this part gets perfect, KconfigXT like automatic creation of classes and structures based on a schema file. ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: People, I'v read everything on the other two e-mails and I'v changed quite a few things here and again I ask for some advice. What I'v done: QConfig / QConfigGroup / QConfigWatcher combo classes, to be used from the user QConfigIniBackend, to be used internally. QConfig: uses a 'global' QHashQString, QConfigIniBackend for different files in a way that we don't destruct the info when the object is destroyed, but reuses the JSON information stored, and parse it to the config object. it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value Why the global state? A QConfig should be valid for a single file and constructed on-demand. If you want to share stuff and keep it open, adding something like a KSharedConfig might be a good idea. But again, that is something that could/should be built on-top of QConfig (imo). QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); And how do you check whether window-width was read or not? What do you return on error? A default-constructed value? What type does the value have for that matter? Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. Without the ability to provide a default value, one can never figure out whether `c.value(some-int) == 0` means the value could not be read and a default should be used, or whether the value is 0. I plan to set the defaults via a schema-based file ( could be the KConfigXt based, but I dislike having to edit XML by hand, so something more similar to QML would be best ). Any tougths on that? If you store JSON, maybe use JSON? The mapping will give you the default value and from there you get a type. { foo : 1, bar : { lala: string } } QConfigWatcher: created automatically via the .watcher() method on QConfig and QConfigGroup It should be the other way around, imo. Also see below. Removed the need for pointers and references, implemented via DPointer and move-semantics. Example usage: QConfig config; QConfigGroup window = config.group(window); window.setValue(width, 800); window.setValue(height, 600); window.setValue(x, 100); window.setValue(y,100); window.setValue(opacity, 55); QConfigGroup font = config.group(fonts); font.setValue(family, san-serif); font.setValue(pointSize, 9); font.setValue(bold, true); font.setValue(italic, true); QConfigGroup plasmoids = config.group(plasmoids); for(int i = 0; i 5; i++){ QConfigGroup plasmoid = plasmoids.group(QString::number(i)); plasmoid.setValue(name, name_ + QString::number(i)); plasmoid.setValue(width, rand() % 100 + 100); plasmoid.setValue(value, rand() % 100 + 100); } connect(plasmoids.watcher(), SIGNAL(changed(QConfigGroup)), this, SLOT(plasmoidsChanged(QConfigGroup))); config.sync(); When the context is left, QConfig is destroyed. What happens to the watcher? It stays alive/is leaked? How can the connect work otherwise? TODO, but only after this part gets perfect, KconfigXT like automatic creation of classes and structures based on a schema file. I hope, again, that you reconsider more API from the KConfig world. You decisions with the global state inside QConfig as well as the removal of default-values for reading from the config are very bad imo, and much better handled in K{,Shared}Config. Bye -- Milian Wolff | milian.wo...@kdab.com | Software Engineer KDAB (Deutschland) GmbHCo KG, a KDAB Group company Tel. Germany +49-30-521325470, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] QConfig update.
On Tue, Oct 14, 2014 at 1:35 PM, Milian Wolff milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: People, I'v read everything on the other two e-mails and I'v changed quite a few things here and again I ask for some advice. What I'v done: QConfig / QConfigGroup / QConfigWatcher combo classes, to be used from the user QConfigIniBackend, to be used internally. QConfig: uses a 'global' QHashQString, QConfigIniBackend for different files in a way that we don't destruct the info when the object is destroyed, but reuses the JSON information stored, and parse it to the config object. it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value Why the global state? A QConfig should be valid for a single file and constructed on-demand. If you want to share stuff and keep it open, adding something like a KSharedConfig might be a good idea. But again, that is something that could/should be built on-top of QConfig (imo). so I don't need to open a config file and parse it every time the user created a QConfig object. QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); And how do you check whether window-width was read or not? What do you return on error? A default-constructed value? What type does the value have for that matter? Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. Without the ability to provide a default value, one can never figure out whether `c.value(some-int) == 0` means the value could not be read and a default should be used, or whether the value is 0. Since I wanted to add schema-validation on the low level stuff, this wouldn't be an issue, 'value couldn't be read' would cause an assert. but I can postpone this for later. I plan to set the defaults via a schema-based file ( could be the KConfigXt based, but I dislike having to edit XML by hand, so something more similar to QML would be best ). Any tougths on that? If you store JSON, maybe use JSON? The mapping will give you the default value and from there you get a type. { foo : 1, bar : { lala: string } } Yup - and I'm already working on a schema format conversor for json. QConfigWatcher: created automatically via the .watcher() method on QConfig and QConfigGroup It should be the other way around, imo. Also see below. you are right. :) Removed the need for pointers and references, implemented via DPointer and move-semantics. Example usage: QConfig config; QConfigGroup window = config.group(window); window.setValue(width, 800); window.setValue(height, 600); window.setValue(x, 100); window.setValue(y,100); window.setValue(opacity, 55); QConfigGroup font = config.group(fonts); font.setValue(family, san-serif); font.setValue(pointSize, 9); font.setValue(bold, true); font.setValue(italic, true); QConfigGroup plasmoids = config.group(plasmoids); for(int i = 0; i 5; i++){ QConfigGroup plasmoid = plasmoids.group(QString::number(i)); plasmoid.setValue(name, name_ + QString::number(i)); plasmoid.setValue(width, rand() % 100 + 100); plasmoid.setValue(value, rand() % 100 + 100); } connect(plasmoids.watcher(), SIGNAL(changed(QConfigGroup)), this, SLOT(plasmoidsChanged(QConfigGroup))); config.sync(); When the context is left, QConfig is destroyed. What happens to the watcher? It stays alive/is leaked? How can the connect work otherwise? Right now, it's not leaked but reused every time the same group is created, but I can see it was a bad design decision. Redoing that. :) TODO, but only after this part gets perfect, KconfigXT like automatic creation of classes and structures based on a schema file. I hope, again, that you reconsider more API from the KConfig world. You decisions with the global state inside QConfig as well as the removal of default-values for reading from the config are very bad imo, and much better handled in K{,Shared}Config. Okay - will take a look at K{,Shared}Config to see what the api looks like. Bye -- Milian Wolff | milian.wo...@kdab.com | Software Engineer KDAB (Deutschland) GmbHCo KG, a KDAB Group company Tel. Germany +49-30-521325470, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions
Re: [Development] QConfig update.
On Tuesday 14 October 2014 13:44:30 Tomaz Canabrava wrote: On Tue, Oct 14, 2014 at 1:35 PM, Milian Wolff milian.wo...@kdab.com wrote: On Tuesday 14 October 2014 13:22:51 Tomaz Canabrava wrote: People, I'v read everything on the other two e-mails and I'v changed quite a few things here and again I ask for some advice. What I'v done: QConfig / QConfigGroup / QConfigWatcher combo classes, to be used from the user QConfigIniBackend, to be used internally. QConfig: uses a 'global' QHashQString, QConfigIniBackend for different files in a way that we don't destruct the info when the object is destroyed, but reuses the JSON information stored, and parse it to the config object. it has a QConfigGroup 'global' value that can be acced directly via .setValue and .value Why the global state? A QConfig should be valid for a single file and constructed on-demand. If you want to share stuff and keep it open, adding something like a KSharedConfig might be a good idea. But again, that is something that could/should be built on-top of QConfig (imo). so I don't need to open a config file and parse it every time the user created a QConfig object. Then provide a QSharedConfig or let the user store the QConfig himself, if it turns out to be a performance-bottleneck for him. If you add global state to QConfig, you'll need synchronization or otherwise you are doomed in a multithreaded application. Also: If you add a cheap JSON cache, is it really worth to optimize at all? Furthermore: If you keep the QConfig in memory all the time, you'll probably end up duplicating the stuff as soon as you add the fancy high-level interface on-top. QConfig will operate on JSON after all and you'll incur a conversion penalty whenever you read a value from it. The high-level interface should (hopefully) read the values once and store it internally in the proper type. If you don't do this and always read from QConfig, you'll end up with issues in this pattern: void HighLevelConfig::setFoo(quint64 foo) { if (foo == m_foo) { return; } m_foo = foo; emit fooChanged(foo); } If this would read from QConfig, instead of directly comparing to the quint64 m_foo member, you'll get rounding errors etc. pp. This, the more I think about it, is actually a big issue with a JSON cache in general. .ini does not have that issue as the byte-array gets interpreted based on the type you pass along (a kind of duck-typing). It might mean that you'll have to store everything as a string in JSON to prevent a loss of data when storing e.g. std::limitsquint64::max() (note: JSON only knows double). But storing everything as a string looses the difference between foo=1 and foo=1 Afaik this issue has not yet been discussed, has it? QConfig and QConfigGroup *does not* support setting a default value on the getter, I know that this is used in a lot of places but this can cause inconsistencies: Main.cpp QConfig c; c.value(window-width, 800); MainWindow.cpp c.value(window-width, 1200); so we must create a better way for that. for now, I simply removed the possibility for that, we can only do c.value(window-width); And how do you check whether window-width was read or not? What do you return on error? A default-constructed value? What type does the value have for that matter? Imo, this makes this API extremely inconvenient. Yes it's possible to do an error, but that is life. You should only add such error-prevention stuff into the high-level schema stuff, not into QConfig itself. Without the ability to provide a default value, one can never figure out whether `c.value(some-int) == 0` means the value could not be read and a default should be used, or whether the value is 0. Since I wanted to add schema-validation on the low level stuff, this wouldn't be an issue, 'value couldn't be read' would cause an assert. but I can postpone this for later. Most applications, (all KDE applications btw), would then assert. Initially, no configuration file is available after all. And again: Please do not overdesign QConfig. KISS! Add fancy schema-validation and stuff on-top of that. Don't remove something as essential as reading a setting with a default value fallback mechanism! Bye -- Milian Wolff | milian.wo...@kdab.com | Software Engineer KDAB (Deutschland) GmbHCo KG, a KDAB Group company Tel. Germany +49-30-521325470, Sweden (HQ) +46-563-540090 KDAB - Qt Experts - Platform-independent software solutions ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development