Settings und XML

Verschiedenes zu Qt
Antworten
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Settings und XML

Beitrag von franzf »

Hi,

Steh vor einem "kleinen" Entscheidungsproblem, vllt. kann mich jemand in die richtige Richtung schubsen...

Ich will meine Settings via XML speichern. Ginge ja eigentlich recht einfach, in dem man ein neues Settings-Format (+read/write-fkt-pointer) registriert.
Nur will ich teilweise die Settings als Attribute, teils auch als text() speichern.
Und das weiß ich jetzt nicht, wie ich das dem QSettings einbläuen kann, ist ja recht XML-spezifisch.

(Hintergrund: Ich will die Klasse dann auch einfach für Templates verwenden. Darin werden dann benötigte Plugins aufgelistet welche geladen werden. Jedes Plugin hat seine eigenen Einstellungen.
Diese will ich dann einfach erzeugen können ala "Config* getConfig(QDomElement e)" oder so.)

Gut, fange ich mal an was eigenes zu schreiben. Wollte vorab mal testen, wie ich z.B. ein QVariant aus nem String mache, welcher eine StringList repräsentiert. (QDomElement gibt ja überall nen QString zurück)
da fängt es schon an.

Code: Alles auswählen

QString str("Hello, world"); // So speichert QSettings die QStringList ab
QVariant v(str);
QStringList l = v.toStringList();
qDebug() << l.size();
tja, die Größe ist 1...
Ich könnte jetzt ja schreiben

Code: Alles auswählen

QStringList l = v.toString().split(", ");
Aber das ist ja nicht der Sinn des Variant.

Langer Rede kurzer Sinn:
Ich müsste wohl die ganze QSettingsPrivate kopieren (und anpassen), um hier eine funktionierende Klasse bieten zu können. Das ist nicht der Sinn von OOP, kreiert Fehler, und nicht zuletzt kann es zu Lizenzrechtlichen Problemen führen (Auch LGPL verbietet Code-Veränderungen, wenn ich das mal kommerziell vertreiben wollte).

Soll ich also jetzt meine Settings einheitlich als Attribut oder text des QDomElement speichern, oder versuchen, die Probleme der korrekten Konvertierung ohne Spicken im Qt-Quelltext zu lösen?

Oder hat jemand noch nen anderen Tip? (Z.B. ne fertige (L)GPL-XMLSettings-Klasse :D)

Besten Dank
Franz
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Tja, ich hab jetzt eine für mich passable Lösung auf Basis von QSettings + eigenem Format gefunden.
Nur ist mir eine Sache aufgefallen:
Ich hab eine Funktion, die rekursiv (startend bei QDomDocument::documentElement) über alle Nodes läuft. Die (momentan) nodeName()s werden per "/" getrennt (=key) und das nodeValue() (=value) in die map gelegt (jetzt in readFunc()).
War kurz vorm Irrenhaus, weil zwar der Key eingefügt wurde, aber nicht das value (nur ein leerer QVariant).
Das lag einfach nur an dem führenden "/" im key. wenn ich key.mid(1) nehm, geht alles glatt.

Code: Alles auswählen

bool readFkt( QIODevice&, QSettings::SettingsMap& map )
{
    map.insert("Test/Test1", "test1");  // "Test/Test1" QVariant(QString, "test1")
    map.insert("/Test/Test2", "test2"); // "/Test/Test2" QVariant(, )
    return true;
}
Wenn ich aber settings.setValue("/ein/key", "einValue"); mache, entfernt der automatisch den führenden "/".
Ist das ein Bug? Wäre ein request bei qtsoftware da angebracht (schlimm ist es ja nicht - wenn man weiß woran man sich halten muss... In der Doku steht nur nix)

Grüße
Franz
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Gehen wir doch mal streng OOP mässig an die Sache ran.

Du erzaehlst was von QSettings: ok
Du erzaehlst was von nem eigenen Format: ok

ergo, du baust quasi nen Plugin zu ner Schnittstelle .... mit QSetting als eben dieser Schnittstelle.
Das macht aber meistens nur Sinn, wenn du scho Module hasst die mit vorhandenen QSettings funktionieren du aber nachtraeglich das format austauschen willst, bzw. du transparent zum modul das format umschaltbar machen willst, aus irgendwelchen gruenden.
Du z.b. spaeter mal wieder auf die Standard QSettings impl zurueckwillst ... aus irgendwelchen gruenden.
Das heisst allerdings auch, dass du der Schnittstelle keinerlei weitere funktionalitaet und /oder keine weiterer restrictionen mehr zufuegen solltest.

Beides, les ich aus deinem post raus, iss ned so 100%ig gegeben.

Und eigentlich soll QSettings auch sowas ned sein ....
Sondern ne einfache impl fuer den Zugriff auf einfache config files im BS spezifischen Rahmen.

Ich wuerd an deiner stelle ne neue schnittstelle bauen, die vielleicht bissi aehnlich zu qsettings ist, aber doch viel emhr auf deine beduerfnisse zugeschnitten. Und bei der impl kannst du dich dann viel einfacher tun ...

Noch ne Anmerkung:

Plugins (von Fremdzulieferern) die sich in vorhandenen, von uns verwalteten dateien serialisieren muessen, haben wir hier auch ....

Wir haben scho mehrere Loesungen versucht, sind aber immer an grenzen gestossen. Selbst eine Schnittstelle ala QProperty (aber was ohne Qt) .... wo man fast jeden Datentyp und beliebige Listen wegspeichern kann, kam ueber kurz oder lang an ihre Grenzen .... du glaubst gar ned, was und wie manche ihr zeugs serialisieren wollen.

Momentan haben wir nen Mischverbau, wo die plugins dynamisch drauf reagieren koennen.
Beim uebergeben der serialize schnittstelle kriegt das plugin das eigentliche, von der anwendung verwendete format (binaer, plain text, xml) und die zeichencodierung mit.
das plugin schiesst dann alles in nen binaeren datenstrom, gibt das der anwendung zurueck, und sagt der anwendung, was es da reingeschrieben hat (binaer, plain text, xml).
Die anwendung entscheidet dann selber, wie es die daten einbettet .... z.b. wenn beides XML ist, liest die anwendung die eingestellten daten ein, und haengt die komplette XML struktur unter den entsprechend fuer das pligin gebauten knoten. (geht mit der qt schoen easy).
Isses was anderes als xml, wird das zeugs als binaerblock (base64 codiert) im xml von der app abgelegt.

Das nur mal als beispiel, wie man es treiben kann, besonders wenn du mit zig anderen dich immer irgendwie einigen musst ^^
Also verbau dir ned zu viel durch ungeeignete Schnittstellen (ich find die meisten qt klassen ned als schnittstellen geeignet).


Ciao ...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Danke RHBaum für deine Antwort!
RHBaum hat geschrieben:ergo, du baust quasi nen Plugin zu ner Schnittstelle .... mit QSetting als eben dieser Schnittstelle.
Nö. Ich habe eigene Interfaces (+ teilweise Defaultimplementierungen), auf denen die Plugins aufsetzen, QSettings will ich wirklich nur zum Speichern der Einstellungen verenden.
Das macht aber meistens nur Sinn, wenn du scho Module hasst die mit vorhandenen QSettings funktionieren du aber nachtraeglich das format austauschen willst, bzw. du transparent zum modul das format umschaltbar machen willst, aus irgendwelchen gruenden.
Du z.b. spaeter mal wieder auf die Standard QSettings impl zurueckwillst ... aus irgendwelchen gruenden.
Das heisst allerdings auch, dass du der Schnittstelle keinerlei weitere funktionalitaet und/oder keine weiterer restrictionen mehr zufuegen solltest.
Ich will nicht auf die Standard-QSettings zurück. Die sind mir zu "flach".

Code: Alles auswählen

settings.setValue("eins/zwei/drei/vier/fünf/sechs", "Tiiiiiief drinnen im Wald");

wird zu

[eins]
zwei\drei\vier\fuennf\sechs=Tiiiiiief drinnen im Wald
Da bietet sich XML schon an, insbesondere wenn man mal selbst Hand anlegen will, wäre die Standard-QSettings-ini recht unübersichtlich.
Und eigentlich soll QSettings auch sowas ned sein ....
Sondern ne einfache impl fuer den Zugriff auf einfache config files im BS spezifischen Rahmen.
Naja, wenn Qt die Möglichkeit bietet, eigene Formate zu registrieren (und dann auch zu verwenden) warum sollte man sich das nicht zu Nutze machen?
Also auch BS-unabhängig seine Einstellungen speichern?

Ich weiß, das mit den xml-templates (also keine Klassen/Funktionstemplates!!!) geht vllt. ein bisschen weit mit QSettings.
Aber wenn es funktioniert, warum sollte ich es nicht verwenden?
Ich wuerd an deiner stelle ne neue schnittstelle bauen, die vielleicht bissi aehnlich zu qsettings ist, aber doch viel emhr auf deine beduerfnisse zugeschnitten. Und bei der impl kannst du dich dann viel einfacher tun ...
Naja, genau das hab ich ja schon angegangen. Nur gibt es Probleme beim umwandeln (in z.B. QStringList) der eingelesenen Strings. Und um das zu gewährleisten, müsste ich wohl von Grund auf vieles neu schreiben (bzw. eben kopieren), was eh schon mit QSettings verfügbar ist. Und auf ständiges neu kopieren der Methoden aus QSettingsPrivate (und evtl. patchen) mit jedem neuen Qt-Release hab ich wirklich keine Lust.
Noch ne Anmerkung:
[...]
Das ist wirklich etwas heftig, und ob das bei mir so ausartet ist fraglich.

Grüße
Franz
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Aber wenn es funktioniert, warum sollte ich es nicht verwenden?
Die frage ist, funktioniert es denn ?
Und was bringts wenn es verwendest ?

Problem bei QSettings ist, das die Schnittstelle eben auch recht flach ist ...

QSettings ist toll und macht sinn, wenn man sich an spielregeln haelt.
Eine der Spielregel ist ... benutzte gaengiges Format der initialisierungsdateien !
unter Windows ist es nun mal das ini format und die registry ....

XML definitiv (noch) nicht

Das ganze wuerde imho nur sinn machen wenn du anderen Anwendungen zugriff auf deine inis gewaehren willst, ohne den nen eigenes interface vorzuschreiben ... und ist das bei dir der fall ?
Deine plugins fallen auch ned drunter, weil die fuetterst ja eh mit deinem interface oder ?

was erleichtert dir denn das QSettings so dermassen, das es in dem fall nutzen willst ? das lesen und schreiben ? wohl eher nicht ... sonst wuerdes ned ueber nen eigenes format template nachdenken.
DIe Plattformunabhaengigkeit ? bei XML bekommst die auch so hin ...

was ist es ?

Ciao ...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

RHBaum hat geschrieben:was erleichtert dir denn das QSettings so dermassen, das es in dem fall nutzen willst ? das lesen und schreiben ? wohl eher nicht ...
Doch, genau das ist es.
Hast du schon mal versucht, aus einem QString (z.B. QDomElement::text()), in welchem ein QVariant seinen Inhalt geschrieben hat, welcher eine QStringList darstellt, einen korrekten Wert zu bekommen?
Via QSettings ist das per default eine Komma-separierte Liste.

Code: Alles auswählen

QString listVal=""Hello", "World"";
QVariant v(listVal);
qDebug() << v.toStringList().size();
Das Ergebnis ist ---- 1 ....
Und nicht 2.
Das gleiche Spielchen, wenn ich den Variant mit festem type=QVariant::StringList erstelle.
Oder wenn ich den String nehm, den variant direkt über qDebug() ausgibt (QVariant(QStringList, ("Hello", "World") )).

Die ganze "Magie" hinter der korrekten Konvertierung von Strings nach (korrekt typisiertem) Variant steckt in QSettingsPrivate. Und auf die hab ich keinen Zugriff. Ich müsste, wenn ich was komplett eigenes schreibe (ohne Ableiten von QSettings) also das ganze Handling aus QSettingsPrivate kopieren (-> erwähntes Lizenz-Problem) oder mich hinsetzen, und mir den kompletten Code (ohne bei Qt zu spicken, was eh nur noch halb gegeben ist) selbst aus den Fingern ziehen.

Ich hoffe du verstehst jetzt mein Probem.

Ich würde mir eine eigene Klasse resp. eine Funktion in Qt4 wünschen, die das erledigt und NICHT irgendwo in einer Private-Klasse versteckt ist.

Grüße
Franz
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Ich hoffe du verstehst jetzt mein Probem.
Aehm ... Noe, ned ganz :!:

Warum nutzt du XML, oder willst XML nutzen, wenn du die Gliederungsmöglichkeiten von XML wieder aussen vor laesst.
Stringlisten sollt man in XML ned als Komma seperierte listen speichern, sondern in Knoten !
kann es zu Lizenzrechtlichen Problemen führen (Auch LGPL verbietet Code-Veränderungen, wenn ich das mal kommerziell vertreiben wollte).
Bin jetzt kein jurist, aber:
die kommerzielle version der QT verbietet dir nicht, teile der QT zu nehmen und fuer eigene Funktionen zu kopieren und damit die funktionalitaet der QT fuer dein Projekt erweitern .... du darfst diese funktionalitaet natuerlich dann nie ohne die qt verteilen /vertreiben, klar.

bei der GPL version musst eh deine eigene Funktionalitaet sowieso offen legen ....

Ciao ...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

RHBaum hat geschrieben:Warum nutzt du XML, oder willst XML nutzen, wenn du die Gliederungsmöglichkeiten von XML wieder aussen vor laesst.
Stringlisten sollt man in XML ned als Komma seperierte listen speichern, sondern in Knoten!
Wow, danke! Das war der Tritt, den ich gebraucht hab...
Dann sollte ich das jetzt hinbekommen.
kann es zu Lizenzrechtlichen Problemen führen (Auch LGPL verbietet Code-Veränderungen, wenn ich das mal kommerziell vertreiben wollte).
Bin jetzt kein jurist, aber:
die kommerzielle version der QT verbietet dir nicht, teile der QT zu nehmen und fuer eigene Funktionen zu kopieren und damit die funktionalitaet der QT fuer dein Projekt erweitern .... du darfst diese funktionalitaet natuerlich dann nie ohne die qt verteilen /vertreiben, klar.

bei der GPL version musst eh deine eigene Funktionalitaet sowieso offen legen ....
Mein Hintergedanke war eigentlich schon auf Qt-4.5 bezogen. Da kann man ja Closed Source Programme schreiben, ohne Lizenz. Dank LGPL.
(Keine Ahnung, ob ich das wirklich machen will, bin eigentlich absoluter OpenSource-Fanatiker. Aber momentan könnte ich echt jeden Euro brauchen :D). Und wenn ich in ner Closed-Source-app Qt-eigenen Code verwende, ist das problematisch.

LGPL erlaubt ja nur deynamisches Linken gegen die betreffenden Bibliotheken. Statisch linken ist nicht erlaubt.
Probleme stellen auch schon Templates und Macros dar, da diese ja erst mit meiner app (und auch direkt IN meine app) kompiliert werden. LGPL sieht (AFAIK) max. 10 Zeilen lange Macros vor, templates sind glaub ich sogar verboten (müsste ich aber erst nochmal nachschaeun). Da wird Qtsoftware ne eigene Klausel hinzufügen müssen, dass die Templates und Macros kein Hinderungsgrund für LGPL sind.

Grüße
Franz

// edit:
nachgeschaut:
Sofern Macros, inline-Funktionen und Templates mit weniger als 10 Zeilen enthalten sind, kann man auf eine zusätzliche Klausel verzichten (so verstehe ich Abschnitt 3 der LGPL).
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Und wenn ich in ner Closed-Source-app Qt-eigenen Code verwende, ist das problematisch.
Ausserdem eh technisch gesehen ned so ohne weiteres möglich ...

Der meiste QT code baut auf QT klassen auf ! Grad dein Besipiel mit der QSettings umsetzung.
Wie willst du den code kopieren, wenn du selber ned gegen die QT linken darfst ???
Fuer alles was gegen die QT linkt, ist die LGPL eh bedeutungslos, da kommt nur die kommerzielle und die GPL in frage.
Bei der kommerziellen ist es ausdruecklich, und bei der GPL impliziet erlaubt.

Einige "Ideen" der QT mit QT freien klassen umsetzen, davor wird sich Trolltech/nokia bned schuetzen koennen, sei denn die haben Patente auf diverse Code Muster, was mir neu waer. Wobei sie selber natuerlich auch auf bekannte muster aufsetzen ....

Noch mal zur erklaerung:
.
LGPL erlaubt ja nur deynamisches Linken gegen die betreffenden Bibliotheken.
richtig ....
Aber, entwickeln ohne statisches linken mit der QT ist ned vorgesehen. D.h. momentan wirst du immer Linken, zumindest gegen die import libs !

Fuer dich ist also eine QT mit LGPL Lizenz eigentlich aus technischen gruenden total unintressant. Das einzige was fuer dich intressant ist, ist das ein projekt was die (L)GPL version der QT verwendet, auf die LGPL switchen kann !!!
Das heisst du kannst selber Libs bauen, die die QT verwenden und unter LGPL stehen.
Das wiederum heisst, das kommerzielle produkte gegen diese LGPL Bib dynamisch linken deurfen ... ohne die GPL der QT zu verletzen .

Zumindest unter windows isses so ....

Linux ... keine ahnung wie da Dynamisches linken definiert wird .... aber normal exportiert da ne .so mehr infos als ne dll, weshalb auch der schritt mit der exportlib meist entfaellt.

Ciao ..
Antworten