Converted configuration code to use QSettings.

Tue, 06 Aug 2013 13:32:07 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Tue, 06 Aug 2013 13:32:07 +0300
changeset 436
4268a5507725
parent 435
bc3a51394953
child 437
51313dba897d

Converted configuration code to use QSettings.

src/common.h file | annotate | diff | comparison | revisions
src/config.cpp file | annotate | diff | comparison | revisions
src/config.h file | annotate | diff | comparison | revisions
src/dialogs.cpp file | annotate | diff | comparison | revisions
src/dialogs.h file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/primitives.cpp file | annotate | diff | comparison | revisions
src/ui/ldrawpath.ui file | annotate | diff | comparison | revisions
--- a/src/common.h	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/common.h	Tue Aug 06 13:32:07 2013 +0300
@@ -45,6 +45,9 @@
 #define BUILD_RC       3
 #define BUILD_RELEASE  4
 
+// Uncomment for portable build... maybe it's time to move to cmake?
+#define PORTABLE
+
 // =============================================
 #if (BUILD_ID != BUILD_INTERNAL)
 #define RELEASE
--- a/src/config.cpp	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/config.cpp	Tue Aug 06 13:32:07 2013 +0300
@@ -17,171 +17,121 @@
  */
 
 #include <errno.h>
-#include <time.h>
 #include <QDir>
 #include <QTextStream>
+#include <QSettings>
 #include "common.h"
 #include "config.h"
 #include "misc.h"
 #include "gui.h"
+#include "file.h"
 
 config* g_configPointers[MAX_CONFIG];
 static ushort g_cfgPointerCursor = 0;
 
 // =============================================================================
+static QSettings* getSettingsObject() {
+#ifdef PORTABLE
+# ifdef _WIN32
+#  define EXTENSION ".ini"
+# else
+#  define EXTENSION ".cfg"
+# endif // _WIN32
+	return new QSettings (str (APPNAME).toLower() + EXTENSION, QSettings::IniFormat);
+#else
+	return new QSettings;
+#endif // PORTABLE
+}
+
+// =============================================================================
 // Load the configuration from file
 bool config::load() {
-	print ("config::load: Loading configuration file...\n");
-	print ("config::load: Path to configuration is %1\n", filepath());
-
-	// Locale must be disabled for atof
-	setlocale (LC_NUMERIC, "C");
-
-	File f (filepath(), File::Read);
-	int ln = 0;
-
-	if (!f)
-		return false;
-
-	// Read the values.
-	for (str line : f) {
-		ln++;
-
-		if (line.isEmpty() || line[0] == '#')
-			continue; // Empty line or comment.
-
-		// Find the equals sign.
-		int equals = line.indexOf ('=');
-		
-		if (equals == -1) {
-			fprint (stderr, "couldn't find `=` sign in entry `%1`\n", line);
-			continue;
-		}
-		
-		str entry = line.left (equals);
-		str valstring = line.right (line.length() - equals - 1);
-		
-		// Find the config entry for this.
-		config* cfg = null;
-		
-		for (config* i : g_configPointers) {
-			if (!i)
-				break;
-			
-			if (entry == i->name)
-				cfg = i;
-		}
-		
-		if (!cfg) {
-			fprint (stderr, "unknown config `%1`\n", entry);
-			continue;
-		}
-		
-		switch (cfg->getType()) {
-		case Type_int:
-			static_cast<intconfig*> (cfg)->value = valstring.toInt();
-			break;
-		
-		case Type_str:
-			static_cast<strconfig*> (cfg)->value = valstring;
-			break;
-		
-		case Type_float:
-			static_cast<floatconfig*> (cfg)->value = valstring.toFloat();
-			break;
-		
-		case Type_bool: {
-			bool& val = static_cast<boolconfig*> (cfg)->value;
-			
-			if (valstring.toUpper() == "TRUE" || valstring == "1")
-				val = true;
-			elif (valstring.toUpper() == "FALSE" || valstring == "0")
-				val = false;
-			
-			break;
-		}
-		
-		case Type_keyseq:
-			static_cast<keyseqconfig*> (cfg)->value = keyseq::fromString (valstring);
-			break;
-		
-		default:
-			break;
-		}
-	}
-	
-	f.close();
-	return true;
-}
-
-extern_cfg (str, io_ldpath);
-
-// =============================================================================
-// Save the configuration to disk
-bool config::save() {
-	// The function will write floats, disable the locale now so that they
-	// are written properly.
-	setlocale (LC_NUMERIC, "C");
-	
-	// If the directory doesn't exist, create it now.
-	if (QDir (dirpath()).exists() == false) {
-		fprint (stderr, "Creating config path %1...\n", dirpath());
-		
-		if (!QDir().mkpath (dirpath())) {
-			critical ("Failed to create the configuration directory. Configuration cannot be saved!\n");
-			return false;
-		}
-	}
-	
-	File f (filepath(), File::Write);
-	print ("writing cfg to %1\n", filepath());
-	
-	if (!f) {
-		critical (fmt (QObject::tr ("Cannot save configuration, cannot open %1 for writing: %2\n"),
-			filepath(), strerror (errno)));
-		return false;
-	}
-	
-	fprint (f, "# Configuration file for " APPNAME "\n");
-	str valstring;
+	QSettings* settings = getSettingsObject();
+	print ("config::load: Loading configuration file from %1...\n", settings->fileName());
 	
 	for (config* cfg : g_configPointers) {
 		if (!cfg)
 			break;
 		
-		if (cfg->isDefault())
-			continue;
-		
-		switch (cfg->getType()) {
-		case Type_int:
-			valstring = fmt ("%1", static_cast<intconfig*> (cfg)->value);
-			break;
-		
-		case Type_str:
-			valstring = static_cast<strconfig*> (cfg)->value;
-			break;
-		
-		case Type_float:
-			valstring = fmt ("%1", static_cast<floatconfig*> (cfg)->value);
+		cfg->loadFromConfig (settings);
+	}
+	
+	settings->deleteLater();
+	return true;
+}
+
+// =============================================================================
+void intconfig::loadFromConfig (const QSettings* cfg) {
+	QVariant val = cfg->value (name, str::number (defval));
+	value = val.toInt();
+}
+
+void floatconfig::loadFromConfig (const QSettings* cfg) {
+	QVariant val = cfg->value (name, str::number (defval));
+	value = val.toFloat();
+}
+
+void strconfig::loadFromConfig (const QSettings* cfg) {
+	QVariant val = cfg->value (name, defval);
+	value = val.toString();
+}
+
+void boolconfig::loadFromConfig (const QSettings* cfg) {
+	QVariant val = cfg->value (name, str::number (defval));
+	value = val.toBool();
+}
+
+void keyseqconfig::loadFromConfig (const QSettings* cfg) {
+	QVariant val = cfg->value (name, defval.toString());
+	value = keyseq (val.toString());
+}
+
+// =============================================================================
+// TODO: make virtual
+str config::toString() const {
+	switch (getType()) {
+	case Type_int:
+		return fmt ("%1", static_cast<const intconfig*> (this)->value);
+		break;
+	
+	case Type_str:
+		return static_cast<const strconfig*> (this)->value;
+		break;
+	
+	case Type_float:
+		return fmt ("%1", static_cast<const floatconfig*> (this)->value);
+		break;
+	
+	case Type_bool:
+		return (static_cast<const boolconfig*> (this)->value) ? "true" : "false";
+		break;
+	
+	case Type_keyseq:
+		return static_cast<const keyseqconfig*> (this)->value.toString();
+		break;
+	
+	default:
+		break;
+	}
+	
+	return "";
+}
+
+// =============================================================================
+// Save the configuration to disk
+bool config::save() {
+	QSettings* settings = getSettingsObject();
+	print ("Saving configuration to %1...\n", settings->fileName());
+	
+	for (config* cfg : g_configPointers) {
+		if (!cfg)
 			break;
 		
-		case Type_bool:
-			valstring = (static_cast<boolconfig*> (cfg)->value) ? "true" : "false";
-			break;
-		
-		case Type_keyseq:
-			valstring = static_cast<keyseqconfig*> (cfg)->value.toString();
-			break;
-		
-		default:
-			break;
-		}
-		
-		// Write the entry now.
-		fprint (f, "%1=%2\n", cfg->name, valstring);
+		settings->setValue (cfg->name, cfg->toString());
 	}
 	
-	f.close();
+	settings->sync();
+	settings->deleteLater();
 	return true;
 }
 
@@ -196,21 +146,31 @@
 }
 
 // =============================================================================
-str config::filepath() {
-	str path = fmt ("%1%2.cfg", dirpath(), str (APPNAME).toLower());
-	return path;
+str config::filepath (str file) {
+	return config::dirpath() + DIRSLASH + file;
 }
 
 // =============================================================================
 str config::dirpath() {
-#ifndef _WIN32
-	return fmt ("%1" DIRSLASH ".%2" DIRSLASH,
-		QDir::homePath(), str (APPNAME).toLower());
-#else
-	return fmt ("%1" DIRSLASH APPNAME DIRSLASH, QDir::homePath());
-#endif // _WIN32
+	QSettings* cfg = getSettingsObject();
+	return dirname (cfg->fileName());
 }
 
+// =============================================================================
+str config::defaultString() const {
+	str defstring = m_defstring;
+	
+	// String types inevitably get extra quotes in their default string due to
+	// preprocessing stuff. We can only remove them now...
+	if (getType() == Type_str) {
+		defstring.remove (0, 1);
+		defstring.chop (1);
+	}
+	
+	return defstring;
+}
+
+// =============================================================================
 void addConfig (config* ptr) {
 	if (g_cfgPointerCursor == 0)
 		memset (g_configPointers, 0, sizeof g_configPointers);
--- a/src/config.h	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/config.h	Tue Aug 06 13:32:07 2013 +0300
@@ -24,6 +24,7 @@
 // =============================================================================
 #include <QString>
 #include <QKeySequence>
+class QSettings;
 
 typedef QChar qchar;
 typedef QString str;
@@ -31,7 +32,7 @@
 #define MAX_INI_LINE 512
 #define MAX_CONFIG 512
 
-#define cfg(T, NAME, DEFAULT) T##config NAME (DEFAULT, #NAME)
+#define cfg(T, NAME, DEFAULT) T##config NAME (DEFAULT, #NAME, #DEFAULT)
 #define extern_cfg(T, NAME)   extern T##config NAME
 
 // =========================================================
@@ -46,23 +47,28 @@
 		Type_keyseq,
 	};
 
+	config (const char* defstring) : m_defstring (defstring) {}
 	const char* name;
 
 	virtual Type getType() const {
 		return Type_none;
 	}
-
+	
+	str toString() const;
+	str defaultString() const;
 	virtual void resetValue() {}
-	virtual bool isDefault() const {
-		return false;
-	}
-
+	virtual void loadFromConfig (const QSettings* cfg) { (void) cfg; }
+	virtual bool isDefault() const { return false; }
+	
 	// ------------------------------------------
 	static bool load();
 	static bool save();
 	static void reset();
 	static str dirpath();
-	static str filepath();
+	static str filepath (str file);
+	
+private:
+	const char* m_defstring;
 };
 
 void addConfig (config* ptr);
@@ -113,7 +119,7 @@
 #define IMPLEMENT_CONFIG(T) \
 	T value, defval; \
 	\
-	T##config (T _defval, const char* _name) { \
+	T##config (T _defval, const char* _name, const char* defstring) : config (defstring) { \
 		value = defval = _defval; \
 		name = _name; \
 		addConfig (this); \
@@ -129,7 +135,8 @@
 	} \
 	virtual bool isDefault() const { \
 		return value == defval; \
-	}
+	} \
+	virtual void loadFromConfig (const QSettings* cfg) override;
 
 // =============================================================================
 CONFIGTYPE (int) {
--- a/src/dialogs.cpp	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/dialogs.cpp	Tue Aug 06 13:32:07 2013 +0300
@@ -150,6 +150,7 @@
 	connect (ui->path, SIGNAL (textEdited (QString)), this, SLOT (slot_tryConfigure()));
 	connect (ui->searchButton, SIGNAL (clicked()), this, SLOT (slot_findPath()));
 	connect (ui->buttonBox, SIGNAL (rejected()), this, validDefault ? SLOT (reject()) : SLOT (slot_exit()));
+	connect (ui->buttonBox, SIGNAL (accepted()), this, SLOT (slot_accept()));
 	
 	setPath (io_ldpath);
 	
@@ -201,6 +202,11 @@
 	okButton()->setEnabled (true);
 }
 
+void LDrawPathDialog::slot_accept() {
+	config::save();
+	accept();
+}
+
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
--- a/src/dialogs.h	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/dialogs.h	Tue Aug 06 13:32:07 2013 +0300
@@ -85,6 +85,7 @@
 	void slot_findPath();
 	void slot_tryConfigure();
 	void slot_exit();
+	void slot_accept();
 };
 
 // =============================================================================
--- a/src/main.cpp	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/main.cpp	Tue Aug 06 13:32:07 2013 +0300
@@ -58,7 +58,10 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 int main (int argc, char* argv[]) {
-	const QApplication app (argc, argv);
+	QApplication app (argc, argv);
+	app.setOrganizationName (APPNAME);
+	app.setApplicationName (APPNAME);
+	
 	g_app = &app;
 	LDFile::setCurrent (null);
 	
--- a/src/primitives.cpp	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/primitives.cpp	Tue Aug 06 13:32:07 2013 +0300
@@ -45,7 +45,7 @@
 	loadPrimitiveCatgories();
 	
 	// Try to load prims.cfg
-	File conf (config::dirpath() + "prims.cfg", File::Read);
+	File conf (config::filepath ("prims.cfg"), File::Read);
 	
 	if (!conf) {
 		// No prims.cfg, build it
@@ -124,7 +124,7 @@
 	}
 	
 	// Save to a config file
-	File conf (config::dirpath() + "prims.cfg", File::Write);
+	File conf (config::filepath ("prims.cfg"), File::Write);
 	
 	for (Primitive & info : m_prims)
 		fprint (conf, "%1 %2\n", info.name, info.title);
--- a/src/ui/ldrawpath.ui	Sat Aug 03 12:31:36 2013 +0300
+++ b/src/ui/ldrawpath.ui	Tue Aug 06 13:32:07 2013 +0300
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>344</width>
-    <height>112</height>
+    <height>123</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -57,6 +57,19 @@
     </widget>
    </item>
    <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
@@ -71,22 +84,5 @@
  <resources>
   <include location="../../ldforge.qrc"/>
  </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>LDPathUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
+ <connections/>
 </ui>

mercurial