Now compiles and links but crashes shortly after startup.

Mon, 31 Aug 2015 20:50:12 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Mon, 31 Aug 2015 20:50:12 +0300
changeset 971
c00f9665a9f8
parent 970
c8aae45afd85
child 972
a34b73114823

Now compiles and links but crashes shortly after startup.

.hgignore file | annotate | diff | comparison | revisions
CMakeLists.txt file | annotate | diff | comparison | revisions
codegen/CMakeLists.txt file | annotate | diff | comparison | revisions
codegen/codegen.cpp file | annotate | diff | comparison | revisions
src/addObjectDialog.cpp file | annotate | diff | comparison | revisions
src/configDialog.cpp file | annotate | diff | comparison | revisions
src/configDialog.h file | annotate | diff | comparison | revisions
src/configuration.cpp file | annotate | diff | comparison | revisions
src/configuration.h file | annotate | diff | comparison | revisions
src/dialogs/colorselector.cpp file | annotate | diff | comparison | revisions
src/dialogs/ldrawpathdialog.cpp file | annotate | diff | comparison | revisions
src/dialogs/ldrawpathdialog.h file | annotate | diff | comparison | revisions
src/dialogs/newpartdialog.cpp file | annotate | diff | comparison | revisions
src/editmodes/abstractEditMode.cpp file | annotate | diff | comparison | revisions
src/glCompiler.cpp file | annotate | diff | comparison | revisions
src/glRenderer.cpp file | annotate | diff | comparison | revisions
src/glRenderer.h file | annotate | diff | comparison | revisions
src/ldDocument.cpp file | annotate | diff | comparison | revisions
src/ldObject.cpp file | annotate | diff | comparison | revisions
src/ldpaths.cpp file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/miscallenous.cpp file | annotate | diff | comparison | revisions
src/miscallenous.h file | annotate | diff | comparison | revisions
src/partDownloader.cpp file | annotate | diff | comparison | revisions
src/partDownloader.h file | annotate | diff | comparison | revisions
src/primitives.cpp file | annotate | diff | comparison | revisions
src/toolsets/algorithmtoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/basictoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/extprogramtoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/extprogramtoolset.h file | annotate | diff | comparison | revisions
src/toolsets/filetoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/movetoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/toolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/viewtoolset.cpp file | annotate | diff | comparison | revisions
tools/caseconversions.py file | annotate | diff | comparison | revisions
tools/configcollector.py file | annotate | diff | comparison | revisions
tools/outputfile.py file | annotate | diff | comparison | revisions
tools/updaterevision.py file | annotate | diff | comparison | revisions
--- a/.hgignore	Mon Aug 31 04:57:16 2015 +0300
+++ b/.hgignore	Mon Aug 31 20:50:12 2015 +0300
@@ -12,3 +12,4 @@
 *.rej
 *.orig
 CMakeLists.txt.user
+*.pyc
--- a/CMakeLists.txt	Mon Aug 31 04:57:16 2015 +0300
+++ b/CMakeLists.txt	Mon Aug 31 20:50:12 2015 +0300
@@ -27,20 +27,12 @@
 	COMMAND python "${CMAKE_SOURCE_DIR}/tools/updaterevision.py" hginfo.h
 	WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 
-add_custom_target (config_collection ALL
-	COMMAND python
-		"${CMAKE_SOURCE_DIR}/tools/configcollector.py"
-		--header configurationvaluebag.h
-		--source configurationvaluebag.cpp
-	WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
-
 include_directories (${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
 
 set (LDFORGE_SOURCES
 	src/addObjectDialog.cpp
 	src/basics.cpp
 	src/colors.cpp
-	src/configuration.cpp
 	src/configDialog.cpp
 	src/crashCatcher.cpp
 	src/dialogs.cpp
@@ -48,9 +40,10 @@
 	src/editHistory.cpp
 	src/glRenderer.cpp
 	src/glCompiler.cpp
+	src/hierarchyelement.cpp
 	src/ldDocument.cpp
 	src/ldObject.cpp
-    src/ldObjectMath.cpp
+	src/ldObjectMath.cpp
 	src/ldpaths.cpp
 	src/main.cpp
 	src/mainwindow.cpp
@@ -79,6 +72,7 @@
 	src/toolsets/movetoolset.cpp
 	src/toolsets/toolset.cpp
 	src/toolsets/viewtoolset.cpp
+	${CMAKE_BINARY_DIR}/configurationvaluebag.cpp
 )
 
 set (LDFORGE_HEADERS
@@ -102,11 +96,11 @@
 	src/configDialog.h
 	src/glRenderer.h
 	src/glCompiler.h
-	src/configuration.h
 	src/mainwindow.h
 	src/editHistory.h
 	src/format.h
 	src/ldpaths.h
+	src/hierarchyelement.h
 	src/dialogs/colorselector.h
 	src/dialogs/ldrawpathdialog.h
 	src/dialogs/newpartdialog.h
@@ -207,5 +201,14 @@
 	)
 endif()
 
+add_custom_target (config_collection ALL
+	COMMAND python
+		"${CMAKE_SOURCE_DIR}/tools/configcollector.py"
+		--header ${CMAKE_BINARY_DIR}/configurationvaluebag.h
+		--source ${CMAKE_BINARY_DIR}/configurationvaluebag.cpp
+		--sourcedir ${CMAKE_SOURCE_DIR}/src
+		${LDFORGE_SOURCES}
+	WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+
 add_dependencies (ldforge revision_check config_collection)
 install (TARGETS ldforge RUNTIME DESTINATION bin)
--- a/codegen/CMakeLists.txt	Mon Aug 31 04:57:16 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-cmake_minimum_required (VERSION 2.4)
-add_executable (codegen codegen.cpp)
-
-# 
-# LDForge uses alternative operators. GCC and Clang use these by default but MSVC does not.
-# So we'll have to tell MSVC to use these alternative operators
-# 
-if (MSVC)
-	set_target_properties (codegen PROPERTIES COMPILE_FLAGS "/Za")
-endif()
--- a/codegen/codegen.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2015 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sstream>
-#include <fstream>
-#include <string>
-#include <cstring>
-#include <iostream>
-#include <vector>
-#include <algorithm>
-
-using std::string;
-using std::vector;
-using std::ifstream;
-using std::size_t;
-using std::strncmp;
-using std::getline;
-using std::cout;
-using std::endl;
-
-struct EntryType
-{
-	string name;
-	string type;
-	string defvalue;
-
-	inline bool operator< (EntryType const& other) const
-	{
-		return name < other.name;
-	}
-
-	inline bool operator== (EntryType const& other) const
-	{
-		return name == other.name and type == other.type;
-	}
-
-	inline bool operator!= (EntryType const& other) const
-	{
-		return not operator== (other);
-	}
-};
-
-char AdvancePointer (char const*& ptr)
-{
-	char a = *ptr++;
-
-	if (*ptr == '\0')
-		throw false;
-
-	return a;
-}
-
-void ReadConfigEntries (string const& filename, vector<EntryType>& entries, const char* macroname)
-{
-	ifstream is (filename.c_str());
-	string line;
-	size_t const macrolen = strlen (macroname);
-
-	while (getline (is, line))
-	{
-		try
-		{
-			if (strncmp (line.c_str(), macroname, macrolen) != 0)
-				continue;
-
-			char const* ptr = &line[macrolen];
-			EntryType entry;
-
-			// Skip to paren
-			while (*ptr != '(')
-				AdvancePointer (ptr);
-
-			// Skip whitespace
-			while (isspace (*ptr))
-				AdvancePointer (ptr);
-
-			// Skip paren
-			AdvancePointer (ptr);
-
-			// Read type
-			while (*ptr != ',')
-				entry.type += AdvancePointer (ptr);
-
-			// Skip comma and whitespace
-			for (AdvancePointer (ptr); isspace (*ptr); AdvancePointer (ptr))
-				;
-
-			// Read name
-			while (*ptr != ',')
-				entry.name += AdvancePointer (ptr);
-
-			// Skip comma and whitespace
-			for (AdvancePointer (ptr); isspace (*ptr); AdvancePointer (ptr))
-				;
-
-			// Read default
-			while (*ptr != ')')
-				entry.defvalue += AdvancePointer (ptr);
-
-			entries.push_back (entry);
-		}
-		catch (bool) {}
-	}
-}
-
-bool CheckEquality (vector<EntryType> a, vector<EntryType> b)
-{
-	if (a.size() != b.size())
-		return false;
-
-	std::sort (a.begin(), a.end());
-	std::sort (b.begin(), b.end());
-
-	for (size_t i = 0; i < a.size(); ++i)
-	{
-		if (a[i] != b[i])
-			return false;
-	}
-
-	return true;
-}
-
-int main (int argc, char* argv[])
-{
-	vector<EntryType> entries;
-	vector<EntryType> oldentries;
-	ReadConfigEntries (argv[argc - 1], oldentries, "CODEGEN_CACHE");
-
-	for (int arg = 1; arg < argc - 1; ++arg)
-		ReadConfigEntries (argv[arg], entries, "CFGENTRY");
-
-	if (CheckEquality (entries, oldentries))
-	{
-		cout << "Configuration options unchanged" << endl;
-		return 0;
-	}
-
-	std::ofstream os (argv[argc - 1]);
-	os << "#pragma once" << endl;
-	os << "#define CODEGEN_CACHE(A,B,C)" << endl;
-
-	for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it)
-	{
-		os << "CODEGEN_CACHE (" << it->type << ", " << it->name << ", " <<
-			  it->defvalue << ")" << endl;
-	}
-
-	os << endl;
-	for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it)
-		os << "EXTERN_CFGENTRY (" << it->type << ", " << it->name << ")" << endl;
-
-	os << endl;
-	os << "static void InitConfigurationEntry (AbstractConfigEntry* entry);" << endl;
-	os << "static void SetupConfigurationLists()" << endl;
-	os << "{" << endl;
-
-	for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it)
-	{
-		os << "\tInitConfigurationEntry (new " << it->type << "ConfigEntry (&cfg::" <<
-			  it->name << ", \"" << it->name << "\", " << it->defvalue << "));" << endl;
-	}
-
-	os << "}" << endl;
-	cout << "Wrote configuration options list to " << argv[argc - 1] << "." << endl;
-	return 0;
-}
--- a/src/addObjectDialog.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/addObjectDialog.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -254,7 +254,7 @@
 // =============================================================================
 void AddObjectDialog::slot_colorButtonClicked()
 {
-	ColorSelector::selectColor (m_color, m_color, this);
+	ColorSelector::selectColor (this, m_color, m_color);
 	setButtonBackground (pb_color, m_color);
 }
 
--- a/src/configDialog.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/configDialog.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -29,10 +29,10 @@
 #include <QDoubleSpinBox>
 #include <QLineEdit>
 #include <QCheckBox>
+#include <QSettings>
 #include "main.h"
 #include "configDialog.h"
 #include "ldDocument.h"
-#include "configuration.h"
 #include "miscallenous.h"
 #include "colors.h"
 #include "dialogs/colorselector.h"
@@ -45,19 +45,19 @@
 #endif
 	"All files (*.*)(*.*)";
 
-//
-//
 ConfigDialog::ConfigDialog (QWidget* parent, ConfigDialog::Tab defaulttab, Qt::WindowFlags f) :
 	QDialog (parent, f),
-	HierarchyElement (parent)
+	HierarchyElement (parent),
+	m_settings (m_window->makeSettings (this))
 {
 	ui = new Ui_ConfigUI;
 	ui->setupUi (this);
 
 	// Set defaults
-	applyToWidgetOptions ([&](QWidget* wdg, AbstractConfigEntry* conf)
+	applyToWidgetOptions (
+	[&](QWidget* widget, QString confname)
 	{
-		QVariant value (conf->toVariant());
+		QVariant value = m_settings->value (confname, m_config->defaultValueByName (confname));
 		QLineEdit* le;
 		QSpinBox* spinbox;
 		QDoubleSpinBox* doublespinbox;
@@ -65,34 +65,34 @@
 		QCheckBox* checkbox;
 		QPushButton* button;
 
-		if ((le = qobject_cast<QLineEdit*> (wdg)) != null)
+		if ((le = qobject_cast<QLineEdit*> (widget)) != null)
 		{
 			le->setText (value.toString());
 		}
-		else if ((spinbox = qobject_cast<QSpinBox*> (wdg)) != null)
+		else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
 		{
 			spinbox->setValue (value.toInt());
 		}
-		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (wdg)) != null)
+		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
 		{
 			doublespinbox->setValue (value.toDouble());
 		}
-		else if ((slider = qobject_cast<QSlider*> (wdg)) != null)
+		else if ((slider = qobject_cast<QSlider*> (widget)) != null)
 		{
 			slider->setValue (value.toInt());
 		}
-		else if ((checkbox = qobject_cast<QCheckBox*> (wdg)) != null)
+		else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
 		{
 			checkbox->setChecked (value.toBool());
 		}
-		else if ((button = qobject_cast<QPushButton*> (wdg)) != null)
+		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
 		{
 			setButtonBackground (button, value.toString());
 			connect (button, SIGNAL (clicked()), this, SLOT (setButtonColor()));
 		}
 		else
 		{
-			print ("Unknown widget of type %1\n", wdg->metaObject()->className());
+			print ("Unknown widget of type %1\n", widget->metaObject()->className());
 		}
 	});
 
@@ -124,15 +124,11 @@
 	connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), this, SLOT (selectPage (int)));
 }
 
-//
-//
 ConfigDialog::~ConfigDialog()
 {
 	delete ui;
 }
 
-//
-//
 void ConfigDialog::selectPage (int row)
 {
 	ui->m_pagelist->setCurrentRow (row);
@@ -177,7 +173,7 @@
 		QPushButton* setPathButton = new QPushButton;
 
 		icon->setPixmap (GetIcon (name.toLower()));
-		input->setText (*info.path);
+		input->setText (m_window->externalPrograms()->getPathSetting (program));
 		setPathButton->setIcon (GetIcon ("folder"));
 		widgets.input = input;
 		widgets.setPathButton = setPathButton;
@@ -196,14 +192,12 @@
 			pathsLayout->addWidget (wineBox, row, 4);
 		}
 #endif
-
 		++row;
 	}
-
 	ui->extProgs->setLayout (pathsLayout);
 }
 
-void ConfigDialog::applyToWidgetOptions (std::function<void (QWidget*, AbstractConfigEntry*)> func)
+void ConfigDialog::applyToWidgetOptions (std::function<void (QWidget*, QString)> func)
 {
 	// Apply configuration
 	for (QWidget* widget : findChildren<QWidget*>())
@@ -211,16 +205,12 @@
 		if (not widget->objectName().startsWith ("config"))
 			continue;
 
-		QString confname (widget->objectName().mid (strlen ("config")));
-		AbstractConfigEntry* conf (m_config->findByName (confname));
+		QString optionname (widget->objectName().mid (strlen ("config")));
 
-		if (conf == null)
-		{
-			print ("Couldn't find configuration entry named %1", confname);
-			continue;
-		}
-
-		func (widget, conf);
+		if (m_settings->contains (optionname))
+			func (widget, optionname);
+		else
+			print ("Couldn't find configuration entry named %1", optionname);
 	}
 }
 
@@ -229,9 +219,9 @@
 //
 void ConfigDialog::applySettings()
 {
-	applyToWidgetOptions ([&](QWidget* widget, AbstractConfigEntry* conf)
+	applyToWidgetOptions ([&](QWidget* widget, QString confname)
 	{
-		QVariant value (conf->toVariant());
+		QVariant value;
 		QLineEdit* le;
 		QSpinBox* spinbox;
 		QDoubleSpinBox* doublespinbox;
@@ -252,14 +242,17 @@
 		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
 			value = m_buttonColors[button];
 		else
+		{
 			print ("Unknown widget of type %1\n", widget->metaObject()->className());
+			return;
+		}
 
-		conf->loadFromVariant (value);
+		m_settings->setValue (confname, value);
 	});
 
 	// Rebuild the quick color toolbar
 	m_window->setQuickColors (quickColors);
-	m_config->quickColorToolbar = quickColorString();
+	m_config->setQuickColorToolbar (quickColorString());
 
 	// Ext program settings
 	for (int i = 0; i < NumExternalPrograms; ++i)
@@ -270,7 +263,7 @@
 		toolset->getPathSetting (program) = widgets.input->text();
 
 		if (widgets.wineBox)
-			toolset->getWineSetting (program) = widgets.wineBox->isChecked();
+			toolset->setWineSetting (program, widgets.wineBox->isChecked());
 	}
 
 	// Apply shortcuts
@@ -280,7 +273,7 @@
 		item->action()->setShortcut (item->sequence());
 	}
 
-	Config::Save();
+	m_window->syncSettings();
 	LDDocument::current()->reloadAllSubfiles();
 	LoadLogoStuds();
 
@@ -384,7 +377,7 @@
 	LDColor defaultValue = entry ? entry->color() : LDColor::nullColor();
 	LDColor value;
 
-	if (not ColorSelector::selectColor (value, defaultValue, this))
+	if (not ColorSelector::selectColor (this, value, defaultValue))
 		return;
 
 	if (entry != null)
--- a/src/configDialog.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/configDialog.h	Mon Aug 31 20:50:12 2015 +0300
@@ -71,6 +71,7 @@
 	QList<QListWidgetItem*> quickColorItems;
 	QMap<QPushButton*, QColor> m_buttonColors;
 	ExternalProgramWidgets m_externalProgramWidgets[NumExternalPrograms];
+	QSettings* m_settings;
 
 	void applySettings();
 	void addShortcut (QAction* act);
@@ -82,7 +83,7 @@
 	QListWidgetItem* getSelectedQuickColor();
 	QList<ShortcutListItem*> getShortcutSelection();
 	void initExtProgs();
-	void applyToWidgetOptions (std::function<void (QWidget*, AbstractConfigEntry*)> func);
+	void applyToWidgetOptions (std::function<void (QWidget*, QString)> func);
 
 private slots:
 	void setButtonColor();
--- a/src/configuration.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2015 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *  =====================================================================
- *
- *  config.cxx: Configuration management. I don't like how unsafe QSettings
- *  is so this implements a type-safer and identifer-safer wrapping system of
- *  configuration variables. QSettings is used underlyingly, this is a matter
- *  of interface.
- */
-
-#include <errno.h>
-#include <QDir>
-#include <QTextStream>
-#include <QSettings>
-#include <QApplication>
-#include "main.h"
-#include "configuration.h"
-#include "miscallenous.h"
-#include "mainwindow.h"
-#include "ldDocument.h"
-#include "glRenderer.h"
-#include "configuration.inc"
-
-#ifdef _WIN32
-# define EXTENSION ".ini"
-#else
-# define EXTENSION ".cfg"
-#endif // _WIN32
-
-#define MAX_CONFIG 512
-
-static QMap<QString, AbstractConfigEntry*>	EntriesByName;
-static QList<AbstractConfigEntry*>			ConfigurationEntries;
-
-AbstractConfigEntry::AbstractConfigEntry (QString name) :
-	m_name (name) {}
-
-void Config::Initialize()
-{
-	SetupConfigurationLists();
-	print ("Configuration initialized with %1 entries\n", ConfigurationEntries.size());
-}
-
-static void InitConfigurationEntry (AbstractConfigEntry* entry)
-{
-	ConfigurationEntries << entry;
-	EntriesByName[entry->name()] = entry;
-}
-
-//
-// Load the configuration from file
-//
-bool Config::Load()
-{
-	QSettings* settings = SettingsObject();
-	print ("Loading configuration file from %1\n", settings->fileName());
-
-	for (AbstractConfigEntry* cfg : ConfigurationEntries)
-	{
-		if (cfg == null)
-			break;
-
-		QVariant val = settings->value (cfg->name(), cfg->getDefaultAsVariant());
-		cfg->loadFromVariant (val);
-	}
-
-	if (g_win != null)
-		g_win->loadShortcuts (settings);
-
-	delete settings;
-	return true;
-}
-
-//
-// Save the configuration to disk
-//
-bool Config::Save()
-{
-	QSettings* settings = SettingsObject();
-
-	for (AbstractConfigEntry* cfg : ConfigurationEntries)
-	{
-		if (not cfg->isDefault())
-			settings->setValue (cfg->name(), cfg->toVariant());
-		else
-			settings->remove (cfg->name());
-	}
-
-	if (g_win != null)
-		g_win->saveShortcuts (settings);
-
-	settings->sync();
-	print ("Configuration saved to %1.\n", settings->fileName());
-	delete settings;
-	return true;
-}
-
-//
-// Reset configuration to defaults.
-//
-void Config::ResetToDefaults()
-{
-	for (AbstractConfigEntry* cfg : ConfigurationEntries)
-		cfg->resetValue();
-}
-
-//
-// Where is the configuration file located at?
-//
-QString Config::FilePath (QString file)
-{
-	return Config::DirectoryPath() + DIRSLASH + file;
-}
-
-//
-// Directory of the configuration file.
-//
-QString Config::DirectoryPath()
-{
-	QSettings* settings = SettingsObject();
-	QString result = Dirname (settings->fileName());
-	delete settings;
-	return result;
-}
-
-//
-// Accessor to the settings object
-//
-QSettings* Config::SettingsObject()
-{
-	QString path = qApp->applicationDirPath() + "/" UNIXNAME EXTENSION;
-	return new QSettings (path, QSettings::IniFormat);
-}
-
-//
-// Accessor to entry list
-//
-QList<AbstractConfigEntry*> const& Config::AllConfigEntries()
-{
-	return ConfigurationEntries;
-}
-
-AbstractConfigEntry* Config::FindByName (QString const& name)
-{
-	auto it = EntriesByName.find (name);
-	return (it != EntriesByName.end()) ? *it : null;
-}
-
-template<typename T>
-static T* GetConfigByName (QString name, AbstractConfigEntry::Type type)
-{
-	auto it = EntriesByName.find (name);
-
-	if (it == EntriesByName.end())
-		return null;
-
-	AbstractConfigEntry* cfg = it.value();
-
-	if (cfg->getType() != type)
-	{
-		fprint (stderr, "type of %1 is %2, not %3\n", name, cfg->getType(), type);
-		abort();
-	}
-
-	return reinterpret_cast<T*> (cfg);
-}
-
-#undef IMPLEMENT_CONFIG
-
-#define IMPLEMENT_CONFIG(NAME)												\
-	NAME##ConfigEntry* NAME##ConfigEntry::getByName (QString name)			\
-	{																		\
-		return GetConfigByName<NAME##ConfigEntry> (name, E##NAME##Type);	\
-	}
-
-IMPLEMENT_CONFIG (Int)
-IMPLEMENT_CONFIG (String)
-IMPLEMENT_CONFIG (Bool)
-IMPLEMENT_CONFIG (Float)
-IMPLEMENT_CONFIG (List)
-IMPLEMENT_CONFIG (KeySequence)
-IMPLEMENT_CONFIG (Vertex)
-
-void IntConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toInt();
-}
-
-void StringConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toString();
-}
-
-void BoolConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toBool();
-}
-
-void ListConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toList();
-}
-
-void KeySequenceConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toString();
-}
-
-void FloatConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.toDouble();
-}
-
-void VertexConfigEntry::loadFromVariant (const QVariant& val)
-{
-	*m_valueptr = val.value<Vertex>();
-}
--- a/src/configuration.h	Mon Aug 31 04:57:16 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2015 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-#include <QString>
-#include <QVariant>
-#include <QKeySequence>
-#include "macros.h"
-#include "basics.h"
-
-class QSettings;
-class AbstractConfigEntry;
-
-namespace Config
-{
-	void Initialize();
-	bool Load();
-	bool Save();
-	void ResetToDefaults();
-	QString DirectoryPath();
-	QString FilePath (QString file);
-	QSettings* SettingsObject();
-	QList<AbstractConfigEntry*> const& AllConfigEntries();
-	AbstractConfigEntry* FindByName (QString const& name);
-}
-
-class AbstractConfigEntry
-{
-	PROPERTY (private, QString, name, setName, STOCK_WRITE)
-
-public:
-	enum Type
-	{
-		EIntType,
-		EStringType,
-		EFloatType,
-		EBoolType,
-		EKeySequenceType,
-		EListType,
-		EVertexType,
-	};
-
-	using IntType			= int;
-	using StringType		= QString;
-	using FloatType			= float;
-	using BoolType			= bool;
-	using KeySequenceType	= QKeySequence;
-	using ListType			= QList<QVariant>;
-	using VertexType		= Vertex;
-
-	AbstractConfigEntry (QString name);
-
-	virtual QVariant	getDefaultAsVariant() const = 0;
-	virtual Type		getType() const = 0;
-	virtual bool		isDefault() const = 0;
-	virtual void		loadFromVariant (const QVariant& val) = 0;
-	virtual void		resetValue() = 0;
-	virtual QVariant	toVariant() const = 0;
-};
-
-#define IMPLEMENT_CONFIG(NAME)														\
-public:																				\
-	using ValueType = AbstractConfigEntry::NAME##Type;								\
-																					\
-	NAME##ConfigEntry (ValueType* valueptr, QString name, ValueType def) :			\
-		AbstractConfigEntry (name),													\
-		m_valueptr (valueptr),														\
-		m_default (def)																\
-	{																				\
-		*m_valueptr = def;															\
-	}																				\
-																					\
-	inline ValueType getValue() const												\
-	{																				\
-		return *m_valueptr;															\
-	}																				\
-																					\
-	inline void setValue (ValueType val)											\
-	{																				\
-		*m_valueptr = val;															\
-	}																				\
-																					\
-	virtual AbstractConfigEntry::Type getType() const								\
-	{																				\
-		return AbstractConfigEntry::E##NAME##Type;									\
-	}																				\
-																					\
-	virtual void resetValue()														\
-	{																				\
-		*m_valueptr = m_default;													\
-	}																				\
-																					\
-	virtual const ValueType& getDefault() const										\
-	{																				\
-		return m_default;															\
-	}																				\
-																					\
-	virtual bool isDefault() const													\
-	{																				\
-		return *m_valueptr == m_default;											\
-	}																				\
-																					\
-	virtual void loadFromVariant (const QVariant& val);								\
-																					\
-	virtual QVariant toVariant() const												\
-	{																				\
-		return QVariant::fromValue<ValueType> (*m_valueptr);						\
-	}																				\
-																					\
-	virtual QVariant getDefaultAsVariant() const									\
-	{																				\
-		return QVariant::fromValue<ValueType> (m_default);							\
-	}																				\
-																					\
-	static NAME##ConfigEntry* getByName (QString name);								\
-																					\
-private:																			\
-	ValueType*	m_valueptr;															\
-	ValueType	m_default;
-
-class IntConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (Int)
-};
-
-class StringConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (String)
-};
-
-class FloatConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (Float)
-};
-
-class BoolConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (Bool)
-};
-
-class KeySequenceConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (KeySequence)
-};
-
-class ListConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (List)
-};
-
-class VertexConfigEntry : public AbstractConfigEntry
-{
-	IMPLEMENT_CONFIG (Vertex)
-};
--- a/src/dialogs/colorselector.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/dialogs/colorselector.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -24,7 +24,6 @@
 #include "../main.h"
 #include "../mainwindow.h"
 #include "../colors.h"
-#include "../configuration.h"
 #include "../miscallenous.h"
 #include "colorselector.h"
 #include "ui_colorselector.h"
@@ -55,8 +54,8 @@
 
 			if (ldcolor == MainColor)
 			{
-				color = QColor (m_config->mainColor);
-				color.setAlphaF (m_config->mainColorAlpha);
+				color = QColor (m_config->mainColor());
+				color.setAlphaF (m_config->mainColorAlpha());
 			}
 
 			QString color2name (Luma (color) < 80 ? "white" : "black");
--- a/src/dialogs/ldrawpathdialog.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/dialogs/ldrawpathdialog.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -44,7 +44,7 @@
 	connect (ui.path, SIGNAL (textChanged (QString)), this, SIGNAL (pathChanged (QString)));
 	connect (ui.searchButton, SIGNAL (clicked()), this, SLOT (searchButtonClicked()));
 	connect (ui.buttonBox, SIGNAL (rejected()), this, validDefault ? SLOT (reject()) : SLOT (slot_exit()));
-	connect (ui.buttonBox, SIGNAL (accepted()), this, SLOT (slot_accept()));
+	connect (ui.buttonBox, SIGNAL (accepted()), this, SLOT (accept()));
 	setPath (defaultPath);
 }
 
@@ -98,10 +98,4 @@
 			.arg (ok ? "#700" : "#270")
 			.arg (statusText));
 	}
-}
-
-void LDrawPathDialog::slot_accept()
-{
-	Config::Save();
-	accept();
 }
\ No newline at end of file
--- a/src/dialogs/ldrawpathdialog.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/dialogs/ldrawpathdialog.h	Mon Aug 31 20:50:12 2015 +0300
@@ -43,5 +43,4 @@
 private slots:
 	void searchButtonClicked();
 	void slot_exit();
-	void slot_accept();
 };
--- a/src/dialogs/newpartdialog.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/dialogs/newpartdialog.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -31,13 +31,13 @@
 {
 	ui.setupUi (this);
 
-	QString authortext = m_config->defaultName;
+	QString authortext = m_config->defaultName();
 
-	if (not m_config->defaultUser.isEmpty())
-		authortext.append (format (" [%1]", m_config->defaultUser));
+	if (not m_config->defaultUser().isEmpty())
+		authortext.append (format (" [%1]", m_config->defaultUser()));
 
 	ui.author->setText (authortext);
-	ui.useCaLicense->setChecked (m_config->useCaLicense);
+	ui.useCaLicense->setChecked (m_config->useCaLicense());
 }
 
 BFCStatement NewPartDialog::getWinding() const
--- a/src/editmodes/abstractEditMode.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/editmodes/abstractEditMode.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -183,7 +183,7 @@
 void AbstractDrawMode::drawLength (QPainter &painter, const Vertex &v0, const Vertex &v1,
 	const QPointF& v0p, const QPointF& v1p) const
 {
-	if (not m_config->drawLineLengths)
+	if (not m_config->drawLineLengths())
 		return;
 
 	const QString label = QString::number ((v1 - v0).length());
@@ -230,7 +230,7 @@
 			if (withlengths)
 				drawLength (painter, poly3d[i], poly3d[j], poly[i], poly[j]);
 
-			if (withangles and m_config->drawAngles)
+			if (withangles and m_config->drawAngles())
 			{
 				QLineF l0 (poly[h], poly[i]),
 					l1 (poly[i], poly[j]);
--- a/src/glCompiler.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/glCompiler.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -78,7 +78,7 @@
 // =============================================================================
 //
 GLCompiler::GLCompiler (GLRenderer* renderer) :
-	HierarchyElement (parent),
+	HierarchyElement (renderer),
 	m_renderer (renderer)
 {
 	needMerge();
@@ -161,13 +161,13 @@
 			if (poly.color == MainColor)
 			{
 				if (topobj->color() == MainColor)
-					qcol = GLRenderer::getMainColor();
+					qcol = m_renderer->getMainColor();
 				else
 					qcol = topobj->color().faceColor();
 			}
 			else if (poly.color == EdgeColor)
 			{
-				qcol = Luma (QColor (m_config->backgroundColor)) > 40 ? Qt::black : Qt::white;
+				qcol = Luma (QColor (m_config->backgroundColor())) > 40 ? Qt::black : Qt::white;
 			}
 			else
 			{
@@ -184,7 +184,7 @@
 		// The color was unknown. Use main color to make the polygon at least
 		// not appear pitch-black.
 		if (poly.num != 2 and poly.num != 5)
-			qcol = GLRenderer::getMainColor();
+			qcol = m_renderer->getMainColor();
 		else
 			qcol = Qt::black;
 
@@ -207,7 +207,7 @@
 
 	if (blendAlpha != 0.0)
 	{
-		QColor selcolor (m_config->selectColorBlend);
+		QColor selcolor (m_config->selectColorBlend());
 		double denom = blendAlpha + 1.0;
 		qcol.setRed ((qcol.red() + (selcolor.red() * blendAlpha)) / denom);
 		qcol.setGreen ((qcol.green() + (selcolor.green() * blendAlpha)) / denom);
--- a/src/glRenderer.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/glRenderer.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -29,7 +29,6 @@
 #include <QTimer>
 #include <GL/glu.h>
 #include "main.h"
-#include "configuration.h"
 #include "ldDocument.h"
 #include "glRenderer.h"
 #include "colors.h"
@@ -104,7 +103,7 @@
 	HierarchyElement (parent)
 {
 	m_isPicking = false;
-	m_camera = (ECamera) m_config->camera;
+	m_camera = (ECamera) m_config->camera();
 	m_drawToolTip = false;
 	m_editmode = AbstractEditMode::createByType (this, EditModeType::Select);
 	m_panning = false;
@@ -195,7 +194,7 @@
 	glShadeModel (GL_SMOOTH);
 	glEnable (GL_MULTISAMPLE);
 
-	if (m_config->antiAliasedLines)
+	if (m_config->antiAliasedLines())
 	{
 		glEnable (GL_LINE_SMOOTH);
 		glEnable (GL_POLYGON_SMOOTH);
@@ -249,7 +248,7 @@
 	initializeOpenGLFunctions();
 #endif
 	setBackground();
-	glLineWidth (m_config->lineThickness);
+	glLineWidth (m_config->lineThickness());
 	glLineStipple (1, 0x6666);
 	setAutoFillBackground (false);
 	setMouseTracking (true);
@@ -296,12 +295,12 @@
 //
 QColor GLRenderer::getMainColor()
 {
-	QColor col (m_config->mainColor);
+	QColor col (m_config->mainColor());
 
 	if (not col.isValid())
 		return QColor (0, 0, 0);
 
-	col.setAlpha (m_config->mainColorAlpha * 255.f);
+	col.setAlpha (m_config->mainColorAlpha() * 255.f);
 	return col;
 }
 
@@ -315,7 +314,7 @@
 		return;
 	}
 
-	QColor col (m_config->backgroundColor);
+	QColor col (m_config->backgroundColor());
 
 	if (not col.isValid())
 		return;
@@ -377,7 +376,7 @@
 		zoomAllToFit();
 	}
 
-	if (m_config->drawWireframe and not isPicking())
+	if (m_config->drawWireframe() and not isPicking())
 		glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
 
 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -431,7 +430,7 @@
 	}
 	else
 	{
-		if (m_config->bfcRedGreenView)
+		if (m_config->bfcRedGreenView())
 		{
 			glEnable (GL_CULL_FACE);
 			glCullFace (GL_BACK);
@@ -444,7 +443,7 @@
 		}
 		else
 		{
-			EVBOComplement colors = (m_config->randomColors) ? VBOCM_RandomColors : VBOCM_NormalColors;
+			EVBOComplement colors = (m_config->randomColors()) ? VBOCM_RandomColors : VBOCM_NormalColors;
 			drawVBOs (VBOSF_Triangles, colors, GL_TRIANGLES);
 			drawVBOs (VBOSF_Quads, colors, GL_QUADS);
 		}
@@ -454,7 +453,7 @@
 		drawVBOs (VBOSF_CondLines, VBOCM_NormalColors, GL_LINES);
 		glDisable (GL_LINE_STIPPLE);
 
-		if (m_config->drawAxes)
+		if (m_config->drawAxes())
 		{
 			glBindBuffer (GL_ARRAY_BUFFER, m_axesVBO);
 			glVertexPointer (3, GL_FLOAT, 0, NULL);
@@ -480,9 +479,9 @@
 void GLRenderer::drawVBOs (EVBOSurface surface, EVBOComplement colors, GLenum type)
 {
 	// Filter this through some configuration options
-	if ((isOneOf (surface, VBOSF_Quads, VBOSF_Triangles) and m_config->drawSurfaces == false) or
-		(surface == VBOSF_Lines and m_config->drawEdgeLines == false) or
-		(surface == VBOSF_CondLines and m_config->drawConditionalLines == false))
+	if ((isOneOf (surface, VBOSF_Quads, VBOSF_Triangles) and m_config->drawSurfaces() == false) or
+		(surface == VBOSF_Lines and m_config->drawEdgeLines() == false) or
+		(surface == VBOSF_CondLines and m_config->drawConditionalLines() == false))
 	{
 		return;
 	}
@@ -895,7 +894,7 @@
 		return;
 
 	m_camera = cam;
-	m_config->camera = (int) cam;
+	m_config->setCamera ((int) cam);
 	m_window->updateEditModeActions();
 }
 
@@ -1077,14 +1076,14 @@
 		glDisable (GL_DITHER);
 
 		// Use particularly thick lines while picking ease up selecting lines.
-		glLineWidth (qMax<double> (m_config->lineThickness, 6.5));
+		glLineWidth (qMax<double> (m_config->lineThickness(), 6.5));
 	}
 	else
 	{
 		glEnable (GL_DITHER);
 
 		// Restore line thickness
-		glLineWidth (m_config->lineThickness);
+		glLineWidth (m_config->lineThickness());
 	}
 }
 
@@ -1529,14 +1528,14 @@
 //
 void GLRenderer::highlightCursorObject()
 {
-	if (not m_config->highlightObjectBelowCursor and objectAtCursor() == null)
+	if (not m_config->highlightObjectBelowCursor() and objectAtCursor() == null)
 		return;
 
 	LDObject* newObject = nullptr;
 	LDObject* oldObject = objectAtCursor();
 	qint32 newIndex;
 
-	if (isCameraMoving() or not m_config->highlightObjectBelowCursor)
+	if (isCameraMoving() or not m_config->highlightObjectBelowCursor())
 	{
 		newIndex = 0;
 	}
--- a/src/glRenderer.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/glRenderer.h	Mon Aug 31 20:50:12 2015 +0300
@@ -195,7 +195,7 @@
 	void					updateOverlayObjects();
 	void					zoomNotch (bool inward);
 
-	static QColor			getMainColor();
+	QColor					getMainColor();
 
 protected:
 	void					contextMenuEvent (QContextMenuEvent* ev);
--- a/src/ldDocument.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/ldDocument.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -22,7 +22,6 @@
 #include <QTime>
 #include <QApplication>
 #include "main.h"
-#include "configuration.h"
 #include "ldDocument.h"
 #include "miscallenous.h"
 #include "mainwindow.h"
@@ -223,7 +222,7 @@
 		return relpath;
 
 	// Try with just the LDraw path first
-	fullPath = format ("%1" DIRSLASH "%2", g_win->configBag()->lDrawPath, relpath);
+	fullPath = format ("%1" DIRSLASH "%2", g_win->configBag()->lDrawPath(), relpath);
 
 	if (QFile::exists (fullPath))
 		return fullPath;
@@ -232,7 +231,7 @@
 	{
 		// Look in sub-directories: parts and p. Also look in net_downloadpath, since that's
 		// where we download parts from the PT to.
-		QStringList dirs = { g_win->configBag()->lDrawPath, g_win->configBag()->downloadFilePath };
+		QStringList dirs = { g_win->configBag()->lDrawPath(), g_win->configBag()->downloadFilePath() };
 		for (const QString& topdir : dirs)
 		{
 			for (const QString& subdir : QStringList ({ "parts", "p" }))
@@ -572,7 +571,7 @@
 //
 void AddRecentFile (QString path)
 {
-	QStringList& recentFiles = g_win->configBag()->recentFiles;
+	QStringList recentFiles = g_win->configBag()->recentFiles();
 	int idx = recentFiles.indexOf (path);
 
 	// If this file already is in the list, pop it out.
@@ -590,7 +589,8 @@
 
 	// Add the file
 	recentFiles << path;
-	Config::Save();
+	g_win->configBag()->setRecentFiles (recentFiles);
+	g_win->syncSettings();
 	g_win->updateRecentFilesMenu();
 }
 
@@ -669,7 +669,7 @@
 		unknowns << static_cast<LDError*> (obj)->fileReferenced();
 	}
 
-	if (g_win->configBag()->tryDownloadMissingFiles and not unknowns.isEmpty())
+	if (g_win->configBag()->tryDownloadMissingFiles() and not unknowns.isEmpty())
 	{
 		PartDownloader dl;
 
@@ -1268,7 +1268,7 @@
 	// Possibly substitute with logoed studs:
 	// stud.dat -> stud-logo.dat
 	// stud2.dat -> stud-logo2.dat
-	if (g_win->configBag()->useLogoStuds and renderinline)
+	if (g_win->configBag()->useLogoStuds() and renderinline)
 	{
 		// Ensure logoed studs are loaded first
 		LoadLogoStuds();
--- a/src/ldObject.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/ldObject.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -859,7 +859,7 @@
 //
 QString PreferredLicenseText()
 {
-	return (g_win->configBag()->useCaLicense ? CALicenseText : "");
+	return g_win->configBag()->useCaLicense() ? CALicenseText : "";
 }
 
 // =============================================================================
--- a/src/ldpaths.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/ldpaths.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -12,7 +12,7 @@
 
 void LDPaths::checkPaths()
 {
-	QString& pathconfig = m_config->lDrawPath;
+	QString pathconfig = m_config->lDrawPath();
 
 	if (not configurePaths (pathconfig))
 	{
@@ -22,7 +22,7 @@
 		if (not m_dialog->exec())
 			Exit();
 		else
-			pathconfig = m_dialog->path();
+			m_config->setLDrawPath (m_dialog->path());
 	}
 }
 
--- a/src/main.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/main.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -25,12 +25,10 @@
 #include "mainwindow.h"
 #include "ldDocument.h"
 #include "miscallenous.h"
-#include "configuration.h"
 #include "colors.h"
 #include "basics.h"
 #include "primitives.h"
 #include "glRenderer.h"
-#include "configDialog.h"
 #include "dialogs.h"
 #include "crashCatcher.h"
 #include "ldpaths.h"
@@ -42,7 +40,7 @@
 const Vertex Origin (0.0f, 0.0f, 0.0f);
 const Matrix IdentityMatrix ({1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f});
 
-ConfigOption (bool firstStart = true)
+ConfigOption (bool FirstStart = true)
 
 // =============================================================================
 //
@@ -52,19 +50,6 @@
 	app.setOrganizationName (APPNAME);
 	app.setApplicationName (APPNAME);
 	initCrashCatcher();
-	Config::Initialize();
-
-	// Load or create the configuration
-	if (not Config::Load())
-	{
-		print ("Creating configuration file...\n");
-
-		if (Config::Save())
-			print ("Configuration file successfully created.\n");
-		else
-			Critical ("Failed to create configuration file!\n");
-	}
-	
 	MainWindow* win = new MainWindow;
 	LDPaths* paths = new LDPaths (win);
 	paths->checkPaths();
@@ -74,15 +59,6 @@
 	newFile();
 	win->show();
 
-	// If this is the first start, get the user to configuration. Especially point
-	// them to the profile tab, it's the most important form to fill in.
-	if (win->configBag()->firstStart)
-	{
-		(new ConfigDialog (ConfigDialog::ProfileTab))->exec();
-		win->configBag()->firstStart = false;
-		Config::Save();
-	}
-
 	// Process the command line
 	for (int arg = 1; arg < argc; ++arg)
 		OpenMainModel (QString::fromLocal8Bit (argv[arg]));
--- a/src/main.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/main.h	Mon Aug 31 20:50:12 2015 +0300
@@ -29,7 +29,6 @@
 #include <QTextFormat>
 #include "macros.h"
 #include "version.h"
-#include "configuration.h"
 #include "format.h"
 #include "hierarchyelement.h"
 
--- a/src/mainwindow.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/mainwindow.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -40,14 +40,13 @@
 #include "glRenderer.h"
 #include "mainwindow.h"
 #include "ldDocument.h"
-#include "configuration.h"
 #include "miscallenous.h"
 #include "colors.h"
 #include "editHistory.h"
 #include "radioGroup.h"
 #include "addObjectDialog.h"
 #include "messageLog.h"
-#include "configuration.h"
+#include "configDialog.h"
 #include "ui_mainwindow.h"
 #include "primitives.h"
 #include "editmodes/abstractEditMode.h"
@@ -62,12 +61,14 @@
 ConfigOption (bool listImplicitFiles = false)
 ConfigOption (QStringList hiddenToolbars)
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 MainWindow::MainWindow (QWidget* parent, Qt::WindowFlags flags) :
 	QMainWindow (parent, flags),
+	m_configOptions (this),
 	ui (*new Ui_MainWindow),
-	m_externalPrograms (nullptr)
+	m_externalPrograms (nullptr),
+	m_settings (makeSettings (this))
 {
 	g_win = this;
 	ui.setupUi (this);
@@ -111,7 +112,7 @@
 	updateRecentFilesMenu();
 	updateColorToolbar();
 	updateTitle();
-	loadShortcuts (Config::SettingsObject());
+	loadShortcuts();
 	setMinimumSize (300, 200);
 	connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (slot_lastSecondCleanup()));
 	connect (ui.ringToolHiRes, SIGNAL (clicked (bool)), this, SLOT (ringToolHiResClicked (bool)));
@@ -133,8 +134,8 @@
 	{
 		const QMetaObject* meta = toolset->metaObject();
 
-		if (qobject_cast<ExtProgramToolset*> (meta))
-			m_externalPrograms = meta;
+		if (qobject_cast<ExtProgramToolset*> (toolset))
+			m_externalPrograms = static_cast<ExtProgramToolset*> (toolset);
 
 		for (int i = 0; i < meta->methodCount(); ++i)
 		{
@@ -156,13 +157,22 @@
 		}
 	}
 
-	for (QVariant const& toolbarname : m_configOptions.hiddenToolbars)
+	for (QVariant const& toolbarname : m_configOptions.hiddenToolbars())
 	{
 		QToolBar* toolbar = findChild<QToolBar*> (toolbarname.toString());
 
 		if (toolbar != null)
 			toolbar->hide();
 	}
+
+	// If this is the first start, get the user to configuration. Especially point
+	// them to the profile tab, it's the most important form to fill in.
+	if (m_configOptions.firstStart())
+	{
+		(new ConfigDialog (this, ConfigDialog::ProfileTab))->exec();
+		m_configOptions.setFirstStart (false);
+		syncSettings();
+	}
 }
 
 MainWindow::~MainWindow()
@@ -170,7 +180,7 @@
 	g_win = null;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_action()
 {
@@ -192,7 +202,7 @@
 	endAction();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::endAction()
 {
@@ -205,7 +215,7 @@
 	refresh();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_lastSecondCleanup()
 {
@@ -213,19 +223,19 @@
 	delete &ui;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateRecentFilesMenu()
 {
 	// First, clear any items in the recent files menu
-for (QAction * recent : m_recentFiles)
+	for (QAction* recent : m_recentFiles)
 		delete recent;
 
 	m_recentFiles.clear();
 
 	QAction* first = null;
 
-	for (const QVariant& it : m_configOptions.recentFiles)
+	for (const QVariant& it : m_configOptions.recentFiles())
 	{
 		QString file = it.toString();
 		QAction* recent = new QAction (GetIcon ("open-recent"), file, this);
@@ -237,13 +247,13 @@
 	}
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QList<LDQuickColor> LoadQuickColorList()
 {
 	QList<LDQuickColor> colors;
 
-	for (QString colorname : m_configOptions.quickColorToolbar.split (":"))
+	for (QString colorname : g_win->configBag()->quickColorToolbar().split (":"))
 	{
 		if (colorname == "|")
 			colors << LDQuickColor::getSeparator();
@@ -259,7 +269,7 @@
 	return colors;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateColorToolbar()
 {
@@ -292,17 +302,18 @@
 	updateGridToolBar();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateGridToolBar()
 {
 	// Ensure that the current grid - and only the current grid - is selected.
-	ui.actionGridCoarse->setChecked (m_configOptions.grid == Grid::Coarse);
-	ui.actionGridMedium->setChecked (m_configOptions.grid == Grid::Medium);
-	ui.actionGridFine->setChecked (m_configOptions.grid == Grid::Fine);
+	int grid = m_configOptions.grid();
+	ui.actionGridCoarse->setChecked (grid == Grid::Coarse);
+	ui.actionGridMedium->setChecked (grid == Grid::Medium);
+	ui.actionGridFine->setChecked (grid == Grid::Fine);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateTitle()
 {
@@ -338,7 +349,7 @@
 	setWindowTitle (title);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 int MainWindow::deleteSelection()
 {
@@ -355,7 +366,7 @@
 	return selCopy.size();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::buildObjList()
 {
@@ -465,7 +476,7 @@
 			item->setBackground (QColor ("#AA0000"));
 			item->setForeground (QColor ("#FFAA00"));
 		}
-		else if (m_configOptions.colorizeObjectsList
+		else if (m_configOptions.colorizeObjectsList()
 			and obj->isColored()
 			and obj->color().isValid()
 			and obj->color() != MainColor
@@ -484,7 +495,7 @@
 	scrollToSelection();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::scrollToSelection()
 {
@@ -495,7 +506,7 @@
 	ui.objectList->scrollToItem (obj->qObjListEntry);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_selectionChanged()
 {
@@ -534,7 +545,7 @@
 	R()->update();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_recentFile()
 {
@@ -542,7 +553,7 @@
 	OpenMainModel (qAct->text());
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_quickColor()
 {
@@ -574,7 +585,7 @@
 	refresh();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 int MainWindow::getInsertionPoint()
 {
@@ -586,7 +597,7 @@
 	return CurrentDocument()->getObjectCount();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::doFullRefresh()
 {
@@ -594,7 +605,7 @@
 	m_renderer->hardRefresh();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::refresh()
 {
@@ -602,7 +613,7 @@
 	m_renderer->update();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateSelection()
 {
@@ -645,7 +656,7 @@
 	g_isSelectionLocked = false;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 LDColor MainWindow::getSelectedColor()
 {
@@ -666,7 +677,7 @@
 	return result;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::closeEvent (QCloseEvent* ev)
 {
@@ -678,20 +689,21 @@
 	}
 
 	// Save the toolbar set
-	m_configOptions.hiddenToolbars.clear();
+	QStringList hiddenToolbars;
 
 	for (QToolBar* toolbar : findChildren<QToolBar*>())
 	{
 		if (toolbar->isHidden())
-			m_configOptions.hiddenToolbars << toolbar->objectName();
+			hiddenToolbars << toolbar->objectName();
 	}
 
 	// Save the configuration before leaving.
-	Config::Save();
+	m_configOptions.setHiddenToolbars (hiddenToolbars);
+	syncSettings();
 	ev->accept();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::spawnContextMenu (const QPoint pos)
 {
@@ -757,7 +769,7 @@
 	contextMenu->exec (pos);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::deleteByColor (LDColor color)
 {
@@ -775,7 +787,7 @@
 		obj->destroy();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateEditModeActions()
 {
@@ -788,7 +800,7 @@
 	ui.actionModeLinePath->setChecked (mode == EditModeType::LinePath);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::slot_editObject (QListWidgetItem* listitem)
 {
@@ -802,7 +814,7 @@
 	}
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 bool MainWindow::save (LDDocument* doc, bool saveAs)
 {
@@ -819,7 +831,7 @@
 			name = doc->name();
 
 		name.replace ("\\", "/");
-		path = QFileDialog::getSaveFileName (g_win, tr ("Save As"),
+		path = QFileDialog::getSaveFileName (this, tr ("Save As"),
 			name, tr ("LDraw files (*.dat *.ldr)"));
 
 		if (path.isEmpty())
@@ -844,7 +856,7 @@
 	QString message = format (tr ("Failed to save to %1: %2"), path, strerror (errno));
 
 	// Tell the user the save failed, and give the option for saving as with it.
-	QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win);
+	QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, this);
 
 	// Add a save-as button
 	QPushButton* saveAsBtn = new QPushButton (tr ("Save As"));
@@ -870,21 +882,21 @@
 	g_win->spawnContextMenu (ev->globalPos());
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QPixmap GetIcon (QString iconName)
 {
 	return (QPixmap (format (":/icons/%1.png", iconName)));
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 bool Confirm (const QString& message)
 {
 	return Confirm (MainWindow::tr ("Confirm"), message);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 bool Confirm (const QString& title, const QString& message)
 {
@@ -892,7 +904,7 @@
 		(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void Critical (const QString& message)
 {
@@ -900,7 +912,7 @@
 		(QMessageBox::Close), QMessageBox::Close);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QIcon MakeColorIcon (LDColor colinfo, const int size)
 {
@@ -912,8 +924,8 @@
 	if (colinfo == MainColor)
 	{
 		// Use the user preferences for main color here
-		col = g_win->configBag()->mainColor;
-		col.setAlphaF (g_win->configBag()->mainColorAlpha);
+		col = g_win->configBag()->mainColor();
+		col.setAlphaF (g_win->configBag()->mainColorAlpha());
 	}
 
 	// Paint the icon border
@@ -927,7 +939,7 @@
 	return QIcon (QPixmap::fromImage (img));
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MakeColorComboBox (QComboBox* box)
 {
@@ -958,7 +970,7 @@
 	}
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateDocumentList()
 {
@@ -978,7 +990,7 @@
 	m_updatingTabs = false;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateDocumentListItem (LDDocument* doc)
 {
@@ -1006,7 +1018,7 @@
 	m_updatingTabs = oldUpdatingTabs;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 // A file is selected from the list of files on the left of the screen. Find out
 // which file was picked and change to it.
@@ -1037,7 +1049,7 @@
 	LDDocument::setCurrent (file);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::refreshObjectList()
 {
@@ -1053,7 +1065,7 @@
 	buildObjList();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updateActions()
 {
@@ -1065,24 +1077,24 @@
 		ui.actionRedo->setEnabled (pos < (long) his->getSize() - 1);
 	}
 
-	ui.actionWireframe->setChecked (m_configOptions.drawWireframe);
-	ui.actionAxes->setChecked (m_configOptions.drawAxes);
-	ui.actionBfcView->setChecked (m_configOptions.bfcRedGreenView);
-	ui.actionRandomColors->setChecked (m_configOptions.randomColors);
-	ui.actionDrawAngles->setChecked (m_configOptions.drawAngles);
-	ui.actionDrawSurfaces->setChecked (m_configOptions.drawSurfaces);
-	ui.actionDrawEdgeLines->setChecked (m_configOptions.drawEdgeLines);
-	ui.actionDrawConditionalLines->setChecked (m_configOptions.drawConditionalLines);
+	ui.actionWireframe->setChecked (m_configOptions.drawWireframe());
+	ui.actionAxes->setChecked (m_configOptions.drawAxes());
+	ui.actionBfcView->setChecked (m_configOptions.bfcRedGreenView());
+	ui.actionRandomColors->setChecked (m_configOptions.randomColors());
+	ui.actionDrawAngles->setChecked (m_configOptions.drawAngles());
+	ui.actionDrawSurfaces->setChecked (m_configOptions.drawSurfaces());
+	ui.actionDrawEdgeLines->setChecked (m_configOptions.drawEdgeLines());
+	ui.actionDrawConditionalLines->setChecked (m_configOptions.drawConditionalLines());
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::updatePrimitives()
 {
 	PopulatePrimitives (ui.primitives);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::closeTab (int tabindex)
 {
@@ -1094,33 +1106,37 @@
 	doc->dismiss();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
-void MainWindow::loadShortcuts (QSettings const* settings)
+void MainWindow::loadShortcuts()
 {
 	for (QAction* act : findChildren<QAction*>())
 	{
-		QKeySequence seq = settings->value ("shortcut_" + act->objectName(), act->shortcut()).value<QKeySequence>();
+		QKeySequence seq = m_settings->value ("shortcut_" + act->objectName(), act->shortcut()).value<QKeySequence>();
 		act->setShortcut (seq);
 	}
+
+	m_settings->deleteLater();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
-void MainWindow::saveShortcuts (QSettings* settings)
+void MainWindow::saveShortcuts()
 {
 	applyToActions ([&](QAction* act)
 	{
 		QString const key = "shortcut_" + act->objectName();
 
 		if (g_defaultShortcuts[act] != act->shortcut())
-			settings->setValue (key, act->shortcut());
+			m_settings->setValue (key, act->shortcut());
 		else
-			settings->remove (key);
+			m_settings->remove (key);
 	});
+
+	m_settings->deleteLater();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::applyToActions (std::function<void(QAction*)> function)
 {
@@ -1131,35 +1147,35 @@
 	}
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QTreeWidget* MainWindow::getPrimitivesTree() const
 {
 	return ui.primitives;
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QKeySequence MainWindow::defaultShortcut (QAction* act) // [static]
 {
 	return g_defaultShortcuts[act];
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 bool MainWindow::ringToolHiRes() const
 {
 	return ui.ringToolHiRes->isChecked();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 int MainWindow::ringToolSegments() const
 {
 	return ui.ringToolSegments->value();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::ringToolHiResClicked (bool checked)
 {
@@ -1175,7 +1191,7 @@
 	}
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::circleToolSegmentsChanged()
 {
@@ -1185,36 +1201,29 @@
 	ui.ringToolSegmentsLabel->setText (format ("%1 / %2", numerator, denominator));
 }
 
-
-//
-// Where is the configuration file located at?
-//
-QString MainWindow::configFilePath (QString file)
-{
-	return Config::DirectoryPath() + DIRSLASH + file;
-}
-
-//
-// Directory of the configuration file.
-//
-QString Config::DirectoryPath()
-{
-	QSettings* settings = SettingsObject();
-	QString result = Dirname (settings->fileName());
-	delete settings;
-	return result;
-}
-
+// ---------------------------------------------------------------------------------------------------------------------
 //
 // Accessor to the settings object
 //
-QSettings* Config::SettingsObject()
+QSettings* MainWindow::makeSettings (QObject* parent)
 {
 	QString path = qApp->applicationDirPath() + "/" UNIXNAME ".ini";
-	return new QSettings (path, QSettings::IniFormat);
+	return new QSettings (path, QSettings::IniFormat, parent);
 }
 
-// =============================================================================
+void MainWindow::syncSettings()
+{
+	m_settings->sync();
+	m_settings->deleteLater();
+}
+
+QVariant MainWindow::getConfigValue (QString name)
+{
+	QVariant value = m_settings->value (name, m_configOptions.defaultValueByName (name));
+	return value;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
 //
 QImage GetImageFromScreencap (uchar* data, int w, int h)
 {
@@ -1222,26 +1231,28 @@
 	return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored();
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 LDQuickColor::LDQuickColor (LDColor color, QToolButton* toolButton) :
 	m_color (color),
 	m_toolButton (toolButton) {}
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 LDQuickColor LDQuickColor::getSeparator()
 {
 	return LDQuickColor (LDColor::nullColor(), null);
 }
 
-// =============================================================================
+// ---------------------------------------------------------------------------------------------------------------------
 //
 bool LDQuickColor::isSeparator() const
 {
 	return color() == LDColor::nullColor();
 }
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
 void PopulatePrimitives (QTreeWidget* tw, QString const& selectByDefault)
 {
 	tw->clear();
--- a/src/mainwindow.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/mainwindow.h	Mon Aug 31 20:50:12 2015 +0300
@@ -24,7 +24,6 @@
 #include <QRadioButton>
 #include <QTreeWidget>
 #include <QMetaMethod>
-#include "configuration.h"
 #include "ldObject.h"
 #include "colors.h"
 #include "configurationvaluebag.h"
@@ -157,19 +156,17 @@
 	void endAction();
 	QTreeWidget* getPrimitivesTree() const;
 	static QKeySequence defaultShortcut (QAction* act);
-	void loadShortcuts (QSettings const* settings);
-	void saveShortcuts (QSettings* settings);
+	void loadShortcuts();
+	void saveShortcuts();
 	void applyToActions (std::function<void(QAction*)> function);
 
 	bool ringToolHiRes() const;
 	int ringToolSegments() const;
-	ConfigurationValueBag* configBag() const { return m_configOptions; }
-
-	template<typename T>
-	auto& config (T key)
-	{
-		return m_configOptions.get (key);
-	}
+	ConfigurationValueBag* configBag() { return &m_configOptions; }
+	class QSettings* makeSettings (QObject* parent = nullptr);
+	void syncSettings();
+	QVariant getConfigValue (QString name);
+	class QSettings* getSettings() { return m_settings; }
 
 	class ExtProgramToolset* externalPrograms()
 	{
@@ -203,6 +200,7 @@
 	QVector<Toolset*>	m_toolsets;
 	QMap<QAction*, ToolInfo> m_toolmap;
 	class ExtProgramToolset* m_externalPrograms;
+	class QSettings* m_settings;
 
 private slots:
 	void slot_selectionChanged();
--- a/src/miscallenous.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/miscallenous.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -95,16 +95,32 @@
 ConfigOption (int RotationPointType = 0)
 ConfigOption (Vertex CustomRotationPoint = Origin)
 
-const GridData Grids[3] =
+float gridCoordinateSnap()
 {
-	{ "Coarse", cfg::GRID_COARSE_COORDINATE_SNAP, cfg::GRID_COARSE_ANGLE_SNAP },
-	{ "Medium", cfg::GRID_MEDIUM_COORDINATE_SNAP, cfg::GRID_MEDIUM_ANGLE_SNAP },
-	{ "Fine", cfg::GRID_FINE_COORDINATE_SNAP, cfg::GRID_FINE_ANGLE_SNAP },
-};
+	ConfigurationValueBag* config = g_win->configBag();
+
+	switch (config->grid())
+	{
+	case Grid::Coarse: return config->gridCoarseCoordinateSnap();
+	case Grid::Medium: return config->gridMediumCoordinateSnap();
+	case Grid::Fine: return config->gridFineCoordinateSnap();
+	}
+
+	return 1.0f;
+}
 
-const GridData& CurrentGrid()
+float gridAngleSnap()
 {
-	return Grids[g_win->configBag()->grid];
+	ConfigurationValueBag* config = g_win->configBag();
+
+	switch (config->grid())
+	{
+	case Grid::Coarse: return config->gridCoarseAngleSnap();
+	case Grid::Medium: return config->gridMediumAngleSnap();
+	case Grid::Fine: return config->gridFineAngleSnap();
+	}
+
+	return 45.0f;
 }
 
 // =============================================================================
@@ -113,7 +129,7 @@
 //
 double Grid::Snap (double value, const Grid::Config type)
 {
-	double snapvalue = g_win->config ((type == Coordinate) ? CurrentGrid().coordinateSnap : CurrentGrid().angleSnap);
+	double snapvalue = (type == Coordinate) ? gridCoordinateSnap() : gridAngleSnap();
 	double mult = floor (qAbs<double> (value / snapvalue));
 	double out = mult * snapvalue;
 
@@ -158,7 +174,7 @@
 //
 Vertex GetRotationPoint (const LDObjectList& objs)
 {
-	switch (RotationPoint (g_win->configBag()->rotationPointType))
+	switch (RotationPoint (g_win->configBag()->rotationPointType()))
 	{
 	case RotationPoint::ObjectOrigin:
 		{
@@ -180,7 +196,7 @@
 		return Origin;
 
 	case RotationPoint::CustomPoint:
-		return g_win->configBag()->customRotationPoint;
+		return g_win->configBag()->customRotationPoint();
 
 	case RotationPoint::NumValues:
 		break;
@@ -197,7 +213,7 @@
 	Ui::RotPointUI ui;
 	ui.setupUi (dlg);
 
-	switch (RotationPoint (g_win->configBag()->rotationPointType))
+	switch (RotationPoint (g_win->configBag()->rotationPointType()))
 	{
 	case RotationPoint::ObjectOrigin:
 		ui.objectPoint->setChecked (true);
@@ -215,7 +231,7 @@
 		break;
 	}
 
-	Vertex& custompoint = g_win->configBag()->customRotationPoint;
+	Vertex custompoint = g_win->configBag()->customRotationPoint();
 	ui.customX->setValue (custompoint.x());
 	ui.customY->setValue (custompoint.y());
 	ui.customZ->setValue (custompoint.z());
@@ -223,14 +239,15 @@
 	if (not dlg->exec())
 		return;
 
-	g_win->configBag()->rotationPointType =
+	g_win->configBag()->setRotationPointType (int (
 		(ui.objectPoint->isChecked()) ? RotationPoint::ObjectOrigin :
 		(ui.worldPoint->isChecked())  ? RotationPoint::WorldOrigin :
-		RotationPoint::CustomPoint;
+		RotationPoint::CustomPoint));
 
 	custompoint.setX (ui.customX->value());
 	custompoint.setY (ui.customY->value());
 	custompoint.setZ (ui.customZ->value());
+	g_win->configBag()->setCustomRotationPoint (custompoint);
 }
 
 // =============================================================================
--- a/src/miscallenous.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/miscallenous.h	Mon Aug 31 20:50:12 2015 +0300
@@ -19,7 +19,6 @@
 #pragma once
 #include <QVector>
 #include <functional>
-#include "configuration.h"
 #include "main.h"
 #include "basics.h"
 #include "configurationvaluebag.h"
@@ -44,15 +43,8 @@
 QString Join (QList<StringFormatArg> vals, QString delim = " ");
 
 // Grid stuff
-struct GridData
-{
-	const char* name;
-	CONFIG_KEY_TYPE(float) coordinateSnap;
-	CONFIG_KEY_TYPE(float) angleSnap;
-};
-
-extern const GridData Grids[3];
-const GridData& CurrentGrid();
+float gridCoordinateSnap();
+float gridAngleSnap();
 
 // =============================================================================
 enum class RotationPoint
--- a/src/partDownloader.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/partDownloader.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -53,7 +53,7 @@
 //
 QString PartDownloader::getDownloadPath()
 {
-	QString path = m_config->downloadFilePath;
+	QString path = m_config->downloadFilePath();
 
 	if (DIRSLASH[0] != '/')
 		path.replace (DIRSLASH, "/");
@@ -109,7 +109,7 @@
 		if (path.isEmpty())
 			return false;
 
-		m_config->downloadFilePath = path;
+		m_config->setDownloadFilePath (path);
 	}
 
 	return true;
@@ -145,7 +145,7 @@
 	dest = dest.simplified();
 
 	// If the user doesn't want us to guess, stop right here.
-	if (not m_config->guessDownloadPaths)
+	if (not m_config->guessDownloadPaths())
 		return;
 
 	// Ensure .dat extension
@@ -254,7 +254,7 @@
 
 		modifyDestination (dest);
 
-		if (QFile::exists (PartDownloader::getDownloadPath() + DIRSLASH + dest))
+		if (QFile::exists (getDownloadPath() + DIRSLASH + dest))
 		{
 			const QString overwritemsg = format (tr ("%1 already exists in download directory. Overwrite?"), dest);
 			if (not Confirm (tr ("Overwrite?"), overwritemsg))
@@ -332,7 +332,7 @@
 		for (LDDocument* f : m_files)
 		f->reloadAllSubfiles();
 
-	if (m_config->autoCloseDownloadDialog and not failed)
+	if (m_config->autoCloseDownloadDialog() and not failed)
 	{
 		// Close automatically if desired.
 		accept();
@@ -372,7 +372,7 @@
 	m_prompt (parent),
 	m_url (url),
 	m_destinaton (dest),
-	m_filePath (PartDownloader::getDownloadPath() + DIRSLASH + dest),
+	m_filePath (parent->getDownloadPath() + DIRSLASH + dest),
 	m_networkManager (new QNetworkAccessManager),
 	m_isFirstUpdate (true),
 	m_isPrimary (primary),
--- a/src/partDownloader.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/partDownloader.h	Mon Aug 31 20:50:12 2015 +0300
@@ -79,7 +79,7 @@
 	void			setSource (Source src);
 	void			modifyDestination (QString& dest) const;
 
-	static QString	getDownloadPath();
+	QString			getDownloadPath();
 	static void		staticBegin();
 
 public slots:
--- a/src/primitives.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/primitives.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -47,12 +47,17 @@
 	return g_activeScanner;
 }
 
+QString getPrimitivesCfgPath()
+{
+	return qApp->applicationDirPath() + DIRSLASH "prims.cfg";
+}
+
 // =============================================================================
 //
 void LoadPrimitives()
 {
 	// Try to load prims.cfg
-	QFile conf (Config::FilePath ("prims.cfg"));
+	QFile conf (getPrimitivesCfgPath());
 
 	if (not conf.open (QIODevice::ReadOnly))
 	{
@@ -160,7 +165,7 @@
 	if (m_i == m_files.size())
 	{
 		// Done with primitives, now save to a config file
-		QString path = Config::FilePath ("prims.cfg");
+		QString path = getPrimitivesCfgPath();
 		QFile conf (path);
 
 		if (not conf.open (QIODevice::WriteOnly | QIODevice::Text))
@@ -279,11 +284,7 @@
 		delete cat;
 
 	g_PrimitiveCategories.clear();
-	QString path = Config::DirectoryPath() + "primregexps.cfg";
-
-	if (not QFile::exists (path))
-		path = ":/data/primitive-categories.cfg";
-
+	QString path = ":/data/primitive-categories.cfg";
 	QFile f (path);
 
 	if (not f.open (QIODevice::ReadOnly))
@@ -618,10 +619,10 @@
 	QString author = APPNAME;
 	QString license = "";
 
-	if (not g_win->configBag()->defaultName.isEmpty())
+	if (not g_win->configBag()->defaultName().isEmpty())
 	{
 		license = PreferredLicenseText();
-		author = format ("%1 [%2]", g_win->configBag()->defaultName, g_win->configBag()->defaultUser);
+		author = format ("%1 [%2]", g_win->configBag()->defaultName(), g_win->configBag()->defaultUser());
 	}
 
 	LDObjectList objs;
--- a/src/toolsets/algorithmtoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/algorithmtoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -158,14 +158,14 @@
 			Vertex v = mo->position();
 			Matrix t = mo->transform();
 
-			v.apply ([](Axis, double& a)
+			v.apply ([&](Axis, double& a)
 			{
-				RoundToDecimals (a, m_config->roundPositionPrecision);
+				RoundToDecimals (a, m_config->roundPositionPrecision());
 			});
 
-			ApplyToMatrix (t, [](int, double& a)
+			ApplyToMatrix (t, [&](int, double& a)
 			{
-				RoundToDecimals (a, m_config->roundMatrixPrecision);
+				RoundToDecimals (a, m_config->roundMatrixPrecision());
 			});
 
 			mo->setPosition (v);
@@ -177,9 +177,9 @@
 			for (int i = 0; i < obj->numVertices(); ++i)
 			{
 				Vertex v = obj->vertex (i);
-				v.apply ([](Axis, double& a)
+				v.apply ([&](Axis, double& a)
 				{
-					RoundToDecimals (a, m_config->roundPositionPrecision);
+					RoundToDecimals (a, m_config->roundPositionPrecision());
 				});
 				obj->setVertex (i, v);
 				num += 3;
@@ -332,7 +332,7 @@
 	QDialog* dlg = new QDialog;
 	Ui_AddHistoryLine* ui = new Ui_AddHistoryLine;
 	ui->setupUi (dlg);
-	ui->m_username->setText (m_config->defaultUser);
+	ui->m_username->setText (m_config->defaultUser());
 	ui->m_date->setDate (QDate::currentDate());
 	ui->m_comment->setFocus();
 
@@ -377,13 +377,12 @@
 {
 	bool ok;
 	int segments = QInputDialog::getInt (m_window, APPNAME, "Amount of segments:",
-		m_window->config (m_config->splitLinesSegments), 0,
-		std::numeric_limits<int>::max(), 1, &ok);
+		m_config->splitLinesSegments(), 0, std::numeric_limits<int>::max(), 1, &ok);
 
 	if (not ok)
 		return;
 
-	m_config->splitLinesSegments = segments;
+	m_config->setSplitLinesSegments (segments);
 
 	for (LDObject* obj : Selection())
 	{
@@ -544,7 +543,7 @@
 	LDObjectList objs;
 	objs << LDSpawn<LDComment> (subtitle);
 	objs << LDSpawn<LDComment> ("Name: "); // This gets filled in when the subfile is saved
-	objs << LDSpawn<LDComment> (format ("Author: %1 [%2]", m_config->defaultName, m_config->defaultUser));
+	objs << LDSpawn<LDComment> (format ("Author: %1 [%2]", m_config->defaultName(), m_config->defaultUser()));
 	objs << LDSpawn<LDComment> ("!LDRAW_ORG Unofficial_Subpart");
 
 	if (not license.isEmpty())
--- a/src/toolsets/basictoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/basictoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -208,7 +208,7 @@
 	LDColor defaultcol = m_window->getSelectedColor();
 
 	// Show the dialog to the user now and ask for a color.
-	if (ColorSelector::selectColor (color, defaultcol, m_window))
+	if (ColorSelector::selectColor (m_window, color, defaultcol))
 	{
 		for (LDObject* obj : objs)
 		{
--- a/src/toolsets/extprogramtoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/extprogramtoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -24,9 +24,9 @@
 #include <QCheckBox>
 #include <QComboBox>
 #include <QGridLayout>
+#include <QSettings>
 #include <QFileInfo>
 #include "../main.h"
-#include "../configuration.h"
 #include "../miscallenous.h"
 #include "../mainwindow.h"
 #include "../ldDocument.h"
@@ -60,23 +60,11 @@
 	Toolset (parent)
 {
 	extProgramInfo[Isecalc].name = "Isecalc";
-	extProgramInfo[Isecalc].path = &m_config->isecalcPath;
-	extProgramInfo[Isecalc].wine = &m_config->isecalcUsesWine;
 	extProgramInfo[Intersector].name = "Intersector";
-	extProgramInfo[Intersector].path = &m_config->intersectorPath;
-	extProgramInfo[Intersector].wine = &m_config->intersectorUsesWine;
 	extProgramInfo[Coverer].name = "Coverer";
-	extProgramInfo[Coverer].path = &m_config->covererPath;
-	extProgramInfo[Coverer].wine = &m_config->covererUsesWine;
 	extProgramInfo[Ytruder].name = "Ytruder";
-	extProgramInfo[Ytruder].path = &m_config->ytruderPath;
-	extProgramInfo[Ytruder].wine = &m_config->ytruderUsesWine;
 	extProgramInfo[Rectifier].name = "Rectifier";
-	extProgramInfo[Rectifier].path = &m_config->rectifierPath;
-	extProgramInfo[Rectifier].wine = &m_config->rectifierUsesWine;
 	extProgramInfo[Edger2].name = "Edger2";
-	extProgramInfo[Edger2].path = &m_config->edger2Path;
-	extProgramInfo[Edger2].wine = &m_config->edger2UsesWine;
 }
 
 bool ExtProgramToolset::makeTempFile (QTemporaryFile& tmp, QString& fname)
@@ -98,14 +86,24 @@
 #endif
 }
 
-bool& ExtProgramToolset::getWineSetting (ExtProgramType program)
+bool ExtProgramToolset::getWineSetting (ExtProgramType program)
 {
-	return *extProgramInfo[program].wine;
+	return m_window->getConfigValue (externalProgramName (program) + "UsesWine").toBool();
 }
 
 QString ExtProgramToolset::getPathSetting (ExtProgramType program)
 {
-	return *extProgramInfo[program].path;
+	return m_window->getConfigValue (externalProgramName (program) + "Path").toString();
+}
+
+void ExtProgramToolset::setPathSetting (ExtProgramType program, QString value)
+{
+	m_window->getSettings()->setValue (externalProgramName (program) + "Path", QVariant::fromValue (value));
+}
+
+void ExtProgramToolset::setWineSetting (ExtProgramType program, bool value)
+{
+	m_window->getSettings()->setValue (externalProgramName (program) + "UsesWine", QVariant::fromValue (value));
 }
 
 QString ExtProgramToolset::externalProgramName (ExtProgramType program)
@@ -113,18 +111,18 @@
 	return extProgramInfo[program].name;
 }
 
-QString ExtProgramToolset::checkExtProgramPath(ExtProgramType program)
+bool ExtProgramToolset::checkExtProgramPath (ExtProgramType program)
 {
-	QString& path = getPathSetting (program);
+	QString path = getPathSetting (program);
 
 	if (not path.isEmpty())
 		return true;
 
-	ExtProgPathPrompt* dlg = new ExtProgPathPrompt (externalProgramName (program));
+	ExtProgPathPrompt* dialog = new ExtProgPathPrompt (externalProgramName (program));
 
-	if (dlg->exec() and not dlg->getPath().isEmpty())
+	if (dialog->exec() and not dialog->getPath().isEmpty())
 	{
-		path = dlg->getPath();
+		setPathSetting (program, dialog->getPath());
 		return true;
 	}
 
@@ -392,12 +390,12 @@
 		outDATName
 	});
 
-	WriteSelection (inDATName);
+	writeSelection (inDATName);
 
 	if (not runExtProgram (Ytruder, argv))
 		return;
 
-	InsertOutput (outDATName, false, {});
+	insertOutput (outDATName, false, {});
 }
 
 // =============================================================================
@@ -437,12 +435,12 @@
 		outDATName
 	});
 
-	WriteSelection (inDATName);
+	writeSelection (inDATName);
 
 	if (not runExtProgram (Rectifier, argv))
 		return;
 
-	InsertOutput (outDATName, true, {});
+	insertOutput (outDATName, true, {});
 }
 
 // =============================================================================
--- a/src/toolsets/extprogramtoolset.h	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/extprogramtoolset.h	Mon Aug 31 20:50:12 2015 +0300
@@ -35,12 +35,12 @@
 struct ExtProgramInfo
 {
 	QString name;
-	QString* path;
-	bool* wine;
 };
 
 class ExtProgramToolset : public Toolset
 {
+	Q_OBJECT
+
 public:
 	ExtProgramToolset (MainWindow* parent);
 
@@ -50,12 +50,17 @@
 	Q_INVOKABLE void isecalc();
 	Q_INVOKABLE void rectifier();
 	Q_INVOKABLE void ytruder();
+	
+	bool programUsesWine (ExtProgramType program);
+	QString externalProgramName (ExtProgramType program);
+	QString getPathSetting (ExtProgramType program);
+	bool getWineSetting (ExtProgramType program);
+	void setPathSetting (ExtProgramType program, QString value);
+	void setWineSetting (ExtProgramType program, bool value);
 
 private:
-	QString externalProgramName (ExtProgramType program);
-	bool programUsesWine (ExtProgramType program);
-	QString checkExtProgramPath (ExtProgramType program);
-	bool makeTempFile (QTemporaryFile& tmp, QString& fname);
+	bool checkExtProgramPath(ExtProgramType program);
+	bool makeTempFile (class QTemporaryFile& tmp, QString& fname);
 	bool runExtProgram (ExtProgramType prog, QString argvstr);
 	QString errorCodeString (ExtProgramType program, class QProcess& process);
 	void insertOutput (QString fname, bool replace, QList<LDColor> colorsToReplace);
@@ -63,8 +68,6 @@
 	void writeObjects (const LDObjectList& objects, QFile& f);
 	void writeObjects (const LDObjectList& objects, QString fname);
 	void writeSelection (QString fname);
-	bool& getWineSetting (ExtProgramType program);
-	QString getPathSetting (ExtProgramType program);
 
 	ExtProgramInfo extProgramInfo[NumExternalPrograms];
 };
--- a/src/toolsets/filetoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/filetoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -99,7 +99,10 @@
 
 void FileToolset::setLDrawPath()
 {
-	(new LDrawPathDialog (m_config->ldrawPath, true))->exec();
+	LDrawPathDialog* dialog = new LDrawPathDialog (m_config->lDrawPath(), true);
+
+	if (dialog->exec())
+		m_config->setLDrawPath (dialog->path());
 }
 
 void FileToolset::exit()
--- a/src/toolsets/movetoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/movetoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -44,26 +44,26 @@
 
 void MoveToolset::gridCoarse()
 {
-	m_config->grid = Grid::Coarse;
+	m_config->setGrid (Grid::Coarse);
 	m_window->updateGridToolBar();
 }
 
 void MoveToolset::gridMedium()
 {
-	m_config->grid = Grid::Medium;
+	m_config->setGrid (Grid::Medium);
 	m_window->updateGridToolBar();
 }
 
 void MoveToolset::gridFine()
 {
-	m_config->grid = Grid::Fine;
+	m_config->setGrid (Grid::Fine);
 	m_window->updateGridToolBar();
 }
 
 void MoveToolset::moveObjects (Vertex vect)
 {
 	// Apply the grid values
-	vect *= m_window->config (CurrentGrid().coordinateSnap);
+	vect *= gridCoordinateSnap();
 
 	for (LDObject* obj : Selection())
 		obj->move (vect);
@@ -101,7 +101,7 @@
 
 double MoveToolset::getRotateActionAngle()
 {
-	return (Pi * m_window->config (CurrentGrid().angleSnap)) / 180;
+	return (Pi * gridAngleSnap()) / 180;
 }
 
 void MoveToolset::rotateXPos()
--- a/src/toolsets/toolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/toolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -27,8 +27,7 @@
 
 Toolset::Toolset (MainWindow* parent) :
 	QObject (parent),
-	HierarchyElement (parent),
-	m_window (parent) {}
+	HierarchyElement (parent) {}
 
 QVector<Toolset*> Toolset::createToolsets (MainWindow* parent)
 {
--- a/src/toolsets/viewtoolset.cpp	Mon Aug 31 04:57:16 2015 +0300
+++ b/src/toolsets/viewtoolset.cpp	Mon Aug 31 20:50:12 2015 +0300
@@ -126,7 +126,7 @@
 
 void ViewToolset::axes()
 {
-	m_config->drawAxes = not m_config->drawAxes;
+	m_config->setDrawAxes (not m_config->drawAxes());
 	m_window->updateActions();
 	m_window->R()->update();
 }
@@ -151,7 +151,7 @@
 
 void ViewToolset::wireframe()
 {
-	m_config->drawWireframe = not m_config->drawWireframe;
+	m_config->setDrawWireframe (not m_config->drawWireframe());
 	m_window->R()->refresh();
 }
 
@@ -173,7 +173,7 @@
 
 void ViewToolset::drawAngles()
 {
-	m_config->drawAngles = not m_config->drawAngles;
+	m_config->setDrawAngles (not m_config->drawAngles());
 	m_window->R()->refresh();
 }
 
@@ -242,10 +242,10 @@
 
 void ViewToolset::bfcView()
 {
-	m_config->bfcRedGreenView = not m_config->bfcRedGreenView;
+	m_config->setBfcRedGreenView (not m_config->bfcRedGreenView());
 
-	if (m_config->bfcRedGreenView)
-		m_config->randomColors = false;
+	if (m_config->bfcRedGreenView())
+		m_config->setRandomColors (false);
 
 	m_window->updateActions();
 	m_window->R()->refresh();
@@ -273,10 +273,10 @@
 
 void ViewToolset::randomColors()
 {
-	m_config->randomColors = not m_config->randomColors;
+	m_config->setRandomColors (not m_config->randomColors());
 
-	if (m_config->randomColors)
-		m_config->bfcRedGreenView = false;
+	if (m_config->randomColors())
+		m_config->setBfcRedGreenView (false);
 
 	m_window->updateActions();
 	m_window->R()->refresh();
@@ -284,18 +284,18 @@
 
 void ViewToolset::drawSurfaces()
 {
-	m_config->drawSurfaces = not m_config->drawSurfaces;
+	m_config->setDrawSurfaces (not m_config->drawSurfaces());
 	m_window->updateActions();
 }
 
 void ViewToolset::drawEdgeLines()
 {
-	m_config->drawEdgeLines = not m_config->drawEdgeLines;
+	m_config->setDrawEdgeLines (not m_config->drawEdgeLines());
 	m_window->updateActions();
 }
 
 void ViewToolset::drawConditionalLines()
 {
-	m_config->drawConditionalLines = not m_config->drawConditionalLines;
+	m_config->setDrawConditionalLines (not m_config->drawConditionalLines());
 	m_window->updateActions();
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/caseconversions.py	Mon Aug 31 20:50:12 2015 +0300
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+'''
+Provides facilities to converting identifier cases.
+'''
+
+#
+#	Copyright 2015 Teemu Piippo
+#	All rights reserved.
+#
+#	Redistribution and use in source and binary forms, with or without
+#	modification, are permitted provided that the following conditions
+#	are met:
+#
+#	1. Redistributions of source code must retain the above copyright
+#	   notice, this list of conditions and the following disclaimer.
+#	2. Redistributions in binary form must reproduce the above copyright
+#	   notice, this list of conditions and the following disclaimer in the
+#	   documentation and/or other materials provided with the distribution.
+#	3. Neither the name of the copyright holder nor the names of its
+#	   contributors may be used to endorse or promote products derived from
+#	   this software without specific prior written permission.
+#
+#	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+#	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+#	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+#	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import string
+import re
+
+def to_one_case (name, tolower):
+	'''
+	Convers name to either all uppercase or all lowercase (depending on the truth value of tolower), using underscores
+	as delimiters.
+	'''
+	result = ""
+	targetSet = (string.ascii_lowercase if tolower else string.ascii_uppercase) + string.digits
+	inverseSet = (string.ascii_uppercase if tolower else string.ascii_lowercase)
+	isUnderscorable = lambda ch: ch in string.ascii_uppercase \
+		or ch in string.whitespace or ch in string.punctuation
+	previousWasUnderscorable = isUnderscorable (name[0])
+
+	for ch in name:
+		if isUnderscorable (ch) and result != "" and not previousWasUnderscorable:
+			result += "_"
+
+		if ch in inverseSet:
+			result += (ch.lower() if tolower else ch.upper())
+		elif ch in targetSet:
+			result += ch
+		previousWasUnderscorable = isUnderscorable (ch)
+
+	return result
+
+def to_camel_case (name, java = False):
+	'''
+	Converts name to camelcase. If java is False, the first letter will be lowercase, otherwise it will be uppercase.
+	'''
+	result = ""
+	wantUpperCase = False
+
+	# If it's all uppercase, make it all lowercase so that this algorithm can digest it
+	if name == name.upper():
+		name = name.lower()
+
+	for ch in name:
+		if ch == '_':
+			wantUpperCase = True
+			continue
+
+		if wantUpperCase:
+			if ch in string.ascii_lowercase:
+				ch = ch.upper()
+			wantUpperCase = False
+
+		result += ch
+
+	if java:
+		match = re.match (r'^([A-Z]+)([A-Z].+)$', result)
+		if match:
+			result = match.group (1).lower() + match.group (2)
+		else:
+			result = result[0].lower() + result[1:]
+	else:
+		result = result[0].upper() + result[1:]
+	return result
+
+case_styles = {
+	'lower': lambda name: to_one_case (name, tolower=True),
+	'upper': lambda name: to_one_case (name, tolower=False),
+	'camel': lambda name: to_camel_case (name, java=False),
+	'java': lambda name: to_camel_case (name, java=True),
+}
+
+def convert_case (name, style):
+	'''
+	Converts name to the given style. Style may be one of:
+		- 'lower': 'foo_barBaz' -> 'foo_bar_baz'
+		- 'upper': 'foo_barBaz' -> 'FOO_BAR_BAZ'
+		- 'camel': 'foo_barBaz' -> 'FooBarBaz'
+		- 'java': 'foo_barBaz' -> 'fooBarBaz'
+	'''
+	try:
+		stylefunc = case_styles[style]
+	except KeyError:
+		validstyles = ', '.join (sorted (case_styles.keys()))
+		raise ValueError ('Unknown style "%s", should be one of: %s' % (style, validstyles))
+	else:
+		return stylefunc (name)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/configcollector.py	Mon Aug 31 20:50:12 2015 +0300
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+# coding: utf-8
+#
+#	Copyright 2015 Teemu Piippo
+#	All rights reserved.
+#
+#	Redistribution and use in source and binary forms, with or without
+#	modification, are permitted provided that the following conditions
+#	are met:
+#
+#	1. Redistributions of source code must retain the above copyright
+#	   notice, this list of conditions and the following disclaimer.
+#	2. Redistributions in binary form must reproduce the above copyright
+#	   notice, this list of conditions and the following disclaimer in the
+#	   documentation and/or other materials provided with the distribution.
+#	3. Neither the name of the copyright holder nor the names of its
+#	   contributors may be used to endorse or promote products derived from
+#	   this software without specific prior written permission.
+#
+#	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+#	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+#	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+#	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import argparse
+import caseconversions
+import collections
+import outputfile
+import re
+from pprint import pprint
+
+passbyvalue = {'int', 'bool', 'float', 'double' }
+
+class ConfigCollector (object):
+	def __init__ (self, args):
+		self.pattern = re.compile (r'\s*ConfigOption\s*\((.+)\)\s*')
+		self.declpattern = re.compile (r'^([A-Za-z0-9,<>\[\]\(\)\{\}\s]+)\s+(\w+)(\s*=\s*(.+))?$')
+		self.decls = []
+		self.qttypes = set()
+		self.args = args
+
+	def collect (self, filenames):
+		for filename in filenames:
+			with open (filename, 'r') as fp:
+				lines = fp.read().splitlines()
+
+			for line in lines:
+				matches = self.pattern.findall (line)
+				for match in matches:
+					match = match.strip()
+					declarations = self.declpattern.findall (match)
+					for decl in declarations:
+						self.add_config_declaration (decl)
+
+		self.decls.sort (key=lambda x: x['name'].upper())
+
+	def add_config_declaration (self, decl):
+		decltype, declname, junk, decldefault = decl
+		if not decldefault:
+			if decltype == 'int':
+				decldefault = '0'
+			elif decltype == 'float':
+				decldefault = '0.0f'
+			elif decltype == 'double':
+				decldefault = '0.0'
+			elif decltype == 'bool':
+				raise TypeError ('bool entries must provide a default value')
+			else:
+				decldefault = decltype + '()'
+
+		self.decls.append (dict (name=declname, type=decltype, default=decldefault))
+
+		# Take note of any Qt types we may want to #include in our source file (we'll need to #include them).
+		self.qttypes.update (re.findall (r'(Q[A-Za-z]+)', decltype))
+
+	def make_config_key_type (self, basetype):
+		result = 'ConfigTypeKey_' + basetype
+		result = re.sub (r'[^\w]+', '_', result)
+		return result
+
+	def make_enums (self):
+		self.enums = collections.OrderedDict()
+
+		for decl in self.decls:
+			enumname = self.make_config_key_type (decl['type'])
+			decl['enumerator'] = caseconversions.convert_case (decl['name'], style='upper')
+			decl['enumname'] = enumname
+			decl['getter'] = caseconversions.convert_case (decl['name'], style='java')
+			decl['varname'] = 'm_' + decl['getter']
+			decl['setter'] = 'set' + caseconversions.convert_case (decl['name'], style='camel')
+			decl['typecref'] = 'const %s&' % decl['type'] if decl['type'] not in passbyvalue else decl['type']
+
+			if enumname not in self.enums:
+				self.enums[enumname] = dict (
+					name = enumname,
+					typename = decl['type'],
+					values = [],
+					numvalues = 0,
+					highestkey = -1)
+
+			self.enums[enumname]['values'].append (decl)
+			self.enums[enumname]['numvalues'] += 1
+			self.enums[enumname]['highestkey'] += 1
+
+		self.enums = collections.OrderedDict (sorted (self.enums.items(), key=lambda x: x[0].upper()))
+
+		for name, enum in self.enums.items():
+			for i, value in enumerate (enum['values']):
+				value['index'] = i
+
+	def write_header (self, fp):
+		fp.write ('#pragma once\n')
+		for qttype in sorted (self.qttypes):
+			fp.write ('#include <%s>\n' % qttype)
+		formatargs = {}
+		write = lambda value: fp.write (value)
+		write ('class ConfigurationValueBag\n')
+		write ('{\n')
+		write ('public:\n')
+		write ('\tConfigurationValueBag (class MainWindow* window);\n')
+		write ('\t~ConfigurationValueBag();\n')
+		write ('\tQVariant defaultValueByName (const QString& name);\n')
+
+		for decl in self.decls:
+			write ('\t{type} {getter}();\n'.format (**decl))
+		for decl in self.decls:
+			write ('\tvoid {setter} ({typecref} value);\n'.format (**decl))
+
+		write ('\n')
+		write ('private:\n')
+		write ('\tclass MainWindow* m_window;\n')
+		write ('\tclass QSettings* m_settings;\n')
+
+		write ('};\n')
+
+	def write_source (self, fp, headername):
+		fp.write ('#include <QSet>\n')
+		fp.write ('#include <QSettings>\n')
+		fp.write ('#include <QVariant>\n')
+		fp.write ('#include "%s/mainwindow.h"\n' % (self.args.sourcedir))
+		fp.write ('#include "%s"\n' % headername)
+
+		fp.write (
+			'\n'
+			'ConfigurationValueBag::ConfigurationValueBag (MainWindow* window) :\n'
+			'\tm_window (window),\n'
+			'\tm_settings (window->makeSettings (nullptr)) {}\n'
+			'\n'
+			'ConfigurationValueBag::~ConfigurationValueBag()\n'
+			'{\n'
+			'\tm_settings->deleteLater();\n'
+			'}\n'
+			'\n')
+
+		maptype = 'QMap<QString, QVariant>'
+		fp.write ('QVariant ConfigurationValueBag::defaultValueByName (const QString& name)\n')
+		fp.write ('{\n')
+		fp.write ('\tstatic %s defaults;\n' % maptype)
+		fp.write ('\tif (defaults.isEmpty())\n')
+		fp.write ('\t{\n')
+
+		for decl in self.decls:
+			fp.write ('\t\tdefaults["{name}"] = QVariant::fromValue<{type}> ({default});\n'.format (**decl))
+
+		fp.write ('\t}\n')
+		fp.write ('\n')
+		fp.write ('\t%s::iterator it = defaults.find (name);\n' % maptype)
+		fp.write ('\tif (it != defaults.end())\n')
+		fp.write ('\t\treturn *it;\n')
+		fp.write ('\treturn QVariant();\n')
+		fp.write ('}\n')
+		fp.write ('\n')
+
+		for decl in self.decls:
+			fp.write ('{type} ConfigurationValueBag::{getter}()\n'.format (**decl))
+			fp.write ('{\n')
+			fp.write ('\tstatic QVariant defaultvalue = QVariant::fromValue<{type}> ({default});\n'.format (**decl))
+			fp.write ('\treturn m_settings->value ("{name}", defaultvalue).value<{type}>();\n'.format (**decl))
+			fp.write ('}\n')
+			fp.write ('\n')
+
+		for decl in self.decls:
+			fp.write ('void ConfigurationValueBag::{setter} ({typecref} value)\n'.format (**decl))
+			fp.write ('{\n')
+			fp.write ('\tif (value != {default})\n'.format (**decl))
+			fp.write ('\t\tm_settings->setValue ("{name}", QVariant::fromValue<{type}> (value));\n'.format (**decl))
+			fp.write ('\telse\n')
+			fp.write ('\t\tm_settings->remove ("{name}");\n'.format (**decl))
+			fp.write ('}\n')
+			fp.write ('\n')
+
+def main():
+	parser = argparse.ArgumentParser (description='Collects a list of configuration objects')
+	parser.add_argument ('inputs', nargs='+')
+	parser.add_argument ('--header', required=True)
+	parser.add_argument ('--source', required=True)
+	parser.add_argument ('--sourcedir', required=True)
+	args = parser.parse_args()
+	collector = ConfigCollector (args)
+	collector.collect (args.inputs)
+	collector.make_enums()
+	header = outputfile.OutputFile (args.header)
+	source = outputfile.OutputFile (args.source)
+	collector.write_source (source, headername=args.header)
+	collector.write_header (header)
+	header.save (verbose = True)
+	source.save (verbose = True)
+
+if __name__ == '__main__':
+	main()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/outputfile.py	Mon Aug 31 20:50:12 2015 +0300
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# coding: utf-8
+#
+#	Copyright 2015 Teemu Piippo
+#	All rights reserved.
+#
+#	Redistribution and use in source and binary forms, with or without
+#	modification, are permitted provided that the following conditions
+#	are met:
+#
+#	1. Redistributions of source code must retain the above copyright
+#	   notice, this list of conditions and the following disclaimer.
+#	2. Redistributions in binary form must reproduce the above copyright
+#	   notice, this list of conditions and the following disclaimer in the
+#	   documentation and/or other materials provided with the distribution.
+#	3. Neither the name of the copyright holder nor the names of its
+#	   contributors may be used to endorse or promote products derived from
+#	   this software without specific prior written permission.
+#
+#	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+#	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+#	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+#	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import hashlib
+import sys
+
+class OutputFile:
+	def __init__ (self, filename):
+		self.filename = filename
+		try:
+			with open (self.filename, "r") as fp:
+				self.oldsum = fp.readline().replace ('\n', '').replace ('// ', '')
+		except IOError:
+			self.oldsum = ''
+
+		self.body = ''
+
+	def write (self, a):
+		self.body += a
+
+	def save (self, verbose = False):
+		if sys.version_info >= (3, 0):
+			checksum = hashlib.md5 (bytes (self.body, 'utf-8')).hexdigest()
+		else:
+			checksum = hashlib.md5 (self.body).hexdigest()
+
+		if checksum == self.oldsum:
+			print ('%s is up to date' % self.filename)
+			return False
+
+		with open (self.filename, "w") as fp:
+			fp.write ('// %s\n' % checksum)
+			fp.write ('// This file has been automatically generated. Do not edit by hand\n')
+			fp.write ('\n')
+			fp.write (self.body)
+
+			if verbose:
+				print ('%s written' % self.filename)
+			return True
--- a/tools/updaterevision.py	Mon Aug 31 04:57:16 2015 +0300
+++ b/tools/updaterevision.py	Mon Aug 31 20:50:12 2015 +0300
@@ -36,10 +36,10 @@
 def main():
 	import subprocess
 	from datetime import datetime
-	parser = argparser.ArgumentParser (description='Writes a header file with Hg commit information')
+	parser = argparse.ArgumentParser (description='Writes a header file with Hg commit information')
 	parser.add_argument ('output')
 	args = parser.parse_args()
-	f = OutputFile (args.output)
+	f = outputfile.OutputFile (args.output)
 	data = subprocess.check_output (['hg', 'log', '-r.', '--template',
 		'{node|short} {branch} {date|hgdate}']).replace ('\n', '').split (' ')
 
@@ -64,4 +64,4 @@
 		print '%s updated to %s' % (f.filename, rev)
 
 if __name__ == '__main__':
-	main()
\ No newline at end of file
+	main()

mercurial